xref: /linux/drivers/video/fbdev/sm712fb.c (revision e9a83bd2322035ed9d7dcf35753d3f984d76c6a5)
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 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 		iounmap(sfb->fb->screen_base);
1433 		sfb->fb->screen_base = NULL;
1434 	}
1435 }
1436 
1437 /*
1438  * We need to wake up the device and make sure its in linear memory mode.
1439  */
1440 static inline void sm7xx_init_hw(void)
1441 {
1442 	outb_p(0x18, 0x3c4);
1443 	outb_p(0x11, 0x3c5);
1444 }
1445 
1446 static u_long sm7xx_vram_probe(struct smtcfb_info *sfb)
1447 {
1448 	u8 vram;
1449 
1450 	switch (sfb->chip_id) {
1451 	case 0x710:
1452 	case 0x712:
1453 		/*
1454 		 * Assume SM712 graphics chip has 4MB VRAM.
1455 		 *
1456 		 * FIXME: SM712 can have 2MB VRAM, which is used on earlier
1457 		 * laptops, such as IBM Thinkpad 240X. This driver would
1458 		 * probably crash on those machines. If anyone gets one of
1459 		 * those and is willing to help, run "git blame" and send me
1460 		 * an E-mail.
1461 		 */
1462 		return 0x00400000;
1463 	case 0x720:
1464 		outb_p(0x76, 0x3c4);
1465 		vram = inb_p(0x3c5) >> 6;
1466 
1467 		if (vram == 0x00)
1468 			return 0x00800000;  /* 8 MB */
1469 		else if (vram == 0x01)
1470 			return 0x01000000;  /* 16 MB */
1471 		else if (vram == 0x02)
1472 			return 0x00400000;  /* illegal, fallback to 4 MB */
1473 		else if (vram == 0x03)
1474 			return 0x00400000;  /* 4 MB */
1475 	}
1476 	return 0;  /* unknown hardware */
1477 }
1478 
1479 static void sm7xx_resolution_probe(struct smtcfb_info *sfb)
1480 {
1481 	/* get mode parameter from smtc_scr_info */
1482 	if (smtc_scr_info.lfb_width != 0) {
1483 		sfb->fb->var.xres = smtc_scr_info.lfb_width;
1484 		sfb->fb->var.yres = smtc_scr_info.lfb_height;
1485 		sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
1486 		goto final;
1487 	}
1488 
1489 	/*
1490 	 * No parameter, default resolution is 1024x768-16.
1491 	 *
1492 	 * FIXME: earlier laptops, such as IBM Thinkpad 240X, has a 800x600
1493 	 * panel, also see the comments about Thinkpad 240X above.
1494 	 */
1495 	sfb->fb->var.xres = SCREEN_X_RES;
1496 	sfb->fb->var.yres = SCREEN_Y_RES_PC;
1497 	sfb->fb->var.bits_per_pixel = SCREEN_BPP;
1498 
1499 #ifdef CONFIG_MIPS
1500 	/*
1501 	 * Loongson MIPS netbooks use 1024x600 LCD panels, which is the original
1502 	 * target platform of this driver, but nearly all old x86 laptops have
1503 	 * 1024x768. Lighting 768 panels using 600's timings would partially
1504 	 * garble the display, so we don't want that. But it's not possible to
1505 	 * distinguish them reliably.
1506 	 *
1507 	 * So we change the default to 768, but keep 600 as-is on MIPS.
1508 	 */
1509 	sfb->fb->var.yres = SCREEN_Y_RES_NETBOOK;
1510 #endif
1511 
1512 final:
1513 	big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
1514 }
1515 
1516 static int smtcfb_pci_probe(struct pci_dev *pdev,
1517 			    const struct pci_device_id *ent)
1518 {
1519 	struct smtcfb_info *sfb;
1520 	struct fb_info *info;
1521 	u_long smem_size;
1522 	int err;
1523 	unsigned long mmio_base;
1524 
1525 	dev_info(&pdev->dev, "Silicon Motion display driver.\n");
1526 
1527 	err = pci_enable_device(pdev);	/* enable SMTC chip */
1528 	if (err)
1529 		return err;
1530 
1531 	err = pci_request_region(pdev, 0, "sm7xxfb");
1532 	if (err < 0) {
1533 		dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
1534 		goto failed_regions;
1535 	}
1536 
1537 	sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
1538 
1539 	info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
1540 	if (!info) {
1541 		err = -ENOMEM;
1542 		goto failed_free;
1543 	}
1544 
1545 	sfb = info->par;
1546 	sfb->fb = info;
1547 	sfb->chip_id = ent->device;
1548 	sfb->pdev = pdev;
1549 	info->flags = FBINFO_FLAG_DEFAULT;
1550 	info->fbops = &smtcfb_ops;
1551 	info->fix = smtcfb_fix;
1552 	info->var = smtcfb_var;
1553 	info->pseudo_palette = sfb->colreg;
1554 	info->par = sfb;
1555 
1556 	pci_set_drvdata(pdev, sfb);
1557 
1558 	sm7xx_init_hw();
1559 
1560 	/* Map address and memory detection */
1561 	mmio_base = pci_resource_start(pdev, 0);
1562 	pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
1563 
1564 	smem_size = sm7xx_vram_probe(sfb);
1565 	dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n",
1566 					smem_size / 1048576);
1567 
1568 	switch (sfb->chip_id) {
1569 	case 0x710:
1570 	case 0x712:
1571 		sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
1572 		sfb->fb->fix.mmio_len = 0x00400000;
1573 		sfb->lfb = ioremap(mmio_base, mmio_addr);
1574 		if (!sfb->lfb) {
1575 			dev_err(&pdev->dev,
1576 				"%s: unable to map memory mapped IO!\n",
1577 				sfb->fb->fix.id);
1578 			err = -ENOMEM;
1579 			goto failed_fb;
1580 		}
1581 
1582 		sfb->mmio = (smtc_regbaseaddress =
1583 		    sfb->lfb + 0x00700000);
1584 		sfb->dp_regs = sfb->lfb + 0x00408000;
1585 		sfb->vp_regs = sfb->lfb + 0x0040c000;
1586 		if (sfb->fb->var.bits_per_pixel == 32) {
1587 			sfb->lfb += big_addr;
1588 			dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
1589 		}
1590 
1591 		/* set MCLK = 14.31818 * (0x16 / 0x2) */
1592 		smtc_seqw(0x6a, 0x16);
1593 		smtc_seqw(0x6b, 0x02);
1594 		smtc_seqw(0x62, 0x3e);
1595 		/* enable PCI burst */
1596 		smtc_seqw(0x17, 0x20);
1597 		/* enable word swap */
1598 		if (sfb->fb->var.bits_per_pixel == 32)
1599 			seqw17();
1600 		break;
1601 	case 0x720:
1602 		sfb->fb->fix.mmio_start = mmio_base;
1603 		sfb->fb->fix.mmio_len = 0x00200000;
1604 		sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
1605 		sfb->lfb = sfb->dp_regs + 0x00200000;
1606 		sfb->mmio = (smtc_regbaseaddress =
1607 		    sfb->dp_regs + 0x000c0000);
1608 		sfb->vp_regs = sfb->dp_regs + 0x800;
1609 
1610 		smtc_seqw(0x62, 0xff);
1611 		smtc_seqw(0x6a, 0x0d);
1612 		smtc_seqw(0x6b, 0x02);
1613 		break;
1614 	default:
1615 		dev_err(&pdev->dev,
1616 			"No valid Silicon Motion display chip was detected!\n");
1617 
1618 		goto failed_fb;
1619 	}
1620 
1621 	/* probe and decide resolution */
1622 	sm7xx_resolution_probe(sfb);
1623 
1624 	/* can support 32 bpp */
1625 	if (sfb->fb->var.bits_per_pixel == 15)
1626 		sfb->fb->var.bits_per_pixel = 16;
1627 
1628 	sfb->fb->var.xres_virtual = sfb->fb->var.xres;
1629 	sfb->fb->var.yres_virtual = sfb->fb->var.yres;
1630 	err = smtc_map_smem(sfb, pdev, smem_size);
1631 	if (err)
1632 		goto failed;
1633 
1634 	/*
1635 	 * The screen would be temporarily garbled when sm712fb takes over
1636 	 * vesafb or VGA text mode. Zero the framebuffer.
1637 	 */
1638 	memset_io(sfb->lfb, 0, sfb->fb->fix.smem_len);
1639 
1640 	err = register_framebuffer(info);
1641 	if (err < 0)
1642 		goto failed;
1643 
1644 	dev_info(&pdev->dev,
1645 		 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n",
1646 		 sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
1647 		 sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
1648 
1649 	return 0;
1650 
1651 failed:
1652 	dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n");
1653 
1654 	smtc_unmap_smem(sfb);
1655 	smtc_unmap_mmio(sfb);
1656 failed_fb:
1657 	framebuffer_release(info);
1658 
1659 failed_free:
1660 	pci_release_region(pdev, 0);
1661 
1662 failed_regions:
1663 	pci_disable_device(pdev);
1664 
1665 	return err;
1666 }
1667 
1668 /*
1669  * 0x710 (LynxEM)
1670  * 0x712 (LynxEM+)
1671  * 0x720 (Lynx3DM, Lynx3DM+)
1672  */
1673 static const struct pci_device_id smtcfb_pci_table[] = {
1674 	{ PCI_DEVICE(0x126f, 0x710), },
1675 	{ PCI_DEVICE(0x126f, 0x712), },
1676 	{ PCI_DEVICE(0x126f, 0x720), },
1677 	{0,}
1678 };
1679 
1680 MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
1681 
1682 static void smtcfb_pci_remove(struct pci_dev *pdev)
1683 {
1684 	struct smtcfb_info *sfb;
1685 
1686 	sfb = pci_get_drvdata(pdev);
1687 	smtc_unmap_smem(sfb);
1688 	smtc_unmap_mmio(sfb);
1689 	unregister_framebuffer(sfb->fb);
1690 	framebuffer_release(sfb->fb);
1691 	pci_release_region(pdev, 0);
1692 	pci_disable_device(pdev);
1693 }
1694 
1695 static int __maybe_unused smtcfb_pci_suspend(struct device *device)
1696 {
1697 	struct pci_dev *pdev = to_pci_dev(device);
1698 	struct smtcfb_info *sfb;
1699 
1700 	sfb = pci_get_drvdata(pdev);
1701 
1702 	/* set the hw in sleep mode use external clock and self memory refresh
1703 	 * so that we can turn off internal PLLs later on
1704 	 */
1705 	smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1706 	smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1707 
1708 	console_lock();
1709 	fb_set_suspend(sfb->fb, 1);
1710 	console_unlock();
1711 
1712 	/* additionally turn off all function blocks including internal PLLs */
1713 	smtc_seqw(0x21, 0xff);
1714 
1715 	return 0;
1716 }
1717 
1718 static int __maybe_unused smtcfb_pci_resume(struct device *device)
1719 {
1720 	struct pci_dev *pdev = to_pci_dev(device);
1721 	struct smtcfb_info *sfb;
1722 
1723 	sfb = pci_get_drvdata(pdev);
1724 
1725 	/* reinit hardware */
1726 	sm7xx_init_hw();
1727 	switch (sfb->chip_id) {
1728 	case 0x710:
1729 	case 0x712:
1730 		/* set MCLK = 14.31818 *  (0x16 / 0x2) */
1731 		smtc_seqw(0x6a, 0x16);
1732 		smtc_seqw(0x6b, 0x02);
1733 		smtc_seqw(0x62, 0x3e);
1734 		/* enable PCI burst */
1735 		smtc_seqw(0x17, 0x20);
1736 		if (sfb->fb->var.bits_per_pixel == 32)
1737 			seqw17();
1738 		break;
1739 	case 0x720:
1740 		smtc_seqw(0x62, 0xff);
1741 		smtc_seqw(0x6a, 0x0d);
1742 		smtc_seqw(0x6b, 0x02);
1743 		break;
1744 	}
1745 
1746 	smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1747 	smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1748 
1749 	smtcfb_setmode(sfb);
1750 
1751 	console_lock();
1752 	fb_set_suspend(sfb->fb, 0);
1753 	console_unlock();
1754 
1755 	return 0;
1756 }
1757 
1758 static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1759 
1760 static struct pci_driver smtcfb_driver = {
1761 	.name = "smtcfb",
1762 	.id_table = smtcfb_pci_table,
1763 	.probe = smtcfb_pci_probe,
1764 	.remove = smtcfb_pci_remove,
1765 	.driver.pm  = &sm7xx_pm_ops,
1766 };
1767 
1768 static int __init sm712fb_init(void)
1769 {
1770 	char *option = NULL;
1771 
1772 	if (fb_get_options("sm712fb", &option))
1773 		return -ENODEV;
1774 	if (option && *option)
1775 		mode_option = option;
1776 	sm7xx_vga_setup(mode_option);
1777 
1778 	return pci_register_driver(&smtcfb_driver);
1779 }
1780 
1781 module_init(sm712fb_init);
1782 
1783 static void __exit sm712fb_exit(void)
1784 {
1785 	pci_unregister_driver(&smtcfb_driver);
1786 }
1787 
1788 module_exit(sm712fb_exit);
1789 
1790 MODULE_AUTHOR("Siliconmotion ");
1791 MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1792 MODULE_LICENSE("GPL");
1793