xref: /openbmc/linux/drivers/video/fbdev/sm712fb.c (revision 173940b3)
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(PAGE_SIZE, 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 + 3) >> 2; i--;) {
1063 			u32 val;
1064 
1065 			val = fb_readl(src);
1066 			*dst = big_swap(val);
1067 			src++;
1068 			dst++;
1069 		}
1070 
1071 		if (copy_to_user(buf, buffer, c)) {
1072 			err = -EFAULT;
1073 			break;
1074 		}
1075 		*ppos += c;
1076 		buf += c;
1077 		cnt += c;
1078 		count -= c;
1079 	}
1080 
1081 	kfree(buffer);
1082 
1083 	return (err) ? err : cnt;
1084 }
1085 
1086 static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
1087 			    size_t count, loff_t *ppos)
1088 {
1089 	unsigned long p = *ppos;
1090 
1091 	u32 *buffer, *src;
1092 	u32 __iomem *dst;
1093 	int c, i, cnt = 0, err = 0;
1094 	unsigned long total_size;
1095 
1096 	if (!info || !info->screen_base)
1097 		return -ENODEV;
1098 
1099 	if (info->state != FBINFO_STATE_RUNNING)
1100 		return -EPERM;
1101 
1102 	total_size = info->screen_size;
1103 
1104 	if (total_size == 0)
1105 		total_size = info->fix.smem_len;
1106 
1107 	if (p > total_size)
1108 		return -EFBIG;
1109 
1110 	if (count > total_size) {
1111 		err = -EFBIG;
1112 		count = total_size;
1113 	}
1114 
1115 	if (count + p > total_size) {
1116 		if (!err)
1117 			err = -ENOSPC;
1118 
1119 		count = total_size - p;
1120 	}
1121 
1122 	buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
1123 	if (!buffer)
1124 		return -ENOMEM;
1125 
1126 	dst = (u32 __iomem *)(info->screen_base + p);
1127 
1128 	if (info->fbops->fb_sync)
1129 		info->fbops->fb_sync(info);
1130 
1131 	while (count) {
1132 		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1133 		src = buffer;
1134 
1135 		if (copy_from_user(src, buf, c)) {
1136 			err = -EFAULT;
1137 			break;
1138 		}
1139 
1140 		for (i = (c + 3) >> 2; i--;) {
1141 			fb_writel(big_swap(*src), dst);
1142 			dst++;
1143 			src++;
1144 		}
1145 
1146 		*ppos += c;
1147 		buf += c;
1148 		cnt += c;
1149 		count -= c;
1150 	}
1151 
1152 	kfree(buffer);
1153 
1154 	return (cnt) ? cnt : err;
1155 }
1156 
1157 static void sm7xx_set_timing(struct smtcfb_info *sfb)
1158 {
1159 	int i = 0, j = 0;
1160 	u32 m_nscreenstride;
1161 
1162 	dev_dbg(&sfb->pdev->dev,
1163 		"sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n",
1164 		sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz);
1165 
1166 	for (j = 0; j < ARRAY_SIZE(vgamode); j++) {
1167 		if (vgamode[j].mmsizex != sfb->width ||
1168 		    vgamode[j].mmsizey != sfb->height ||
1169 		    vgamode[j].bpp != sfb->fb->var.bits_per_pixel ||
1170 		    vgamode[j].hz != sfb->hz)
1171 			continue;
1172 
1173 		dev_dbg(&sfb->pdev->dev,
1174 			"vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
1175 			vgamode[j].mmsizex, vgamode[j].mmsizey,
1176 			vgamode[j].bpp, vgamode[j].hz);
1177 
1178 		dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
1179 
1180 		smtc_mmiowb(0x0, 0x3c6);
1181 
1182 		smtc_seqw(0, 0x1);
1183 
1184 		smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
1185 
1186 		/* init SEQ register SR00 - SR04 */
1187 		for (i = 0; i < SIZE_SR00_SR04; i++)
1188 			smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
1189 
1190 		/* init SEQ register SR10 - SR24 */
1191 		for (i = 0; i < SIZE_SR10_SR24; i++)
1192 			smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]);
1193 
1194 		/* init SEQ register SR30 - SR75 */
1195 		for (i = 0; i < SIZE_SR30_SR75; i++)
1196 			if ((i + 0x30) != 0x30 && (i + 0x30) != 0x62 &&
1197 			    (i + 0x30) != 0x6a && (i + 0x30) != 0x6b &&
1198 			    (i + 0x30) != 0x70 && (i + 0x30) != 0x71 &&
1199 			    (i + 0x30) != 0x74 && (i + 0x30) != 0x75)
1200 				smtc_seqw(i + 0x30,
1201 					  vgamode[j].init_sr30_sr75[i]);
1202 
1203 		/* init SEQ register SR80 - SR93 */
1204 		for (i = 0; i < SIZE_SR80_SR93; i++)
1205 			smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]);
1206 
1207 		/* init SEQ register SRA0 - SRAF */
1208 		for (i = 0; i < SIZE_SRA0_SRAF; i++)
1209 			smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]);
1210 
1211 		/* init Graphic register GR00 - GR08 */
1212 		for (i = 0; i < SIZE_GR00_GR08; i++)
1213 			smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
1214 
1215 		/* init Attribute register AR00 - AR14 */
1216 		for (i = 0; i < SIZE_AR00_AR14; i++)
1217 			smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
1218 
1219 		/* init CRTC register CR00 - CR18 */
1220 		for (i = 0; i < SIZE_CR00_CR18; i++)
1221 			smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
1222 
1223 		/* init CRTC register CR30 - CR4D */
1224 		for (i = 0; i < SIZE_CR30_CR4D; i++) {
1225 			if ((i + 0x30) >= 0x3B && (i + 0x30) <= 0x3F)
1226 				/* side-effect, don't write to CR3B-CR3F */
1227 				continue;
1228 			smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
1229 		}
1230 
1231 		/* init CRTC register CR90 - CRA7 */
1232 		for (i = 0; i < SIZE_CR90_CRA7; i++)
1233 			smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]);
1234 	}
1235 	smtc_mmiowb(0x67, 0x3c2);
1236 
1237 	/* set VPR registers */
1238 	writel(0x0, sfb->vp_regs + 0x0C);
1239 	writel(0x0, sfb->vp_regs + 0x40);
1240 
1241 	/* set data width */
1242 	m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64;
1243 	switch (sfb->fb->var.bits_per_pixel) {
1244 	case 8:
1245 		writel(0x0, sfb->vp_regs + 0x0);
1246 		break;
1247 	case 16:
1248 		writel(0x00020000, sfb->vp_regs + 0x0);
1249 		break;
1250 	case 24:
1251 		writel(0x00040000, sfb->vp_regs + 0x0);
1252 		break;
1253 	case 32:
1254 		writel(0x00030000, sfb->vp_regs + 0x0);
1255 		break;
1256 	}
1257 	writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride),
1258 	       sfb->vp_regs + 0x10);
1259 }
1260 
1261 static void smtc_set_timing(struct smtcfb_info *sfb)
1262 {
1263 	switch (sfb->chip_id) {
1264 	case 0x710:
1265 	case 0x712:
1266 	case 0x720:
1267 		sm7xx_set_timing(sfb);
1268 		break;
1269 	}
1270 }
1271 
1272 static void smtcfb_setmode(struct smtcfb_info *sfb)
1273 {
1274 	switch (sfb->fb->var.bits_per_pixel) {
1275 	case 32:
1276 		sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1277 		sfb->fb->fix.line_length  = sfb->fb->var.xres * 4;
1278 		sfb->fb->var.red.length   = 8;
1279 		sfb->fb->var.green.length = 8;
1280 		sfb->fb->var.blue.length  = 8;
1281 		sfb->fb->var.red.offset   = 16;
1282 		sfb->fb->var.green.offset = 8;
1283 		sfb->fb->var.blue.offset  = 0;
1284 		break;
1285 	case 24:
1286 		sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1287 		sfb->fb->fix.line_length  = sfb->fb->var.xres * 3;
1288 		sfb->fb->var.red.length   = 8;
1289 		sfb->fb->var.green.length = 8;
1290 		sfb->fb->var.blue.length  = 8;
1291 		sfb->fb->var.red.offset   = 16;
1292 		sfb->fb->var.green.offset = 8;
1293 		sfb->fb->var.blue.offset  = 0;
1294 		break;
1295 	case 8:
1296 		sfb->fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
1297 		sfb->fb->fix.line_length  = sfb->fb->var.xres;
1298 		sfb->fb->var.red.length   = 3;
1299 		sfb->fb->var.green.length = 3;
1300 		sfb->fb->var.blue.length  = 2;
1301 		sfb->fb->var.red.offset   = 5;
1302 		sfb->fb->var.green.offset = 2;
1303 		sfb->fb->var.blue.offset  = 0;
1304 		break;
1305 	case 16:
1306 	default:
1307 		sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1308 		sfb->fb->fix.line_length  = sfb->fb->var.xres * 2;
1309 		sfb->fb->var.red.length   = 5;
1310 		sfb->fb->var.green.length = 6;
1311 		sfb->fb->var.blue.length  = 5;
1312 		sfb->fb->var.red.offset   = 11;
1313 		sfb->fb->var.green.offset = 5;
1314 		sfb->fb->var.blue.offset  = 0;
1315 		break;
1316 	}
1317 
1318 	sfb->width  = sfb->fb->var.xres;
1319 	sfb->height = sfb->fb->var.yres;
1320 	sfb->hz = 60;
1321 	smtc_set_timing(sfb);
1322 }
1323 
1324 static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1325 {
1326 	/* sanity checks */
1327 	if (var->xres_virtual < var->xres)
1328 		var->xres_virtual = var->xres;
1329 
1330 	if (var->yres_virtual < var->yres)
1331 		var->yres_virtual = var->yres;
1332 
1333 	/* set valid default bpp */
1334 	if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
1335 	    (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
1336 		var->bits_per_pixel = 16;
1337 
1338 	return 0;
1339 }
1340 
1341 static int smtc_set_par(struct fb_info *info)
1342 {
1343 	smtcfb_setmode(info->par);
1344 
1345 	return 0;
1346 }
1347 
1348 static const struct fb_ops smtcfb_ops = {
1349 	.owner        = THIS_MODULE,
1350 	.fb_check_var = smtc_check_var,
1351 	.fb_set_par   = smtc_set_par,
1352 	.fb_setcolreg = smtc_setcolreg,
1353 	.fb_blank     = smtc_blank,
1354 	.fb_fillrect  = cfb_fillrect,
1355 	.fb_imageblit = cfb_imageblit,
1356 	.fb_copyarea  = cfb_copyarea,
1357 	.fb_read      = smtcfb_read,
1358 	.fb_write     = smtcfb_write,
1359 };
1360 
1361 /*
1362  * Unmap in the memory mapped IO registers
1363  */
1364 
1365 static void smtc_unmap_mmio(struct smtcfb_info *sfb)
1366 {
1367 	if (sfb && smtc_regbaseaddress)
1368 		smtc_regbaseaddress = NULL;
1369 }
1370 
1371 /*
1372  * Map in the screen memory
1373  */
1374 
1375 static int smtc_map_smem(struct smtcfb_info *sfb,
1376 			 struct pci_dev *pdev, u_long smem_len)
1377 {
1378 	sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
1379 
1380 	if (sfb->chip_id == 0x720)
1381 		/* on SM720, the framebuffer starts at the 1 MB offset */
1382 		sfb->fb->fix.smem_start += 0x00200000;
1383 
1384 	/* XXX: is it safe for SM720 on Big-Endian? */
1385 	if (sfb->fb->var.bits_per_pixel == 32)
1386 		sfb->fb->fix.smem_start += big_addr;
1387 
1388 	sfb->fb->fix.smem_len = smem_len;
1389 
1390 	sfb->fb->screen_base = sfb->lfb;
1391 
1392 	if (!sfb->fb->screen_base) {
1393 		dev_err(&pdev->dev,
1394 			"%s: unable to map screen memory\n", sfb->fb->fix.id);
1395 		return -ENOMEM;
1396 	}
1397 
1398 	return 0;
1399 }
1400 
1401 /*
1402  * Unmap in the screen memory
1403  *
1404  */
1405 static void smtc_unmap_smem(struct smtcfb_info *sfb)
1406 {
1407 	if (sfb && sfb->fb->screen_base) {
1408 		if (sfb->chip_id == 0x720)
1409 			sfb->fb->screen_base -= 0x00200000;
1410 		iounmap(sfb->fb->screen_base);
1411 		sfb->fb->screen_base = NULL;
1412 	}
1413 }
1414 
1415 /*
1416  * We need to wake up the device and make sure its in linear memory mode.
1417  */
1418 static inline void sm7xx_init_hw(void)
1419 {
1420 	outb_p(0x18, 0x3c4);
1421 	outb_p(0x11, 0x3c5);
1422 }
1423 
1424 static u_long sm7xx_vram_probe(struct smtcfb_info *sfb)
1425 {
1426 	u8 vram;
1427 
1428 	switch (sfb->chip_id) {
1429 	case 0x710:
1430 	case 0x712:
1431 		/*
1432 		 * Assume SM712 graphics chip has 4MB VRAM.
1433 		 *
1434 		 * FIXME: SM712 can have 2MB VRAM, which is used on earlier
1435 		 * laptops, such as IBM Thinkpad 240X. This driver would
1436 		 * probably crash on those machines. If anyone gets one of
1437 		 * those and is willing to help, run "git blame" and send me
1438 		 * an E-mail.
1439 		 */
1440 		return 0x00400000;
1441 	case 0x720:
1442 		outb_p(0x76, 0x3c4);
1443 		vram = inb_p(0x3c5) >> 6;
1444 
1445 		if (vram == 0x00)
1446 			return 0x00800000;  /* 8 MB */
1447 		else if (vram == 0x01)
1448 			return 0x01000000;  /* 16 MB */
1449 		else if (vram == 0x02)
1450 			return 0x00400000;  /* illegal, fallback to 4 MB */
1451 		else if (vram == 0x03)
1452 			return 0x00400000;  /* 4 MB */
1453 	}
1454 	return 0;  /* unknown hardware */
1455 }
1456 
1457 static void sm7xx_resolution_probe(struct smtcfb_info *sfb)
1458 {
1459 	/* get mode parameter from smtc_scr_info */
1460 	if (smtc_scr_info.lfb_width != 0) {
1461 		sfb->fb->var.xres = smtc_scr_info.lfb_width;
1462 		sfb->fb->var.yres = smtc_scr_info.lfb_height;
1463 		sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
1464 		goto final;
1465 	}
1466 
1467 	/*
1468 	 * No parameter, default resolution is 1024x768-16.
1469 	 *
1470 	 * FIXME: earlier laptops, such as IBM Thinkpad 240X, has a 800x600
1471 	 * panel, also see the comments about Thinkpad 240X above.
1472 	 */
1473 	sfb->fb->var.xres = SCREEN_X_RES;
1474 	sfb->fb->var.yres = SCREEN_Y_RES_PC;
1475 	sfb->fb->var.bits_per_pixel = SCREEN_BPP;
1476 
1477 #ifdef CONFIG_MIPS
1478 	/*
1479 	 * Loongson MIPS netbooks use 1024x600 LCD panels, which is the original
1480 	 * target platform of this driver, but nearly all old x86 laptops have
1481 	 * 1024x768. Lighting 768 panels using 600's timings would partially
1482 	 * garble the display, so we don't want that. But it's not possible to
1483 	 * distinguish them reliably.
1484 	 *
1485 	 * So we change the default to 768, but keep 600 as-is on MIPS.
1486 	 */
1487 	sfb->fb->var.yres = SCREEN_Y_RES_NETBOOK;
1488 #endif
1489 
1490 final:
1491 	big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
1492 }
1493 
1494 static int smtcfb_pci_probe(struct pci_dev *pdev,
1495 			    const struct pci_device_id *ent)
1496 {
1497 	struct smtcfb_info *sfb;
1498 	struct fb_info *info;
1499 	u_long smem_size;
1500 	int err;
1501 	unsigned long mmio_base;
1502 
1503 	dev_info(&pdev->dev, "Silicon Motion display driver.\n");
1504 
1505 	err = pci_enable_device(pdev);	/* enable SMTC chip */
1506 	if (err)
1507 		return err;
1508 
1509 	err = pci_request_region(pdev, 0, "sm7xxfb");
1510 	if (err < 0) {
1511 		dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
1512 		goto failed_regions;
1513 	}
1514 
1515 	sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
1516 
1517 	info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
1518 	if (!info) {
1519 		err = -ENOMEM;
1520 		goto failed_free;
1521 	}
1522 
1523 	sfb = info->par;
1524 	sfb->fb = info;
1525 	sfb->chip_id = ent->device;
1526 	sfb->pdev = pdev;
1527 	info->flags = FBINFO_FLAG_DEFAULT;
1528 	info->fbops = &smtcfb_ops;
1529 	info->fix = smtcfb_fix;
1530 	info->var = smtcfb_var;
1531 	info->pseudo_palette = sfb->colreg;
1532 	info->par = sfb;
1533 
1534 	pci_set_drvdata(pdev, sfb);
1535 
1536 	sm7xx_init_hw();
1537 
1538 	/* Map address and memory detection */
1539 	mmio_base = pci_resource_start(pdev, 0);
1540 	pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
1541 
1542 	smem_size = sm7xx_vram_probe(sfb);
1543 	dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n",
1544 					smem_size / 1048576);
1545 
1546 	switch (sfb->chip_id) {
1547 	case 0x710:
1548 	case 0x712:
1549 		sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
1550 		sfb->fb->fix.mmio_len = 0x00400000;
1551 		sfb->lfb = ioremap(mmio_base, mmio_addr);
1552 		if (!sfb->lfb) {
1553 			dev_err(&pdev->dev,
1554 				"%s: unable to map memory mapped IO!\n",
1555 				sfb->fb->fix.id);
1556 			err = -ENOMEM;
1557 			goto failed_fb;
1558 		}
1559 
1560 		sfb->mmio = (smtc_regbaseaddress =
1561 		    sfb->lfb + 0x00700000);
1562 		sfb->dp_regs = sfb->lfb + 0x00408000;
1563 		sfb->vp_regs = sfb->lfb + 0x0040c000;
1564 		if (sfb->fb->var.bits_per_pixel == 32) {
1565 			sfb->lfb += big_addr;
1566 			dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
1567 		}
1568 
1569 		/* set MCLK = 14.31818 * (0x16 / 0x2) */
1570 		smtc_seqw(0x6a, 0x16);
1571 		smtc_seqw(0x6b, 0x02);
1572 		smtc_seqw(0x62, 0x3e);
1573 		/* enable PCI burst */
1574 		smtc_seqw(0x17, 0x20);
1575 		/* enable word swap */
1576 		if (sfb->fb->var.bits_per_pixel == 32)
1577 			seqw17();
1578 		break;
1579 	case 0x720:
1580 		sfb->fb->fix.mmio_start = mmio_base;
1581 		sfb->fb->fix.mmio_len = 0x00200000;
1582 		sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
1583 		if (!sfb->dp_regs) {
1584 			dev_err(&pdev->dev,
1585 				"%s: unable to map memory mapped IO!\n",
1586 				sfb->fb->fix.id);
1587 			err = -ENOMEM;
1588 			goto failed_fb;
1589 		}
1590 
1591 		sfb->lfb = sfb->dp_regs + 0x00200000;
1592 		sfb->mmio = (smtc_regbaseaddress =
1593 		    sfb->dp_regs + 0x000c0000);
1594 		sfb->vp_regs = sfb->dp_regs + 0x800;
1595 
1596 		smtc_seqw(0x62, 0xff);
1597 		smtc_seqw(0x6a, 0x0d);
1598 		smtc_seqw(0x6b, 0x02);
1599 		break;
1600 	default:
1601 		dev_err(&pdev->dev,
1602 			"No valid Silicon Motion display chip was detected!\n");
1603 		err = -ENODEV;
1604 		goto failed_fb;
1605 	}
1606 
1607 	/* probe and decide resolution */
1608 	sm7xx_resolution_probe(sfb);
1609 
1610 	/* can support 32 bpp */
1611 	if (sfb->fb->var.bits_per_pixel == 15)
1612 		sfb->fb->var.bits_per_pixel = 16;
1613 
1614 	sfb->fb->var.xres_virtual = sfb->fb->var.xres;
1615 	sfb->fb->var.yres_virtual = sfb->fb->var.yres;
1616 	err = smtc_map_smem(sfb, pdev, smem_size);
1617 	if (err)
1618 		goto failed;
1619 
1620 	/*
1621 	 * The screen would be temporarily garbled when sm712fb takes over
1622 	 * vesafb or VGA text mode. Zero the framebuffer.
1623 	 */
1624 	memset_io(sfb->lfb, 0, sfb->fb->fix.smem_len);
1625 
1626 	err = register_framebuffer(info);
1627 	if (err < 0)
1628 		goto failed;
1629 
1630 	dev_info(&pdev->dev,
1631 		 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n",
1632 		 sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
1633 		 sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
1634 
1635 	return 0;
1636 
1637 failed:
1638 	dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n");
1639 
1640 	smtc_unmap_smem(sfb);
1641 	smtc_unmap_mmio(sfb);
1642 failed_fb:
1643 	framebuffer_release(info);
1644 
1645 failed_free:
1646 	pci_release_region(pdev, 0);
1647 
1648 failed_regions:
1649 	pci_disable_device(pdev);
1650 
1651 	return err;
1652 }
1653 
1654 /*
1655  * 0x710 (LynxEM)
1656  * 0x712 (LynxEM+)
1657  * 0x720 (Lynx3DM, Lynx3DM+)
1658  */
1659 static const struct pci_device_id smtcfb_pci_table[] = {
1660 	{ PCI_DEVICE(0x126f, 0x710), },
1661 	{ PCI_DEVICE(0x126f, 0x712), },
1662 	{ PCI_DEVICE(0x126f, 0x720), },
1663 	{0,}
1664 };
1665 
1666 MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
1667 
1668 static void smtcfb_pci_remove(struct pci_dev *pdev)
1669 {
1670 	struct smtcfb_info *sfb;
1671 
1672 	sfb = pci_get_drvdata(pdev);
1673 	smtc_unmap_smem(sfb);
1674 	smtc_unmap_mmio(sfb);
1675 	unregister_framebuffer(sfb->fb);
1676 	framebuffer_release(sfb->fb);
1677 	pci_release_region(pdev, 0);
1678 	pci_disable_device(pdev);
1679 }
1680 
1681 static int __maybe_unused smtcfb_pci_suspend(struct device *device)
1682 {
1683 	struct smtcfb_info *sfb = dev_get_drvdata(device);
1684 
1685 
1686 	/* set the hw in sleep mode use external clock and self memory refresh
1687 	 * so that we can turn off internal PLLs later on
1688 	 */
1689 	smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1690 	smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1691 
1692 	console_lock();
1693 	fb_set_suspend(sfb->fb, 1);
1694 	console_unlock();
1695 
1696 	/* additionally turn off all function blocks including internal PLLs */
1697 	smtc_seqw(0x21, 0xff);
1698 
1699 	return 0;
1700 }
1701 
1702 static int __maybe_unused smtcfb_pci_resume(struct device *device)
1703 {
1704 	struct smtcfb_info *sfb = dev_get_drvdata(device);
1705 
1706 
1707 	/* reinit hardware */
1708 	sm7xx_init_hw();
1709 	switch (sfb->chip_id) {
1710 	case 0x710:
1711 	case 0x712:
1712 		/* set MCLK = 14.31818 *  (0x16 / 0x2) */
1713 		smtc_seqw(0x6a, 0x16);
1714 		smtc_seqw(0x6b, 0x02);
1715 		smtc_seqw(0x62, 0x3e);
1716 		/* enable PCI burst */
1717 		smtc_seqw(0x17, 0x20);
1718 		if (sfb->fb->var.bits_per_pixel == 32)
1719 			seqw17();
1720 		break;
1721 	case 0x720:
1722 		smtc_seqw(0x62, 0xff);
1723 		smtc_seqw(0x6a, 0x0d);
1724 		smtc_seqw(0x6b, 0x02);
1725 		break;
1726 	}
1727 
1728 	smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1729 	smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1730 
1731 	smtcfb_setmode(sfb);
1732 
1733 	console_lock();
1734 	fb_set_suspend(sfb->fb, 0);
1735 	console_unlock();
1736 
1737 	return 0;
1738 }
1739 
1740 static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1741 
1742 static struct pci_driver smtcfb_driver = {
1743 	.name = "smtcfb",
1744 	.id_table = smtcfb_pci_table,
1745 	.probe = smtcfb_pci_probe,
1746 	.remove = smtcfb_pci_remove,
1747 	.driver.pm  = &sm7xx_pm_ops,
1748 };
1749 
1750 static int __init sm712fb_init(void)
1751 {
1752 	char *option = NULL;
1753 
1754 	if (fb_get_options("sm712fb", &option))
1755 		return -ENODEV;
1756 	if (option && *option)
1757 		mode_option = option;
1758 	sm7xx_vga_setup(mode_option);
1759 
1760 	return pci_register_driver(&smtcfb_driver);
1761 }
1762 
1763 module_init(sm712fb_init);
1764 
1765 static void __exit sm712fb_exit(void)
1766 {
1767 	pci_unregister_driver(&smtcfb_driver);
1768 }
1769 
1770 module_exit(sm712fb_exit);
1771 
1772 MODULE_AUTHOR("Siliconmotion ");
1773 MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1774 MODULE_LICENSE("GPL");
1775