1 /*
2  * Silicon Motion SM7XX frame buffer device
3  *
4  * Copyright (C) 2006 Silicon Motion Technology Corp.
5  * Authors:  Ge Wang, gewang@siliconmotion.com
6  *	     Boyod boyod.yang@siliconmotion.com.cn
7  *
8  * Copyright (C) 2009 Lemote, Inc.
9  * Author:   Wu Zhangjin, wuzhangjin@gmail.com
10  *
11  * Copyright (C) 2011 Igalia, S.L.
12  * Author:   Javier M. Mellid <jmunhoz@igalia.com>
13  *
14  * This file is subject to the terms and conditions of the GNU General Public
15  * License. See the file COPYING in the main directory of this archive for
16  * more details.
17  *
18  * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips
19  */
20 
21 #include <linux/aperture.h>
22 #include <linux/io.h>
23 #include <linux/fb.h>
24 #include <linux/pci.h>
25 #include <linux/init.h>
26 #include <linux/slab.h>
27 #include <linux/uaccess.h>
28 #include <linux/module.h>
29 #include <linux/console.h>
30 
31 #include <linux/pm.h>
32 
33 #include "sm712.h"
34 
35 struct smtcfb_screen_info {
36 	u16 lfb_width;
37 	u16 lfb_height;
38 	u16 lfb_depth;
39 };
40 
41 /*
42  * Private structure
43  */
44 struct smtcfb_info {
45 	struct pci_dev *pdev;
46 	struct fb_info *fb;
47 	u16 chip_id;
48 	u8  chip_rev_id;
49 
50 	void __iomem *lfb;	/* linear frame buffer */
51 	void __iomem *dp_regs;	/* drawing processor control regs */
52 	void __iomem *vp_regs;	/* video processor control regs */
53 	void __iomem *cp_regs;	/* capture processor control regs */
54 	void __iomem *mmio;	/* memory map IO port */
55 
56 	u_int width;
57 	u_int height;
58 	u_int hz;
59 
60 	u32 colreg[17];
61 };
62 
63 void __iomem *smtc_regbaseaddress;	/* Memory Map IO starting address */
64 
65 static const struct fb_var_screeninfo smtcfb_var = {
66 	.xres           = 1024,
67 	.yres           = 600,
68 	.xres_virtual   = 1024,
69 	.yres_virtual   = 600,
70 	.bits_per_pixel = 16,
71 	.red            = {16, 8, 0},
72 	.green          = {8, 8, 0},
73 	.blue           = {0, 8, 0},
74 	.activate       = FB_ACTIVATE_NOW,
75 	.height         = -1,
76 	.width          = -1,
77 	.vmode          = FB_VMODE_NONINTERLACED,
78 	.nonstd         = 0,
79 	.accel_flags    = FB_ACCELF_TEXT,
80 };
81 
82 static struct fb_fix_screeninfo smtcfb_fix = {
83 	.id             = "smXXXfb",
84 	.type           = FB_TYPE_PACKED_PIXELS,
85 	.visual         = FB_VISUAL_TRUECOLOR,
86 	.line_length    = 800 * 3,
87 	.accel          = FB_ACCEL_SMI_LYNX,
88 	.type_aux       = 0,
89 	.xpanstep       = 0,
90 	.ypanstep       = 0,
91 	.ywrapstep      = 0,
92 };
93 
94 struct vesa_mode {
95 	char index[6];
96 	u16  lfb_width;
97 	u16  lfb_height;
98 	u16  lfb_depth;
99 };
100 
101 static const struct vesa_mode vesa_mode_table[] = {
102 	{"0x301", 640,  480,  8},
103 	{"0x303", 800,  600,  8},
104 	{"0x305", 1024, 768,  8},
105 	{"0x307", 1280, 1024, 8},
106 
107 	{"0x311", 640,  480,  16},
108 	{"0x314", 800,  600,  16},
109 	{"0x317", 1024, 768,  16},
110 	{"0x31A", 1280, 1024, 16},
111 
112 	{"0x312", 640,  480,  24},
113 	{"0x315", 800,  600,  24},
114 	{"0x318", 1024, 768,  24},
115 	{"0x31B", 1280, 1024, 24},
116 };
117 
118 /**********************************************************************
119 			 SM712 Mode table.
120  **********************************************************************/
121 static const struct modeinit vgamode[] = {
122 	{
123 		/*  mode#0: 640 x 480  16Bpp  60Hz */
124 		640, 480, 16, 60,
125 		/*  Init_MISC */
126 		0xE3,
127 		{	/*  Init_SR0_SR4 */
128 			0x03, 0x01, 0x0F, 0x00, 0x0E,
129 		},
130 		{	/*  Init_SR10_SR24 */
131 			0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
132 			0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 			0xC4, 0x30, 0x02, 0x01, 0x01,
134 		},
135 		{	/*  Init_SR30_SR75 */
136 			0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
137 			0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
138 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
139 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
140 			0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
141 			0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
142 			0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
143 			0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
144 			0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
145 		},
146 		{	/*  Init_SR80_SR93 */
147 			0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
148 			0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
149 			0x00, 0x00, 0x00, 0x00,
150 		},
151 		{	/*  Init_SRA0_SRAF */
152 			0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
153 			0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
154 		},
155 		{	/*  Init_GR00_GR08 */
156 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
157 			0xFF,
158 		},
159 		{	/*  Init_AR00_AR14 */
160 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
161 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
162 			0x41, 0x00, 0x0F, 0x00, 0x00,
163 		},
164 		{	/*  Init_CR00_CR18 */
165 			0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
166 			0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167 			0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
168 			0xFF,
169 		},
170 		{	/*  Init_CR30_CR4D */
171 			0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
172 			0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
173 			0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
174 			0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
175 		},
176 		{	/*  Init_CR90_CRA7 */
177 			0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
178 			0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
179 			0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
180 		},
181 	},
182 	{
183 		/*  mode#1: 640 x 480  24Bpp  60Hz */
184 		640, 480, 24, 60,
185 		/*  Init_MISC */
186 		0xE3,
187 		{	/*  Init_SR0_SR4 */
188 			0x03, 0x01, 0x0F, 0x00, 0x0E,
189 		},
190 		{	/*  Init_SR10_SR24 */
191 			0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
192 			0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 			0xC4, 0x30, 0x02, 0x01, 0x01,
194 		},
195 		{	/*  Init_SR30_SR75 */
196 			0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
197 			0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
198 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
199 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
200 			0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
201 			0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
202 			0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
203 			0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
204 			0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
205 		},
206 		{	/*  Init_SR80_SR93 */
207 			0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
208 			0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
209 			0x00, 0x00, 0x00, 0x00,
210 		},
211 		{	/*  Init_SRA0_SRAF */
212 			0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
213 			0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
214 		},
215 		{	/*  Init_GR00_GR08 */
216 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
217 			0xFF,
218 		},
219 		{	/*  Init_AR00_AR14 */
220 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
221 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
222 			0x41, 0x00, 0x0F, 0x00, 0x00,
223 		},
224 		{	/*  Init_CR00_CR18 */
225 			0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
226 			0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 			0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
228 			0xFF,
229 		},
230 		{	/*  Init_CR30_CR4D */
231 			0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
232 			0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
233 			0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
234 			0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
235 		},
236 		{	/*  Init_CR90_CRA7 */
237 			0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
238 			0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
239 			0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
240 		},
241 	},
242 	{
243 		/*  mode#0: 640 x 480  32Bpp  60Hz */
244 		640, 480, 32, 60,
245 		/*  Init_MISC */
246 		0xE3,
247 		{	/*  Init_SR0_SR4 */
248 			0x03, 0x01, 0x0F, 0x00, 0x0E,
249 		},
250 		{	/*  Init_SR10_SR24 */
251 			0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
252 			0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 			0xC4, 0x30, 0x02, 0x01, 0x01,
254 		},
255 		{	/*  Init_SR30_SR75 */
256 			0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
257 			0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
258 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
259 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
260 			0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
261 			0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
262 			0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
263 			0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
264 			0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
265 		},
266 		{	/*  Init_SR80_SR93 */
267 			0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
268 			0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
269 			0x00, 0x00, 0x00, 0x00,
270 		},
271 		{	/*  Init_SRA0_SRAF */
272 			0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
273 			0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
274 		},
275 		{	/*  Init_GR00_GR08 */
276 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
277 			0xFF,
278 		},
279 		{	/*  Init_AR00_AR14 */
280 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
281 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
282 			0x41, 0x00, 0x0F, 0x00, 0x00,
283 		},
284 		{	/*  Init_CR00_CR18 */
285 			0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
286 			0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 			0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
288 			0xFF,
289 		},
290 		{	/*  Init_CR30_CR4D */
291 			0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
292 			0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
293 			0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
294 			0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
295 		},
296 		{	/*  Init_CR90_CRA7 */
297 			0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
298 			0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
299 			0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
300 		},
301 	},
302 
303 	{	/*  mode#2: 800 x 600  16Bpp  60Hz */
304 		800, 600, 16, 60,
305 		/*  Init_MISC */
306 		0x2B,
307 		{	/*  Init_SR0_SR4 */
308 			0x03, 0x01, 0x0F, 0x03, 0x0E,
309 		},
310 		{	/*  Init_SR10_SR24 */
311 			0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
312 			0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
313 			0xC4, 0x30, 0x02, 0x01, 0x01,
314 		},
315 		{	/*  Init_SR30_SR75 */
316 			0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
317 			0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
318 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
319 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
320 			0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
321 			0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
322 			0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
323 			0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
324 			0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
325 		},
326 		{	/*  Init_SR80_SR93 */
327 			0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
328 			0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
329 			0x00, 0x00, 0x00, 0x00,
330 		},
331 		{	/*  Init_SRA0_SRAF */
332 			0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
333 			0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
334 		},
335 		{	/*  Init_GR00_GR08 */
336 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
337 			0xFF,
338 		},
339 		{	/*  Init_AR00_AR14 */
340 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
341 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
342 			0x41, 0x00, 0x0F, 0x00, 0x00,
343 		},
344 		{	/*  Init_CR00_CR18 */
345 			0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
346 			0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 			0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
348 			0xFF,
349 		},
350 		{	/*  Init_CR30_CR4D */
351 			0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
352 			0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
353 			0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
354 			0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
355 		},
356 		{	/*  Init_CR90_CRA7 */
357 			0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
358 			0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
359 			0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
360 		},
361 	},
362 	{	/*  mode#3: 800 x 600  24Bpp  60Hz */
363 		800, 600, 24, 60,
364 		0x2B,
365 		{	/*  Init_SR0_SR4 */
366 			0x03, 0x01, 0x0F, 0x03, 0x0E,
367 		},
368 		{	/*  Init_SR10_SR24 */
369 			0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
370 			0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
371 			0xC4, 0x30, 0x02, 0x01, 0x01,
372 		},
373 		{	/*  Init_SR30_SR75 */
374 			0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36,
375 			0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF,
376 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
377 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36,
378 			0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
379 			0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36,
380 			0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
381 			0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
382 			0x02, 0x45, 0x30, 0x30, 0x40, 0x20,
383 		},
384 		{	/*  Init_SR80_SR93 */
385 			0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36,
386 			0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36,
387 			0x00, 0x00, 0x00, 0x00,
388 		},
389 		{	/*  Init_SRA0_SRAF */
390 			0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
391 			0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
392 		},
393 		{	/*  Init_GR00_GR08 */
394 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
395 			0xFF,
396 		},
397 		{	/*  Init_AR00_AR14 */
398 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
399 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
400 			0x41, 0x00, 0x0F, 0x00, 0x00,
401 		},
402 		{	/*  Init_CR00_CR18 */
403 			0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
404 			0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
405 			0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
406 			0xFF,
407 		},
408 		{	/*  Init_CR30_CR4D */
409 			0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
410 			0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
411 			0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
412 			0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
413 		},
414 		{	/*  Init_CR90_CRA7 */
415 			0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
416 			0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
417 			0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
418 		},
419 	},
420 	{	/*  mode#7: 800 x 600  32Bpp  60Hz */
421 		800, 600, 32, 60,
422 		/*  Init_MISC */
423 		0x2B,
424 		{	/*  Init_SR0_SR4 */
425 			0x03, 0x01, 0x0F, 0x03, 0x0E,
426 		},
427 		{	/*  Init_SR10_SR24 */
428 			0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
429 			0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
430 			0xC4, 0x30, 0x02, 0x01, 0x01,
431 		},
432 		{	/*  Init_SR30_SR75 */
433 			0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
434 			0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
435 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
436 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
437 			0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
438 			0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
439 			0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
440 			0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
441 			0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
442 		},
443 		{	/*  Init_SR80_SR93 */
444 			0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
445 			0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
446 			0x00, 0x00, 0x00, 0x00,
447 		},
448 		{	/*  Init_SRA0_SRAF */
449 			0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
450 			0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
451 		},
452 		{	/*  Init_GR00_GR08 */
453 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
454 			0xFF,
455 		},
456 		{	/*  Init_AR00_AR14 */
457 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
458 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
459 			0x41, 0x00, 0x0F, 0x00, 0x00,
460 		},
461 		{	/*  Init_CR00_CR18 */
462 			0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
463 			0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
464 			0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
465 			0xFF,
466 		},
467 		{	/*  Init_CR30_CR4D */
468 			0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
469 			0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
470 			0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
471 			0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
472 		},
473 		{	/*  Init_CR90_CRA7 */
474 			0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
475 			0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
476 			0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
477 		},
478 	},
479 	/* We use 1024x768 table to light 1024x600 panel for lemote */
480 	{	/*  mode#4: 1024 x 600  16Bpp  60Hz  */
481 		1024, 600, 16, 60,
482 		/*  Init_MISC */
483 		0xEB,
484 		{	/*  Init_SR0_SR4 */
485 			0x03, 0x01, 0x0F, 0x00, 0x0E,
486 		},
487 		{	/*  Init_SR10_SR24 */
488 			0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20,
489 			0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
490 			0xC4, 0x30, 0x02, 0x00, 0x01,
491 		},
492 		{	/*  Init_SR30_SR75 */
493 			0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22,
494 			0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF,
495 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
496 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22,
497 			0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
498 			0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22,
499 			0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
500 			0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02,
501 			0x04, 0x45, 0x3F, 0x30, 0x40, 0x20,
502 		},
503 		{	/*  Init_SR80_SR93 */
504 			0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
505 			0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
506 			0x00, 0x00, 0x00, 0x00,
507 		},
508 		{	/*  Init_SRA0_SRAF */
509 			0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
510 			0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
511 		},
512 		{	/*  Init_GR00_GR08 */
513 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
514 			0xFF,
515 		},
516 		{	/*  Init_AR00_AR14 */
517 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
518 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
519 			0x41, 0x00, 0x0F, 0x00, 0x00,
520 		},
521 		{	/*  Init_CR00_CR18 */
522 			0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
523 			0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
524 			0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
525 			0xFF,
526 		},
527 		{	/*  Init_CR30_CR4D */
528 			0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
529 			0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
530 			0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00,
531 			0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57,
532 		},
533 		{	/*  Init_CR90_CRA7 */
534 			0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
535 			0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
536 			0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
537 		},
538 	},
539 	{	/*  1024 x 768  16Bpp  60Hz */
540 		1024, 768, 16, 60,
541 		/*  Init_MISC */
542 		0xEB,
543 		{	/*  Init_SR0_SR4 */
544 			0x03, 0x01, 0x0F, 0x03, 0x0E,
545 		},
546 		{	/*  Init_SR10_SR24 */
547 			0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
548 			0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
549 			0xC4, 0x30, 0x02, 0x01, 0x01,
550 		},
551 		{	/*  Init_SR30_SR75 */
552 			0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
553 			0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
554 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
555 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
556 			0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
557 			0x0F, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
558 			0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
559 			0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
560 			0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
561 		},
562 		{	/*  Init_SR80_SR93 */
563 			0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
564 			0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
565 			0x00, 0x00, 0x00, 0x00,
566 		},
567 		{	/*  Init_SRA0_SRAF */
568 			0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
569 			0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
570 		},
571 		{	/*  Init_GR00_GR08 */
572 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
573 			0xFF,
574 		},
575 		{	/*  Init_AR00_AR14 */
576 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
577 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
578 			0x41, 0x00, 0x0F, 0x00, 0x00,
579 		},
580 		{	/*  Init_CR00_CR18 */
581 			0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
582 			0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
583 			0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
584 			0xFF,
585 		},
586 		{	/*  Init_CR30_CR4D */
587 			0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
588 			0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
589 			0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
590 			0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
591 		},
592 		{	/*  Init_CR90_CRA7 */
593 			0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
594 			0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
595 			0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
596 		},
597 	},
598 	{	/*  mode#5: 1024 x 768  24Bpp  60Hz */
599 		1024, 768, 24, 60,
600 		/*  Init_MISC */
601 		0xEB,
602 		{	/*  Init_SR0_SR4 */
603 			0x03, 0x01, 0x0F, 0x03, 0x0E,
604 		},
605 		{	/*  Init_SR10_SR24 */
606 			0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
607 			0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
608 			0xC4, 0x30, 0x02, 0x01, 0x01,
609 		},
610 		{	/*  Init_SR30_SR75 */
611 			0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
612 			0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
613 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
614 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
615 			0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
616 			0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
617 			0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
618 			0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
619 			0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
620 		},
621 		{	/*  Init_SR80_SR93 */
622 			0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
623 			0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
624 			0x00, 0x00, 0x00, 0x00,
625 		},
626 		{	/*  Init_SRA0_SRAF */
627 			0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
628 			0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
629 		},
630 		{	/*  Init_GR00_GR08 */
631 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
632 			0xFF,
633 		},
634 		{	/*  Init_AR00_AR14 */
635 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
636 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
637 			0x41, 0x00, 0x0F, 0x00, 0x00,
638 		},
639 		{	/*  Init_CR00_CR18 */
640 			0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
641 			0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642 			0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
643 			0xFF,
644 		},
645 		{	/*  Init_CR30_CR4D */
646 			0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
647 			0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
648 			0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
649 			0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
650 		},
651 		{	/*  Init_CR90_CRA7 */
652 			0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
653 			0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
654 			0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
655 		},
656 	},
657 	{	/*  mode#4: 1024 x 768  32Bpp  60Hz */
658 		1024, 768, 32, 60,
659 		/*  Init_MISC */
660 		0xEB,
661 		{	/*  Init_SR0_SR4 */
662 			0x03, 0x01, 0x0F, 0x03, 0x0E,
663 		},
664 		{	/*  Init_SR10_SR24 */
665 			0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
666 			0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
667 			0xC4, 0x32, 0x02, 0x01, 0x01,
668 		},
669 		{	/*  Init_SR30_SR75 */
670 			0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
671 			0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
672 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
673 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
674 			0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
675 			0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
676 			0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
677 			0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
678 			0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
679 		},
680 		{	/*  Init_SR80_SR93 */
681 			0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
682 			0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
683 			0x00, 0x00, 0x00, 0x00,
684 		},
685 		{	/*  Init_SRA0_SRAF */
686 			0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
687 			0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
688 		},
689 		{	/*  Init_GR00_GR08 */
690 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
691 			0xFF,
692 		},
693 		{	/*  Init_AR00_AR14 */
694 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
695 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
696 			0x41, 0x00, 0x0F, 0x00, 0x00,
697 		},
698 		{	/*  Init_CR00_CR18 */
699 			0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
700 			0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
701 			0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
702 			0xFF,
703 		},
704 		{	/*  Init_CR30_CR4D */
705 			0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
706 			0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
707 			0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
708 			0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
709 		},
710 		{	/*  Init_CR90_CRA7 */
711 			0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
712 			0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
713 			0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
714 		},
715 	},
716 	{	/*  mode#6: 320 x 240  16Bpp  60Hz */
717 		320, 240, 16, 60,
718 		/*  Init_MISC */
719 		0xEB,
720 		{	/*  Init_SR0_SR4 */
721 			0x03, 0x01, 0x0F, 0x03, 0x0E,
722 		},
723 		{	/*  Init_SR10_SR24 */
724 			0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
725 			0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
726 			0xC4, 0x32, 0x02, 0x01, 0x01,
727 		},
728 		{	/*  Init_SR30_SR75 */
729 			0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
730 			0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
731 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
732 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
733 			0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
734 			0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
735 			0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
736 			0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
737 			0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
738 		},
739 		{	/*  Init_SR80_SR93 */
740 			0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
741 			0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
742 			0x00, 0x00, 0x00, 0x00,
743 		},
744 		{	/*  Init_SRA0_SRAF */
745 			0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
746 			0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
747 		},
748 		{	/*  Init_GR00_GR08 */
749 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
750 			0xFF,
751 		},
752 		{	/*  Init_AR00_AR14 */
753 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
754 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
755 			0x41, 0x00, 0x0F, 0x00, 0x00,
756 		},
757 		{	/*  Init_CR00_CR18 */
758 			0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
759 			0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
760 			0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
761 			0xFF,
762 		},
763 		{	/*  Init_CR30_CR4D */
764 			0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
765 			0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
766 			0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
767 			0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
768 		},
769 		{	/*  Init_CR90_CRA7 */
770 			0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
771 			0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
772 			0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
773 		},
774 	},
775 
776 	{	/*  mode#8: 320 x 240  32Bpp  60Hz */
777 		320, 240, 32, 60,
778 		/*  Init_MISC */
779 		0xEB,
780 		{	/*  Init_SR0_SR4 */
781 			0x03, 0x01, 0x0F, 0x03, 0x0E,
782 		},
783 		{	/*  Init_SR10_SR24 */
784 			0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
785 			0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
786 			0xC4, 0x32, 0x02, 0x01, 0x01,
787 		},
788 		{	/*  Init_SR30_SR75 */
789 			0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
790 			0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
791 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
792 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
793 			0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
794 			0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
795 			0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
796 			0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
797 			0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
798 		},
799 		{	/*  Init_SR80_SR93 */
800 			0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
801 			0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
802 			0x00, 0x00, 0x00, 0x00,
803 		},
804 		{	/*  Init_SRA0_SRAF */
805 			0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
806 			0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
807 		},
808 		{	/*  Init_GR00_GR08 */
809 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
810 			0xFF,
811 		},
812 		{	/*  Init_AR00_AR14 */
813 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
814 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
815 			0x41, 0x00, 0x0F, 0x00, 0x00,
816 		},
817 		{	/*  Init_CR00_CR18 */
818 			0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
819 			0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
820 			0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
821 			0xFF,
822 		},
823 		{	/*  Init_CR30_CR4D */
824 			0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
825 			0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
826 			0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
827 			0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
828 		},
829 		{	/*  Init_CR90_CRA7 */
830 			0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
831 			0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
832 			0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
833 		},
834 	},
835 };
836 
837 static struct smtcfb_screen_info smtc_scr_info;
838 
839 static char *mode_option;
840 
841 /* process command line options, get vga parameter */
sm7xx_vga_setup(char * options)842 static void __init sm7xx_vga_setup(char *options)
843 {
844 	int i;
845 
846 	if (!options || !*options)
847 		return;
848 
849 	smtc_scr_info.lfb_width = 0;
850 	smtc_scr_info.lfb_height = 0;
851 	smtc_scr_info.lfb_depth = 0;
852 
853 	pr_debug("%s = %s\n", __func__, options);
854 
855 	for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
856 		if (strstr(options, vesa_mode_table[i].index)) {
857 			smtc_scr_info.lfb_width  = vesa_mode_table[i].lfb_width;
858 			smtc_scr_info.lfb_height =
859 						vesa_mode_table[i].lfb_height;
860 			smtc_scr_info.lfb_depth  = vesa_mode_table[i].lfb_depth;
861 			return;
862 		}
863 	}
864 }
865 
sm712_setpalette(int regno,unsigned int red,unsigned int green,unsigned int blue,struct fb_info * info)866 static void sm712_setpalette(int regno, unsigned int red, unsigned int green,
867 			     unsigned int blue, struct fb_info *info)
868 {
869 	/* set bit 5:4 = 01 (write LCD RAM only) */
870 	smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
871 
872 	smtc_mmiowb(regno, dac_reg);
873 	smtc_mmiowb(red >> 10, dac_val);
874 	smtc_mmiowb(green >> 10, dac_val);
875 	smtc_mmiowb(blue >> 10, dac_val);
876 }
877 
878 /* chan_to_field
879  *
880  * convert a colour value into a field position
881  *
882  * from pxafb.c
883  */
884 
chan_to_field(unsigned int chan,struct fb_bitfield * bf)885 static inline unsigned int chan_to_field(unsigned int chan,
886 					 struct fb_bitfield *bf)
887 {
888 	chan &= 0xffff;
889 	chan >>= 16 - bf->length;
890 	return chan << bf->offset;
891 }
892 
smtc_blank(int blank_mode,struct fb_info * info)893 static int smtc_blank(int blank_mode, struct fb_info *info)
894 {
895 	struct smtcfb_info *sfb = info->par;
896 
897 	/* clear DPMS setting */
898 	switch (blank_mode) {
899 	case FB_BLANK_UNBLANK:
900 		/* Screen On: HSync: On, VSync : On */
901 
902 		switch (sfb->chip_id) {
903 		case 0x710:
904 		case 0x712:
905 			smtc_seqw(0x6a, 0x16);
906 			smtc_seqw(0x6b, 0x02);
907 			break;
908 		case 0x720:
909 			smtc_seqw(0x6a, 0x0d);
910 			smtc_seqw(0x6b, 0x02);
911 			break;
912 		}
913 
914 		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
915 		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
916 		smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
917 		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
918 		smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
919 		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
920 		break;
921 	case FB_BLANK_NORMAL:
922 		/* Screen Off: HSync: On, VSync : On   Soft blank */
923 		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
924 		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
925 		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
926 		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
927 		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
928 		smtc_seqw(0x6a, 0x16);
929 		smtc_seqw(0x6b, 0x02);
930 		break;
931 	case FB_BLANK_VSYNC_SUSPEND:
932 		/* Screen On: HSync: On, VSync : Off */
933 		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
934 		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
935 		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
936 		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
937 		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
938 		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
939 		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
940 		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
941 		smtc_seqw(0x6a, 0x0c);
942 		smtc_seqw(0x6b, 0x02);
943 		break;
944 	case FB_BLANK_HSYNC_SUSPEND:
945 		/* Screen On: HSync: Off, VSync : On */
946 		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
947 		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
948 		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
949 		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
950 		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
951 		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
952 		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
953 		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
954 		smtc_seqw(0x6a, 0x0c);
955 		smtc_seqw(0x6b, 0x02);
956 		break;
957 	case FB_BLANK_POWERDOWN:
958 		/* Screen On: HSync: Off, VSync : Off */
959 		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
960 		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
961 		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
962 		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
963 		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
964 		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
965 		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
966 		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
967 		smtc_seqw(0x6a, 0x0c);
968 		smtc_seqw(0x6b, 0x02);
969 		break;
970 	default:
971 		return -EINVAL;
972 	}
973 
974 	return 0;
975 }
976 
smtc_setcolreg(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue,unsigned int trans,struct fb_info * info)977 static int smtc_setcolreg(unsigned int regno, unsigned int red,
978 			  unsigned int green, unsigned int blue,
979 			  unsigned int trans, struct fb_info *info)
980 {
981 	struct smtcfb_info *sfb;
982 	u32 val;
983 
984 	sfb = info->par;
985 
986 	if (regno > 255)
987 		return 1;
988 
989 	switch (sfb->fb->fix.visual) {
990 	case FB_VISUAL_DIRECTCOLOR:
991 	case FB_VISUAL_TRUECOLOR:
992 		/*
993 		 * 16/32 bit true-colour, use pseudo-palette for 16 base color
994 		 */
995 		if (regno >= 16)
996 			break;
997 		if (sfb->fb->var.bits_per_pixel == 16) {
998 			u32 *pal = sfb->fb->pseudo_palette;
999 
1000 			val = chan_to_field(red, &sfb->fb->var.red);
1001 			val |= chan_to_field(green, &sfb->fb->var.green);
1002 			val |= chan_to_field(blue, &sfb->fb->var.blue);
1003 			pal[regno] = pal_rgb(red, green, blue, val);
1004 		} else {
1005 			u32 *pal = sfb->fb->pseudo_palette;
1006 
1007 			val = chan_to_field(red, &sfb->fb->var.red);
1008 			val |= chan_to_field(green, &sfb->fb->var.green);
1009 			val |= chan_to_field(blue, &sfb->fb->var.blue);
1010 			pal[regno] = big_swap(val);
1011 		}
1012 		break;
1013 
1014 	case FB_VISUAL_PSEUDOCOLOR:
1015 		/* color depth 8 bit */
1016 		sm712_setpalette(regno, red, green, blue, info);
1017 		break;
1018 
1019 	default:
1020 		return 1;	/* unknown type */
1021 	}
1022 
1023 	return 0;
1024 }
1025 
smtcfb_read(struct fb_info * info,char __user * buf,size_t count,loff_t * ppos)1026 static ssize_t smtcfb_read(struct fb_info *info, char __user *buf,
1027 			   size_t count, loff_t *ppos)
1028 {
1029 	unsigned long p = *ppos;
1030 
1031 	u32 *buffer, *dst;
1032 	u32 __iomem *src;
1033 	int c, i, cnt = 0, err = 0;
1034 	unsigned long total_size;
1035 
1036 	if (!info->screen_base)
1037 		return -ENODEV;
1038 
1039 	total_size = info->screen_size;
1040 
1041 	if (total_size == 0)
1042 		total_size = info->fix.smem_len;
1043 
1044 	if (p >= total_size)
1045 		return 0;
1046 
1047 	if (count >= total_size)
1048 		count = total_size;
1049 
1050 	if (count + p > total_size)
1051 		count = total_size - p;
1052 
1053 	buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
1054 	if (!buffer)
1055 		return -ENOMEM;
1056 
1057 	src = (u32 __iomem *)(info->screen_base + p);
1058 
1059 	if (info->fbops->fb_sync)
1060 		info->fbops->fb_sync(info);
1061 
1062 	while (count) {
1063 		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1064 		dst = buffer;
1065 		for (i = (c + 3) >> 2; i--;) {
1066 			u32 val;
1067 
1068 			val = fb_readl(src);
1069 			*dst = big_swap(val);
1070 			src++;
1071 			dst++;
1072 		}
1073 
1074 		if (copy_to_user(buf, buffer, c)) {
1075 			err = -EFAULT;
1076 			break;
1077 		}
1078 		*ppos += c;
1079 		buf += c;
1080 		cnt += c;
1081 		count -= c;
1082 	}
1083 
1084 	kfree(buffer);
1085 
1086 	return (err) ? err : cnt;
1087 }
1088 
smtcfb_write(struct fb_info * info,const char __user * buf,size_t count,loff_t * ppos)1089 static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
1090 			    size_t count, loff_t *ppos)
1091 {
1092 	unsigned long p = *ppos;
1093 
1094 	u32 *buffer, *src;
1095 	u32 __iomem *dst;
1096 	int c, i, cnt = 0, err = 0;
1097 	unsigned long total_size;
1098 
1099 	if (!info->screen_base)
1100 		return -ENODEV;
1101 
1102 	total_size = info->screen_size;
1103 
1104 	if (total_size == 0)
1105 		total_size = info->fix.smem_len;
1106 
1107 	if (p > total_size)
1108 		return -EFBIG;
1109 
1110 	if (count > total_size) {
1111 		err = -EFBIG;
1112 		count = total_size;
1113 	}
1114 
1115 	if (count + p > total_size) {
1116 		if (!err)
1117 			err = -ENOSPC;
1118 
1119 		count = total_size - p;
1120 	}
1121 
1122 	buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
1123 	if (!buffer)
1124 		return -ENOMEM;
1125 
1126 	dst = (u32 __iomem *)(info->screen_base + p);
1127 
1128 	if (info->fbops->fb_sync)
1129 		info->fbops->fb_sync(info);
1130 
1131 	while (count) {
1132 		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1133 		src = buffer;
1134 
1135 		if (copy_from_user(src, buf, c)) {
1136 			err = -EFAULT;
1137 			break;
1138 		}
1139 
1140 		for (i = (c + 3) >> 2; i--;) {
1141 			fb_writel(big_swap(*src), dst);
1142 			dst++;
1143 			src++;
1144 		}
1145 
1146 		*ppos += c;
1147 		buf += c;
1148 		cnt += c;
1149 		count -= c;
1150 	}
1151 
1152 	kfree(buffer);
1153 
1154 	return (cnt) ? cnt : err;
1155 }
1156 
sm7xx_set_timing(struct smtcfb_info * sfb)1157 static void sm7xx_set_timing(struct smtcfb_info *sfb)
1158 {
1159 	int i = 0, j = 0;
1160 	u32 m_nscreenstride;
1161 
1162 	dev_dbg(&sfb->pdev->dev,
1163 		"sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n",
1164 		sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz);
1165 
1166 	for (j = 0; j < ARRAY_SIZE(vgamode); j++) {
1167 		if (vgamode[j].mmsizex != sfb->width ||
1168 		    vgamode[j].mmsizey != sfb->height ||
1169 		    vgamode[j].bpp != sfb->fb->var.bits_per_pixel ||
1170 		    vgamode[j].hz != sfb->hz)
1171 			continue;
1172 
1173 		dev_dbg(&sfb->pdev->dev,
1174 			"vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
1175 			vgamode[j].mmsizex, vgamode[j].mmsizey,
1176 			vgamode[j].bpp, vgamode[j].hz);
1177 
1178 		dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
1179 
1180 		smtc_mmiowb(0x0, 0x3c6);
1181 
1182 		smtc_seqw(0, 0x1);
1183 
1184 		smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
1185 
1186 		/* init SEQ register SR00 - SR04 */
1187 		for (i = 0; i < SIZE_SR00_SR04; i++)
1188 			smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
1189 
1190 		/* init SEQ register SR10 - SR24 */
1191 		for (i = 0; i < SIZE_SR10_SR24; i++)
1192 			smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]);
1193 
1194 		/* init SEQ register SR30 - SR75 */
1195 		for (i = 0; i < SIZE_SR30_SR75; i++)
1196 			if ((i + 0x30) != 0x30 && (i + 0x30) != 0x62 &&
1197 			    (i + 0x30) != 0x6a && (i + 0x30) != 0x6b &&
1198 			    (i + 0x30) != 0x70 && (i + 0x30) != 0x71 &&
1199 			    (i + 0x30) != 0x74 && (i + 0x30) != 0x75)
1200 				smtc_seqw(i + 0x30,
1201 					  vgamode[j].init_sr30_sr75[i]);
1202 
1203 		/* init SEQ register SR80 - SR93 */
1204 		for (i = 0; i < SIZE_SR80_SR93; i++)
1205 			smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]);
1206 
1207 		/* init SEQ register SRA0 - SRAF */
1208 		for (i = 0; i < SIZE_SRA0_SRAF; i++)
1209 			smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]);
1210 
1211 		/* init Graphic register GR00 - GR08 */
1212 		for (i = 0; i < SIZE_GR00_GR08; i++)
1213 			smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
1214 
1215 		/* init Attribute register AR00 - AR14 */
1216 		for (i = 0; i < SIZE_AR00_AR14; i++)
1217 			smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
1218 
1219 		/* init CRTC register CR00 - CR18 */
1220 		for (i = 0; i < SIZE_CR00_CR18; i++)
1221 			smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
1222 
1223 		/* init CRTC register CR30 - CR4D */
1224 		for (i = 0; i < SIZE_CR30_CR4D; i++) {
1225 			if ((i + 0x30) >= 0x3B && (i + 0x30) <= 0x3F)
1226 				/* side-effect, don't write to CR3B-CR3F */
1227 				continue;
1228 			smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
1229 		}
1230 
1231 		/* init CRTC register CR90 - CRA7 */
1232 		for (i = 0; i < SIZE_CR90_CRA7; i++)
1233 			smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]);
1234 	}
1235 	smtc_mmiowb(0x67, 0x3c2);
1236 
1237 	/* set VPR registers */
1238 	writel(0x0, sfb->vp_regs + 0x0C);
1239 	writel(0x0, sfb->vp_regs + 0x40);
1240 
1241 	/* set data width */
1242 	m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64;
1243 	switch (sfb->fb->var.bits_per_pixel) {
1244 	case 8:
1245 		writel(0x0, sfb->vp_regs + 0x0);
1246 		break;
1247 	case 16:
1248 		writel(0x00020000, sfb->vp_regs + 0x0);
1249 		break;
1250 	case 24:
1251 		writel(0x00040000, sfb->vp_regs + 0x0);
1252 		break;
1253 	case 32:
1254 		writel(0x00030000, sfb->vp_regs + 0x0);
1255 		break;
1256 	}
1257 	writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride),
1258 	       sfb->vp_regs + 0x10);
1259 }
1260 
smtc_set_timing(struct smtcfb_info * sfb)1261 static void smtc_set_timing(struct smtcfb_info *sfb)
1262 {
1263 	switch (sfb->chip_id) {
1264 	case 0x710:
1265 	case 0x712:
1266 	case 0x720:
1267 		sm7xx_set_timing(sfb);
1268 		break;
1269 	}
1270 }
1271 
smtcfb_setmode(struct smtcfb_info * sfb)1272 static void smtcfb_setmode(struct smtcfb_info *sfb)
1273 {
1274 	switch (sfb->fb->var.bits_per_pixel) {
1275 	case 32:
1276 		sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1277 		sfb->fb->fix.line_length  = sfb->fb->var.xres * 4;
1278 		sfb->fb->var.red.length   = 8;
1279 		sfb->fb->var.green.length = 8;
1280 		sfb->fb->var.blue.length  = 8;
1281 		sfb->fb->var.red.offset   = 16;
1282 		sfb->fb->var.green.offset = 8;
1283 		sfb->fb->var.blue.offset  = 0;
1284 		break;
1285 	case 24:
1286 		sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1287 		sfb->fb->fix.line_length  = sfb->fb->var.xres * 3;
1288 		sfb->fb->var.red.length   = 8;
1289 		sfb->fb->var.green.length = 8;
1290 		sfb->fb->var.blue.length  = 8;
1291 		sfb->fb->var.red.offset   = 16;
1292 		sfb->fb->var.green.offset = 8;
1293 		sfb->fb->var.blue.offset  = 0;
1294 		break;
1295 	case 8:
1296 		sfb->fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
1297 		sfb->fb->fix.line_length  = sfb->fb->var.xres;
1298 		sfb->fb->var.red.length   = 3;
1299 		sfb->fb->var.green.length = 3;
1300 		sfb->fb->var.blue.length  = 2;
1301 		sfb->fb->var.red.offset   = 5;
1302 		sfb->fb->var.green.offset = 2;
1303 		sfb->fb->var.blue.offset  = 0;
1304 		break;
1305 	case 16:
1306 	default:
1307 		sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1308 		sfb->fb->fix.line_length  = sfb->fb->var.xres * 2;
1309 		sfb->fb->var.red.length   = 5;
1310 		sfb->fb->var.green.length = 6;
1311 		sfb->fb->var.blue.length  = 5;
1312 		sfb->fb->var.red.offset   = 11;
1313 		sfb->fb->var.green.offset = 5;
1314 		sfb->fb->var.blue.offset  = 0;
1315 		break;
1316 	}
1317 
1318 	sfb->width  = sfb->fb->var.xres;
1319 	sfb->height = sfb->fb->var.yres;
1320 	sfb->hz = 60;
1321 	smtc_set_timing(sfb);
1322 }
1323 
smtc_check_var(struct fb_var_screeninfo * var,struct fb_info * info)1324 static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1325 {
1326 	/* sanity checks */
1327 	if (var->xres_virtual < var->xres)
1328 		var->xres_virtual = var->xres;
1329 
1330 	if (var->yres_virtual < var->yres)
1331 		var->yres_virtual = var->yres;
1332 
1333 	/* set valid default bpp */
1334 	if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
1335 	    (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
1336 		var->bits_per_pixel = 16;
1337 
1338 	return 0;
1339 }
1340 
smtc_set_par(struct fb_info * info)1341 static int smtc_set_par(struct fb_info *info)
1342 {
1343 	smtcfb_setmode(info->par);
1344 
1345 	return 0;
1346 }
1347 
1348 static const struct fb_ops smtcfb_ops = {
1349 	.owner        = THIS_MODULE,
1350 	.fb_check_var = smtc_check_var,
1351 	.fb_set_par   = smtc_set_par,
1352 	.fb_setcolreg = smtc_setcolreg,
1353 	.fb_blank     = smtc_blank,
1354 	.fb_fillrect  = cfb_fillrect,
1355 	.fb_imageblit = cfb_imageblit,
1356 	.fb_copyarea  = cfb_copyarea,
1357 	.fb_read      = smtcfb_read,
1358 	.fb_write     = smtcfb_write,
1359 };
1360 
1361 /*
1362  * Unmap in the memory mapped IO registers
1363  */
1364 
smtc_unmap_mmio(struct smtcfb_info * sfb)1365 static void smtc_unmap_mmio(struct smtcfb_info *sfb)
1366 {
1367 	if (sfb && smtc_regbaseaddress)
1368 		smtc_regbaseaddress = NULL;
1369 }
1370 
1371 /*
1372  * Map in the screen memory
1373  */
1374 
smtc_map_smem(struct smtcfb_info * sfb,struct pci_dev * pdev,u_long smem_len)1375 static int smtc_map_smem(struct smtcfb_info *sfb,
1376 			 struct pci_dev *pdev, u_long smem_len)
1377 {
1378 	sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
1379 
1380 	if (sfb->chip_id == 0x720)
1381 		/* on SM720, the framebuffer starts at the 1 MB offset */
1382 		sfb->fb->fix.smem_start += 0x00200000;
1383 
1384 	/* XXX: is it safe for SM720 on Big-Endian? */
1385 	if (sfb->fb->var.bits_per_pixel == 32)
1386 		sfb->fb->fix.smem_start += big_addr;
1387 
1388 	sfb->fb->fix.smem_len = smem_len;
1389 
1390 	sfb->fb->screen_base = sfb->lfb;
1391 
1392 	if (!sfb->fb->screen_base) {
1393 		dev_err(&pdev->dev,
1394 			"%s: unable to map screen memory\n", sfb->fb->fix.id);
1395 		return -ENOMEM;
1396 	}
1397 
1398 	return 0;
1399 }
1400 
1401 /*
1402  * Unmap in the screen memory
1403  *
1404  */
smtc_unmap_smem(struct smtcfb_info * sfb)1405 static void smtc_unmap_smem(struct smtcfb_info *sfb)
1406 {
1407 	if (sfb && sfb->fb->screen_base) {
1408 		if (sfb->chip_id == 0x720)
1409 			sfb->fb->screen_base -= 0x00200000;
1410 		iounmap(sfb->fb->screen_base);
1411 		sfb->fb->screen_base = NULL;
1412 	}
1413 }
1414 
1415 /*
1416  * We need to wake up the device and make sure its in linear memory mode.
1417  */
sm7xx_init_hw(void)1418 static inline void sm7xx_init_hw(void)
1419 {
1420 	outb_p(0x18, 0x3c4);
1421 	outb_p(0x11, 0x3c5);
1422 }
1423 
sm7xx_vram_probe(struct smtcfb_info * sfb)1424 static u_long sm7xx_vram_probe(struct smtcfb_info *sfb)
1425 {
1426 	u8 vram;
1427 
1428 	switch (sfb->chip_id) {
1429 	case 0x710:
1430 	case 0x712:
1431 		/*
1432 		 * Assume SM712 graphics chip has 4MB VRAM.
1433 		 *
1434 		 * FIXME: SM712 can have 2MB VRAM, which is used on earlier
1435 		 * laptops, such as IBM Thinkpad 240X. This driver would
1436 		 * probably crash on those machines. If anyone gets one of
1437 		 * those and is willing to help, run "git blame" and send me
1438 		 * an E-mail.
1439 		 */
1440 		return 0x00400000;
1441 	case 0x720:
1442 		outb_p(0x76, 0x3c4);
1443 		vram = inb_p(0x3c5) >> 6;
1444 
1445 		if (vram == 0x00)
1446 			return 0x00800000;  /* 8 MB */
1447 		else if (vram == 0x01)
1448 			return 0x01000000;  /* 16 MB */
1449 		else if (vram == 0x02)
1450 			return 0x00400000;  /* illegal, fallback to 4 MB */
1451 		else if (vram == 0x03)
1452 			return 0x00400000;  /* 4 MB */
1453 	}
1454 	return 0;  /* unknown hardware */
1455 }
1456 
sm7xx_resolution_probe(struct smtcfb_info * sfb)1457 static void sm7xx_resolution_probe(struct smtcfb_info *sfb)
1458 {
1459 	/* get mode parameter from smtc_scr_info */
1460 	if (smtc_scr_info.lfb_width != 0) {
1461 		sfb->fb->var.xres = smtc_scr_info.lfb_width;
1462 		sfb->fb->var.yres = smtc_scr_info.lfb_height;
1463 		sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
1464 		goto final;
1465 	}
1466 
1467 	/*
1468 	 * No parameter, default resolution is 1024x768-16.
1469 	 *
1470 	 * FIXME: earlier laptops, such as IBM Thinkpad 240X, has a 800x600
1471 	 * panel, also see the comments about Thinkpad 240X above.
1472 	 */
1473 	sfb->fb->var.xres = SCREEN_X_RES;
1474 	sfb->fb->var.yres = SCREEN_Y_RES_PC;
1475 	sfb->fb->var.bits_per_pixel = SCREEN_BPP;
1476 
1477 #ifdef CONFIG_MIPS
1478 	/*
1479 	 * Loongson MIPS netbooks use 1024x600 LCD panels, which is the original
1480 	 * target platform of this driver, but nearly all old x86 laptops have
1481 	 * 1024x768. Lighting 768 panels using 600's timings would partially
1482 	 * garble the display, so we don't want that. But it's not possible to
1483 	 * distinguish them reliably.
1484 	 *
1485 	 * So we change the default to 768, but keep 600 as-is on MIPS.
1486 	 */
1487 	sfb->fb->var.yres = SCREEN_Y_RES_NETBOOK;
1488 #endif
1489 
1490 final:
1491 	big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
1492 }
1493 
smtcfb_pci_probe(struct pci_dev * pdev,const struct pci_device_id * ent)1494 static int smtcfb_pci_probe(struct pci_dev *pdev,
1495 			    const struct pci_device_id *ent)
1496 {
1497 	struct smtcfb_info *sfb;
1498 	struct fb_info *info;
1499 	u_long smem_size;
1500 	int err;
1501 	unsigned long mmio_base;
1502 
1503 	dev_info(&pdev->dev, "Silicon Motion display driver.\n");
1504 
1505 	err = aperture_remove_conflicting_pci_devices(pdev, "smtcfb");
1506 	if (err)
1507 		return err;
1508 
1509 	err = pci_enable_device(pdev);	/* enable SMTC chip */
1510 	if (err)
1511 		return err;
1512 
1513 	err = pci_request_region(pdev, 0, "sm7xxfb");
1514 	if (err < 0) {
1515 		dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
1516 		goto failed_regions;
1517 	}
1518 
1519 	sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
1520 
1521 	info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
1522 	if (!info) {
1523 		err = -ENOMEM;
1524 		goto failed_free;
1525 	}
1526 
1527 	sfb = info->par;
1528 	sfb->fb = info;
1529 	sfb->chip_id = ent->device;
1530 	sfb->pdev = pdev;
1531 	info->fbops = &smtcfb_ops;
1532 	info->fix = smtcfb_fix;
1533 	info->var = smtcfb_var;
1534 	info->pseudo_palette = sfb->colreg;
1535 	info->par = sfb;
1536 
1537 	pci_set_drvdata(pdev, sfb);
1538 
1539 	sm7xx_init_hw();
1540 
1541 	/* Map address and memory detection */
1542 	mmio_base = pci_resource_start(pdev, 0);
1543 	pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
1544 
1545 	smem_size = sm7xx_vram_probe(sfb);
1546 	dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n",
1547 					smem_size / 1048576);
1548 
1549 	switch (sfb->chip_id) {
1550 	case 0x710:
1551 	case 0x712:
1552 		sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
1553 		sfb->fb->fix.mmio_len = 0x00400000;
1554 		sfb->lfb = ioremap(mmio_base, mmio_addr);
1555 		if (!sfb->lfb) {
1556 			dev_err(&pdev->dev,
1557 				"%s: unable to map memory mapped IO!\n",
1558 				sfb->fb->fix.id);
1559 			err = -ENOMEM;
1560 			goto failed_fb;
1561 		}
1562 
1563 		sfb->mmio = (smtc_regbaseaddress =
1564 		    sfb->lfb + 0x00700000);
1565 		sfb->dp_regs = sfb->lfb + 0x00408000;
1566 		sfb->vp_regs = sfb->lfb + 0x0040c000;
1567 		if (sfb->fb->var.bits_per_pixel == 32) {
1568 			sfb->lfb += big_addr;
1569 			dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
1570 		}
1571 
1572 		/* set MCLK = 14.31818 * (0x16 / 0x2) */
1573 		smtc_seqw(0x6a, 0x16);
1574 		smtc_seqw(0x6b, 0x02);
1575 		smtc_seqw(0x62, 0x3e);
1576 		/* enable PCI burst */
1577 		smtc_seqw(0x17, 0x20);
1578 		/* enable word swap */
1579 		if (sfb->fb->var.bits_per_pixel == 32)
1580 			seqw17();
1581 		break;
1582 	case 0x720:
1583 		sfb->fb->fix.mmio_start = mmio_base;
1584 		sfb->fb->fix.mmio_len = 0x00200000;
1585 		sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
1586 		if (!sfb->dp_regs) {
1587 			dev_err(&pdev->dev,
1588 				"%s: unable to map memory mapped IO!\n",
1589 				sfb->fb->fix.id);
1590 			err = -ENOMEM;
1591 			goto failed_fb;
1592 		}
1593 
1594 		sfb->lfb = sfb->dp_regs + 0x00200000;
1595 		sfb->mmio = (smtc_regbaseaddress =
1596 		    sfb->dp_regs + 0x000c0000);
1597 		sfb->vp_regs = sfb->dp_regs + 0x800;
1598 
1599 		smtc_seqw(0x62, 0xff);
1600 		smtc_seqw(0x6a, 0x0d);
1601 		smtc_seqw(0x6b, 0x02);
1602 		break;
1603 	default:
1604 		dev_err(&pdev->dev,
1605 			"No valid Silicon Motion display chip was detected!\n");
1606 		err = -ENODEV;
1607 		goto failed_fb;
1608 	}
1609 
1610 	/* probe and decide resolution */
1611 	sm7xx_resolution_probe(sfb);
1612 
1613 	/* can support 32 bpp */
1614 	if (sfb->fb->var.bits_per_pixel == 15)
1615 		sfb->fb->var.bits_per_pixel = 16;
1616 
1617 	sfb->fb->var.xres_virtual = sfb->fb->var.xres;
1618 	sfb->fb->var.yres_virtual = sfb->fb->var.yres;
1619 	err = smtc_map_smem(sfb, pdev, smem_size);
1620 	if (err)
1621 		goto failed;
1622 
1623 	/*
1624 	 * The screen would be temporarily garbled when sm712fb takes over
1625 	 * vesafb or VGA text mode. Zero the framebuffer.
1626 	 */
1627 	memset_io(sfb->lfb, 0, sfb->fb->fix.smem_len);
1628 
1629 	err = register_framebuffer(info);
1630 	if (err < 0)
1631 		goto failed;
1632 
1633 	dev_info(&pdev->dev,
1634 		 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n",
1635 		 sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
1636 		 sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
1637 
1638 	return 0;
1639 
1640 failed:
1641 	dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n");
1642 
1643 	smtc_unmap_smem(sfb);
1644 	smtc_unmap_mmio(sfb);
1645 failed_fb:
1646 	framebuffer_release(info);
1647 
1648 failed_free:
1649 	pci_release_region(pdev, 0);
1650 
1651 failed_regions:
1652 	pci_disable_device(pdev);
1653 
1654 	return err;
1655 }
1656 
1657 /*
1658  * 0x710 (LynxEM)
1659  * 0x712 (LynxEM+)
1660  * 0x720 (Lynx3DM, Lynx3DM+)
1661  */
1662 static const struct pci_device_id smtcfb_pci_table[] = {
1663 	{ PCI_DEVICE(0x126f, 0x710), },
1664 	{ PCI_DEVICE(0x126f, 0x712), },
1665 	{ PCI_DEVICE(0x126f, 0x720), },
1666 	{0,}
1667 };
1668 
1669 MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
1670 
smtcfb_pci_remove(struct pci_dev * pdev)1671 static void smtcfb_pci_remove(struct pci_dev *pdev)
1672 {
1673 	struct smtcfb_info *sfb;
1674 
1675 	sfb = pci_get_drvdata(pdev);
1676 	smtc_unmap_smem(sfb);
1677 	smtc_unmap_mmio(sfb);
1678 	unregister_framebuffer(sfb->fb);
1679 	framebuffer_release(sfb->fb);
1680 	pci_release_region(pdev, 0);
1681 	pci_disable_device(pdev);
1682 }
1683 
smtcfb_pci_suspend(struct device * device)1684 static int __maybe_unused smtcfb_pci_suspend(struct device *device)
1685 {
1686 	struct smtcfb_info *sfb = dev_get_drvdata(device);
1687 
1688 
1689 	/* set the hw in sleep mode use external clock and self memory refresh
1690 	 * so that we can turn off internal PLLs later on
1691 	 */
1692 	smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1693 	smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1694 
1695 	console_lock();
1696 	fb_set_suspend(sfb->fb, 1);
1697 	console_unlock();
1698 
1699 	/* additionally turn off all function blocks including internal PLLs */
1700 	smtc_seqw(0x21, 0xff);
1701 
1702 	return 0;
1703 }
1704 
smtcfb_pci_resume(struct device * device)1705 static int __maybe_unused smtcfb_pci_resume(struct device *device)
1706 {
1707 	struct smtcfb_info *sfb = dev_get_drvdata(device);
1708 
1709 
1710 	/* reinit hardware */
1711 	sm7xx_init_hw();
1712 	switch (sfb->chip_id) {
1713 	case 0x710:
1714 	case 0x712:
1715 		/* set MCLK = 14.31818 *  (0x16 / 0x2) */
1716 		smtc_seqw(0x6a, 0x16);
1717 		smtc_seqw(0x6b, 0x02);
1718 		smtc_seqw(0x62, 0x3e);
1719 		/* enable PCI burst */
1720 		smtc_seqw(0x17, 0x20);
1721 		if (sfb->fb->var.bits_per_pixel == 32)
1722 			seqw17();
1723 		break;
1724 	case 0x720:
1725 		smtc_seqw(0x62, 0xff);
1726 		smtc_seqw(0x6a, 0x0d);
1727 		smtc_seqw(0x6b, 0x02);
1728 		break;
1729 	}
1730 
1731 	smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1732 	smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1733 
1734 	smtcfb_setmode(sfb);
1735 
1736 	console_lock();
1737 	fb_set_suspend(sfb->fb, 0);
1738 	console_unlock();
1739 
1740 	return 0;
1741 }
1742 
1743 static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1744 
1745 static struct pci_driver smtcfb_driver = {
1746 	.name = "smtcfb",
1747 	.id_table = smtcfb_pci_table,
1748 	.probe = smtcfb_pci_probe,
1749 	.remove = smtcfb_pci_remove,
1750 	.driver.pm  = &sm7xx_pm_ops,
1751 };
1752 
sm712fb_init(void)1753 static int __init sm712fb_init(void)
1754 {
1755 	char *option = NULL;
1756 
1757 	if (fb_modesetting_disabled("sm712fb"))
1758 		return -ENODEV;
1759 
1760 	if (fb_get_options("sm712fb", &option))
1761 		return -ENODEV;
1762 	if (option && *option)
1763 		mode_option = option;
1764 	sm7xx_vga_setup(mode_option);
1765 
1766 	return pci_register_driver(&smtcfb_driver);
1767 }
1768 
1769 module_init(sm712fb_init);
1770 
sm712fb_exit(void)1771 static void __exit sm712fb_exit(void)
1772 {
1773 	pci_unregister_driver(&smtcfb_driver);
1774 }
1775 
1776 module_exit(sm712fb_exit);
1777 
1778 MODULE_AUTHOR("Siliconmotion ");
1779 MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1780 MODULE_LICENSE("GPL");
1781