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