xref: /openbmc/linux/drivers/video/fbdev/sm712fb.c (revision 791d3ef2)
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 	{	/*  mode#5: 1024 x 768  24Bpp  60Hz */
534 		1024, 768, 24, 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 			0x00, 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#4: 1024 x 768  32Bpp  60Hz */
593 		1024, 768, 32, 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, 0x32, 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#6: 320 x 240  16Bpp  60Hz */
652 		320, 240, 16, 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, 0x08, 0x43, 0x08, 0x43,
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, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
701 			0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
702 			0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
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 
711 	{	/*  mode#8: 320 x 240  32Bpp  60Hz */
712 		320, 240, 32, 60,
713 		/*  Init_MISC */
714 		0xEB,
715 		{	/*  Init_SR0_SR4 */
716 			0x03, 0x01, 0x0F, 0x03, 0x0E,
717 		},
718 		{	/*  Init_SR10_SR24 */
719 			0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
720 			0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
721 			0xC4, 0x32, 0x02, 0x01, 0x01,
722 		},
723 		{	/*  Init_SR30_SR75 */
724 			0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
725 			0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
726 			0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
727 			0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
728 			0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
729 			0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
730 			0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
731 			0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
732 			0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
733 		},
734 		{	/*  Init_SR80_SR93 */
735 			0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
736 			0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
737 			0x00, 0x00, 0x00, 0x00,
738 		},
739 		{	/*  Init_SRA0_SRAF */
740 			0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
741 			0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
742 		},
743 		{	/*  Init_GR00_GR08 */
744 			0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
745 			0xFF,
746 		},
747 		{	/*  Init_AR00_AR14 */
748 			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
749 			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
750 			0x41, 0x00, 0x0F, 0x00, 0x00,
751 		},
752 		{	/*  Init_CR00_CR18 */
753 			0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
754 			0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
755 			0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
756 			0xFF,
757 		},
758 		{	/*  Init_CR30_CR4D */
759 			0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
760 			0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
761 			0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
762 			0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
763 		},
764 		{	/*  Init_CR90_CRA7 */
765 			0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
766 			0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
767 			0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
768 		},
769 	},
770 };
771 
772 static struct screen_info smtc_scr_info;
773 
774 static char *mode_option;
775 
776 /* process command line options, get vga parameter */
777 static void __init sm7xx_vga_setup(char *options)
778 {
779 	int i;
780 
781 	if (!options || !*options)
782 		return;
783 
784 	smtc_scr_info.lfb_width = 0;
785 	smtc_scr_info.lfb_height = 0;
786 	smtc_scr_info.lfb_depth = 0;
787 
788 	pr_debug("%s = %s\n", __func__, options);
789 
790 	for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
791 		if (strstr(options, vesa_mode_table[i].index)) {
792 			smtc_scr_info.lfb_width  = vesa_mode_table[i].lfb_width;
793 			smtc_scr_info.lfb_height =
794 						vesa_mode_table[i].lfb_height;
795 			smtc_scr_info.lfb_depth  = vesa_mode_table[i].lfb_depth;
796 			return;
797 		}
798 	}
799 }
800 
801 static void sm712_setpalette(int regno, unsigned int red, unsigned int green,
802 			     unsigned int blue, struct fb_info *info)
803 {
804 	/* set bit 5:4 = 01 (write LCD RAM only) */
805 	smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
806 
807 	smtc_mmiowb(regno, dac_reg);
808 	smtc_mmiowb(red >> 10, dac_val);
809 	smtc_mmiowb(green >> 10, dac_val);
810 	smtc_mmiowb(blue >> 10, dac_val);
811 }
812 
813 /* chan_to_field
814  *
815  * convert a colour value into a field position
816  *
817  * from pxafb.c
818  */
819 
820 static inline unsigned int chan_to_field(unsigned int chan,
821 					 struct fb_bitfield *bf)
822 {
823 	chan &= 0xffff;
824 	chan >>= 16 - bf->length;
825 	return chan << bf->offset;
826 }
827 
828 static int smtc_blank(int blank_mode, struct fb_info *info)
829 {
830 	/* clear DPMS setting */
831 	switch (blank_mode) {
832 	case FB_BLANK_UNBLANK:
833 		/* Screen On: HSync: On, VSync : On */
834 		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
835 		smtc_seqw(0x6a, 0x16);
836 		smtc_seqw(0x6b, 0x02);
837 		smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
838 		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
839 		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
840 		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
841 		smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
842 		break;
843 	case FB_BLANK_NORMAL:
844 		/* Screen Off: HSync: On, VSync : On   Soft blank */
845 		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
846 		smtc_seqw(0x6a, 0x16);
847 		smtc_seqw(0x6b, 0x02);
848 		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
849 		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
850 		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
851 		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
852 		break;
853 	case FB_BLANK_VSYNC_SUSPEND:
854 		/* Screen On: HSync: On, VSync : Off */
855 		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
856 		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
857 		smtc_seqw(0x6a, 0x0c);
858 		smtc_seqw(0x6b, 0x02);
859 		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
860 		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
861 		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
862 		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
863 		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
864 		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
865 		break;
866 	case FB_BLANK_HSYNC_SUSPEND:
867 		/* Screen On: HSync: Off, VSync : On */
868 		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
869 		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
870 		smtc_seqw(0x6a, 0x0c);
871 		smtc_seqw(0x6b, 0x02);
872 		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
873 		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
874 		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
875 		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
876 		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
877 		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
878 		break;
879 	case FB_BLANK_POWERDOWN:
880 		/* Screen On: HSync: Off, VSync : Off */
881 		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
882 		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
883 		smtc_seqw(0x6a, 0x0c);
884 		smtc_seqw(0x6b, 0x02);
885 		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
886 		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
887 		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
888 		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
889 		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
890 		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
891 		break;
892 	default:
893 		return -EINVAL;
894 	}
895 
896 	return 0;
897 }
898 
899 static int smtc_setcolreg(unsigned int regno, unsigned int red,
900 			  unsigned int green, unsigned int blue,
901 			  unsigned int trans, struct fb_info *info)
902 {
903 	struct smtcfb_info *sfb;
904 	u32 val;
905 
906 	sfb = info->par;
907 
908 	if (regno > 255)
909 		return 1;
910 
911 	switch (sfb->fb->fix.visual) {
912 	case FB_VISUAL_DIRECTCOLOR:
913 	case FB_VISUAL_TRUECOLOR:
914 		/*
915 		 * 16/32 bit true-colour, use pseudo-palette for 16 base color
916 		 */
917 		if (regno >= 16)
918 			break;
919 		if (sfb->fb->var.bits_per_pixel == 16) {
920 			u32 *pal = sfb->fb->pseudo_palette;
921 
922 			val = chan_to_field(red, &sfb->fb->var.red);
923 			val |= chan_to_field(green, &sfb->fb->var.green);
924 			val |= chan_to_field(blue, &sfb->fb->var.blue);
925 			pal[regno] = pal_rgb(red, green, blue, val);
926 		} else {
927 			u32 *pal = sfb->fb->pseudo_palette;
928 
929 			val = chan_to_field(red, &sfb->fb->var.red);
930 			val |= chan_to_field(green, &sfb->fb->var.green);
931 			val |= chan_to_field(blue, &sfb->fb->var.blue);
932 			pal[regno] = big_swap(val);
933 		}
934 		break;
935 
936 	case FB_VISUAL_PSEUDOCOLOR:
937 		/* color depth 8 bit */
938 		sm712_setpalette(regno, red, green, blue, info);
939 		break;
940 
941 	default:
942 		return 1;	/* unknown type */
943 	}
944 
945 	return 0;
946 }
947 
948 static ssize_t smtcfb_read(struct fb_info *info, char __user *buf,
949 			   size_t count, loff_t *ppos)
950 {
951 	unsigned long p = *ppos;
952 
953 	u32 *buffer, *dst;
954 	u32 __iomem *src;
955 	int c, i, cnt = 0, err = 0;
956 	unsigned long total_size;
957 
958 	if (!info || !info->screen_base)
959 		return -ENODEV;
960 
961 	if (info->state != FBINFO_STATE_RUNNING)
962 		return -EPERM;
963 
964 	total_size = info->screen_size;
965 
966 	if (total_size == 0)
967 		total_size = info->fix.smem_len;
968 
969 	if (p >= total_size)
970 		return 0;
971 
972 	if (count >= total_size)
973 		count = total_size;
974 
975 	if (count + p > total_size)
976 		count = total_size - p;
977 
978 	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
979 	if (!buffer)
980 		return -ENOMEM;
981 
982 	src = (u32 __iomem *)(info->screen_base + p);
983 
984 	if (info->fbops->fb_sync)
985 		info->fbops->fb_sync(info);
986 
987 	while (count) {
988 		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
989 		dst = buffer;
990 		for (i = c >> 2; i--;) {
991 			*dst = fb_readl(src++);
992 			*dst = big_swap(*dst);
993 			dst++;
994 		}
995 		if (c & 3) {
996 			u8 *dst8 = (u8 *)dst;
997 			u8 __iomem *src8 = (u8 __iomem *)src;
998 
999 			for (i = c & 3; i--;) {
1000 				if (i & 1) {
1001 					*dst8++ = fb_readb(++src8);
1002 				} else {
1003 					*dst8++ = fb_readb(--src8);
1004 					src8 += 2;
1005 				}
1006 			}
1007 			src = (u32 __iomem *)src8;
1008 		}
1009 
1010 		if (copy_to_user(buf, buffer, c)) {
1011 			err = -EFAULT;
1012 			break;
1013 		}
1014 		*ppos += c;
1015 		buf += c;
1016 		cnt += c;
1017 		count -= c;
1018 	}
1019 
1020 	kfree(buffer);
1021 
1022 	return (err) ? err : cnt;
1023 }
1024 
1025 static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
1026 			    size_t count, loff_t *ppos)
1027 {
1028 	unsigned long p = *ppos;
1029 
1030 	u32 *buffer, *src;
1031 	u32 __iomem *dst;
1032 	int c, i, cnt = 0, err = 0;
1033 	unsigned long total_size;
1034 
1035 	if (!info || !info->screen_base)
1036 		return -ENODEV;
1037 
1038 	if (info->state != FBINFO_STATE_RUNNING)
1039 		return -EPERM;
1040 
1041 	total_size = info->screen_size;
1042 
1043 	if (total_size == 0)
1044 		total_size = info->fix.smem_len;
1045 
1046 	if (p > total_size)
1047 		return -EFBIG;
1048 
1049 	if (count > total_size) {
1050 		err = -EFBIG;
1051 		count = total_size;
1052 	}
1053 
1054 	if (count + p > total_size) {
1055 		if (!err)
1056 			err = -ENOSPC;
1057 
1058 		count = total_size - p;
1059 	}
1060 
1061 	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
1062 	if (!buffer)
1063 		return -ENOMEM;
1064 
1065 	dst = (u32 __iomem *)(info->screen_base + p);
1066 
1067 	if (info->fbops->fb_sync)
1068 		info->fbops->fb_sync(info);
1069 
1070 	while (count) {
1071 		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1072 		src = buffer;
1073 
1074 		if (copy_from_user(src, buf, c)) {
1075 			err = -EFAULT;
1076 			break;
1077 		}
1078 
1079 		for (i = c >> 2; i--;) {
1080 			fb_writel(big_swap(*src), dst++);
1081 			src++;
1082 		}
1083 		if (c & 3) {
1084 			u8 *src8 = (u8 *)src;
1085 			u8 __iomem *dst8 = (u8 __iomem *)dst;
1086 
1087 			for (i = c & 3; i--;) {
1088 				if (i & 1) {
1089 					fb_writeb(*src8++, ++dst8);
1090 				} else {
1091 					fb_writeb(*src8++, --dst8);
1092 					dst8 += 2;
1093 				}
1094 			}
1095 			dst = (u32 __iomem *)dst8;
1096 		}
1097 
1098 		*ppos += c;
1099 		buf += c;
1100 		cnt += c;
1101 		count -= c;
1102 	}
1103 
1104 	kfree(buffer);
1105 
1106 	return (cnt) ? cnt : err;
1107 }
1108 
1109 static void sm7xx_set_timing(struct smtcfb_info *sfb)
1110 {
1111 	int i = 0, j = 0;
1112 	u32 m_nscreenstride;
1113 
1114 	dev_dbg(&sfb->pdev->dev,
1115 		"sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n",
1116 		sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz);
1117 
1118 	for (j = 0; j < ARRAY_SIZE(vgamode); j++) {
1119 		if (vgamode[j].mmsizex != sfb->width ||
1120 		    vgamode[j].mmsizey != sfb->height ||
1121 		    vgamode[j].bpp != sfb->fb->var.bits_per_pixel ||
1122 		    vgamode[j].hz != sfb->hz)
1123 			continue;
1124 
1125 		dev_dbg(&sfb->pdev->dev,
1126 			"vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
1127 			vgamode[j].mmsizex, vgamode[j].mmsizey,
1128 			vgamode[j].bpp, vgamode[j].hz);
1129 
1130 		dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
1131 
1132 		smtc_mmiowb(0x0, 0x3c6);
1133 
1134 		smtc_seqw(0, 0x1);
1135 
1136 		smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
1137 
1138 		/* init SEQ register SR00 - SR04 */
1139 		for (i = 0; i < SIZE_SR00_SR04; i++)
1140 			smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
1141 
1142 		/* init SEQ register SR10 - SR24 */
1143 		for (i = 0; i < SIZE_SR10_SR24; i++)
1144 			smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]);
1145 
1146 		/* init SEQ register SR30 - SR75 */
1147 		for (i = 0; i < SIZE_SR30_SR75; i++)
1148 			if ((i + 0x30) != 0x62 && (i + 0x30) != 0x6a &&
1149 			    (i + 0x30) != 0x6b)
1150 				smtc_seqw(i + 0x30,
1151 					  vgamode[j].init_sr30_sr75[i]);
1152 
1153 		/* init SEQ register SR80 - SR93 */
1154 		for (i = 0; i < SIZE_SR80_SR93; i++)
1155 			smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]);
1156 
1157 		/* init SEQ register SRA0 - SRAF */
1158 		for (i = 0; i < SIZE_SRA0_SRAF; i++)
1159 			smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]);
1160 
1161 		/* init Graphic register GR00 - GR08 */
1162 		for (i = 0; i < SIZE_GR00_GR08; i++)
1163 			smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
1164 
1165 		/* init Attribute register AR00 - AR14 */
1166 		for (i = 0; i < SIZE_AR00_AR14; i++)
1167 			smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
1168 
1169 		/* init CRTC register CR00 - CR18 */
1170 		for (i = 0; i < SIZE_CR00_CR18; i++)
1171 			smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
1172 
1173 		/* init CRTC register CR30 - CR4D */
1174 		for (i = 0; i < SIZE_CR30_CR4D; i++)
1175 			smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
1176 
1177 		/* init CRTC register CR90 - CRA7 */
1178 		for (i = 0; i < SIZE_CR90_CRA7; i++)
1179 			smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]);
1180 	}
1181 	smtc_mmiowb(0x67, 0x3c2);
1182 
1183 	/* set VPR registers */
1184 	writel(0x0, sfb->vp_regs + 0x0C);
1185 	writel(0x0, sfb->vp_regs + 0x40);
1186 
1187 	/* set data width */
1188 	m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64;
1189 	switch (sfb->fb->var.bits_per_pixel) {
1190 	case 8:
1191 		writel(0x0, sfb->vp_regs + 0x0);
1192 		break;
1193 	case 16:
1194 		writel(0x00020000, sfb->vp_regs + 0x0);
1195 		break;
1196 	case 24:
1197 		writel(0x00040000, sfb->vp_regs + 0x0);
1198 		break;
1199 	case 32:
1200 		writel(0x00030000, sfb->vp_regs + 0x0);
1201 		break;
1202 	}
1203 	writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride),
1204 	       sfb->vp_regs + 0x10);
1205 }
1206 
1207 static void smtc_set_timing(struct smtcfb_info *sfb)
1208 {
1209 	switch (sfb->chip_id) {
1210 	case 0x710:
1211 	case 0x712:
1212 	case 0x720:
1213 		sm7xx_set_timing(sfb);
1214 		break;
1215 	}
1216 }
1217 
1218 static void smtcfb_setmode(struct smtcfb_info *sfb)
1219 {
1220 	switch (sfb->fb->var.bits_per_pixel) {
1221 	case 32:
1222 		sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1223 		sfb->fb->fix.line_length  = sfb->fb->var.xres * 4;
1224 		sfb->fb->var.red.length   = 8;
1225 		sfb->fb->var.green.length = 8;
1226 		sfb->fb->var.blue.length  = 8;
1227 		sfb->fb->var.red.offset   = 16;
1228 		sfb->fb->var.green.offset = 8;
1229 		sfb->fb->var.blue.offset  = 0;
1230 		break;
1231 	case 24:
1232 		sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1233 		sfb->fb->fix.line_length  = sfb->fb->var.xres * 3;
1234 		sfb->fb->var.red.length   = 8;
1235 		sfb->fb->var.green.length = 8;
1236 		sfb->fb->var.blue.length  = 8;
1237 		sfb->fb->var.red.offset   = 16;
1238 		sfb->fb->var.green.offset = 8;
1239 		sfb->fb->var.blue.offset  = 0;
1240 		break;
1241 	case 8:
1242 		sfb->fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
1243 		sfb->fb->fix.line_length  = sfb->fb->var.xres;
1244 		sfb->fb->var.red.length   = 3;
1245 		sfb->fb->var.green.length = 3;
1246 		sfb->fb->var.blue.length  = 2;
1247 		sfb->fb->var.red.offset   = 5;
1248 		sfb->fb->var.green.offset = 2;
1249 		sfb->fb->var.blue.offset  = 0;
1250 		break;
1251 	case 16:
1252 	default:
1253 		sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1254 		sfb->fb->fix.line_length  = sfb->fb->var.xres * 2;
1255 		sfb->fb->var.red.length   = 5;
1256 		sfb->fb->var.green.length = 6;
1257 		sfb->fb->var.blue.length  = 5;
1258 		sfb->fb->var.red.offset   = 11;
1259 		sfb->fb->var.green.offset = 5;
1260 		sfb->fb->var.blue.offset  = 0;
1261 		break;
1262 	}
1263 
1264 	sfb->width  = sfb->fb->var.xres;
1265 	sfb->height = sfb->fb->var.yres;
1266 	sfb->hz = 60;
1267 	smtc_set_timing(sfb);
1268 }
1269 
1270 static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1271 {
1272 	/* sanity checks */
1273 	if (var->xres_virtual < var->xres)
1274 		var->xres_virtual = var->xres;
1275 
1276 	if (var->yres_virtual < var->yres)
1277 		var->yres_virtual = var->yres;
1278 
1279 	/* set valid default bpp */
1280 	if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
1281 	    (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
1282 		var->bits_per_pixel = 16;
1283 
1284 	return 0;
1285 }
1286 
1287 static int smtc_set_par(struct fb_info *info)
1288 {
1289 	smtcfb_setmode(info->par);
1290 
1291 	return 0;
1292 }
1293 
1294 static struct fb_ops smtcfb_ops = {
1295 	.owner        = THIS_MODULE,
1296 	.fb_check_var = smtc_check_var,
1297 	.fb_set_par   = smtc_set_par,
1298 	.fb_setcolreg = smtc_setcolreg,
1299 	.fb_blank     = smtc_blank,
1300 	.fb_fillrect  = cfb_fillrect,
1301 	.fb_imageblit = cfb_imageblit,
1302 	.fb_copyarea  = cfb_copyarea,
1303 	.fb_read      = smtcfb_read,
1304 	.fb_write     = smtcfb_write,
1305 };
1306 
1307 /*
1308  * Unmap in the memory mapped IO registers
1309  */
1310 
1311 static void smtc_unmap_mmio(struct smtcfb_info *sfb)
1312 {
1313 	if (sfb && smtc_regbaseaddress)
1314 		smtc_regbaseaddress = NULL;
1315 }
1316 
1317 /*
1318  * Map in the screen memory
1319  */
1320 
1321 static int smtc_map_smem(struct smtcfb_info *sfb,
1322 			 struct pci_dev *pdev, u_long smem_len)
1323 {
1324 	sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
1325 
1326 	if (sfb->fb->var.bits_per_pixel == 32)
1327 		sfb->fb->fix.smem_start += big_addr;
1328 
1329 	sfb->fb->fix.smem_len = smem_len;
1330 
1331 	sfb->fb->screen_base = sfb->lfb;
1332 
1333 	if (!sfb->fb->screen_base) {
1334 		dev_err(&pdev->dev,
1335 			"%s: unable to map screen memory\n", sfb->fb->fix.id);
1336 		return -ENOMEM;
1337 	}
1338 
1339 	return 0;
1340 }
1341 
1342 /*
1343  * Unmap in the screen memory
1344  *
1345  */
1346 static void smtc_unmap_smem(struct smtcfb_info *sfb)
1347 {
1348 	if (sfb && sfb->fb->screen_base) {
1349 		iounmap(sfb->fb->screen_base);
1350 		sfb->fb->screen_base = NULL;
1351 	}
1352 }
1353 
1354 /*
1355  * We need to wake up the device and make sure its in linear memory mode.
1356  */
1357 static inline void sm7xx_init_hw(void)
1358 {
1359 	outb_p(0x18, 0x3c4);
1360 	outb_p(0x11, 0x3c5);
1361 }
1362 
1363 static int smtcfb_pci_probe(struct pci_dev *pdev,
1364 			    const struct pci_device_id *ent)
1365 {
1366 	struct smtcfb_info *sfb;
1367 	struct fb_info *info;
1368 	u_long smem_size = 0x00800000;	/* default 8MB */
1369 	int err;
1370 	unsigned long mmio_base;
1371 
1372 	dev_info(&pdev->dev, "Silicon Motion display driver.\n");
1373 
1374 	err = pci_enable_device(pdev);	/* enable SMTC chip */
1375 	if (err)
1376 		return err;
1377 
1378 	err = pci_request_region(pdev, 0, "sm7xxfb");
1379 	if (err < 0) {
1380 		dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
1381 		goto failed_regions;
1382 	}
1383 
1384 	sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
1385 
1386 	info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
1387 	if (!info) {
1388 		dev_err(&pdev->dev, "framebuffer_alloc failed\n");
1389 		err = -ENOMEM;
1390 		goto failed_free;
1391 	}
1392 
1393 	sfb = info->par;
1394 	sfb->fb = info;
1395 	sfb->chip_id = ent->device;
1396 	sfb->pdev = pdev;
1397 	info->flags = FBINFO_FLAG_DEFAULT;
1398 	info->fbops = &smtcfb_ops;
1399 	info->fix = smtcfb_fix;
1400 	info->var = smtcfb_var;
1401 	info->pseudo_palette = sfb->colreg;
1402 	info->par = sfb;
1403 
1404 	pci_set_drvdata(pdev, sfb);
1405 
1406 	sm7xx_init_hw();
1407 
1408 	/* get mode parameter from smtc_scr_info */
1409 	if (smtc_scr_info.lfb_width != 0) {
1410 		sfb->fb->var.xres = smtc_scr_info.lfb_width;
1411 		sfb->fb->var.yres = smtc_scr_info.lfb_height;
1412 		sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
1413 	} else {
1414 		/* default resolution 1024x600 16bit mode */
1415 		sfb->fb->var.xres = SCREEN_X_RES;
1416 		sfb->fb->var.yres = SCREEN_Y_RES;
1417 		sfb->fb->var.bits_per_pixel = SCREEN_BPP;
1418 	}
1419 
1420 	big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
1421 	/* Map address and memory detection */
1422 	mmio_base = pci_resource_start(pdev, 0);
1423 	pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
1424 
1425 	switch (sfb->chip_id) {
1426 	case 0x710:
1427 	case 0x712:
1428 		sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
1429 		sfb->fb->fix.mmio_len = 0x00400000;
1430 		smem_size = SM712_VIDEOMEMORYSIZE;
1431 		sfb->lfb = ioremap(mmio_base, mmio_addr);
1432 		if (!sfb->lfb) {
1433 			dev_err(&pdev->dev,
1434 				"%s: unable to map memory mapped IO!\n",
1435 				sfb->fb->fix.id);
1436 			err = -ENOMEM;
1437 			goto failed_fb;
1438 		}
1439 
1440 		sfb->mmio = (smtc_regbaseaddress =
1441 		    sfb->lfb + 0x00700000);
1442 		sfb->dp_regs = sfb->lfb + 0x00408000;
1443 		sfb->vp_regs = sfb->lfb + 0x0040c000;
1444 		if (sfb->fb->var.bits_per_pixel == 32) {
1445 			sfb->lfb += big_addr;
1446 			dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
1447 		}
1448 
1449 		/* set MCLK = 14.31818 * (0x16 / 0x2) */
1450 		smtc_seqw(0x6a, 0x16);
1451 		smtc_seqw(0x6b, 0x02);
1452 		smtc_seqw(0x62, 0x3e);
1453 		/* enable PCI burst */
1454 		smtc_seqw(0x17, 0x20);
1455 		/* enable word swap */
1456 		if (sfb->fb->var.bits_per_pixel == 32)
1457 			seqw17();
1458 		break;
1459 	case 0x720:
1460 		sfb->fb->fix.mmio_start = mmio_base;
1461 		sfb->fb->fix.mmio_len = 0x00200000;
1462 		smem_size = SM722_VIDEOMEMORYSIZE;
1463 		sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
1464 		sfb->lfb = sfb->dp_regs + 0x00200000;
1465 		sfb->mmio = (smtc_regbaseaddress =
1466 		    sfb->dp_regs + 0x000c0000);
1467 		sfb->vp_regs = sfb->dp_regs + 0x800;
1468 
1469 		smtc_seqw(0x62, 0xff);
1470 		smtc_seqw(0x6a, 0x0d);
1471 		smtc_seqw(0x6b, 0x02);
1472 		break;
1473 	default:
1474 		dev_err(&pdev->dev,
1475 			"No valid Silicon Motion display chip was detected!\n");
1476 
1477 		goto failed_fb;
1478 	}
1479 
1480 	/* can support 32 bpp */
1481 	if (sfb->fb->var.bits_per_pixel == 15)
1482 		sfb->fb->var.bits_per_pixel = 16;
1483 
1484 	sfb->fb->var.xres_virtual = sfb->fb->var.xres;
1485 	sfb->fb->var.yres_virtual = sfb->fb->var.yres;
1486 	err = smtc_map_smem(sfb, pdev, smem_size);
1487 	if (err)
1488 		goto failed;
1489 
1490 	smtcfb_setmode(sfb);
1491 
1492 	err = register_framebuffer(info);
1493 	if (err < 0)
1494 		goto failed;
1495 
1496 	dev_info(&pdev->dev,
1497 		 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n",
1498 		 sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
1499 		 sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
1500 
1501 	return 0;
1502 
1503 failed:
1504 	dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n");
1505 
1506 	smtc_unmap_smem(sfb);
1507 	smtc_unmap_mmio(sfb);
1508 failed_fb:
1509 	framebuffer_release(info);
1510 
1511 failed_free:
1512 	pci_release_region(pdev, 0);
1513 
1514 failed_regions:
1515 	pci_disable_device(pdev);
1516 
1517 	return err;
1518 }
1519 
1520 /*
1521  * 0x710 (LynxEM)
1522  * 0x712 (LynxEM+)
1523  * 0x720 (Lynx3DM, Lynx3DM+)
1524  */
1525 static const struct pci_device_id smtcfb_pci_table[] = {
1526 	{ PCI_DEVICE(0x126f, 0x710), },
1527 	{ PCI_DEVICE(0x126f, 0x712), },
1528 	{ PCI_DEVICE(0x126f, 0x720), },
1529 	{0,}
1530 };
1531 
1532 MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
1533 
1534 static void smtcfb_pci_remove(struct pci_dev *pdev)
1535 {
1536 	struct smtcfb_info *sfb;
1537 
1538 	sfb = pci_get_drvdata(pdev);
1539 	smtc_unmap_smem(sfb);
1540 	smtc_unmap_mmio(sfb);
1541 	unregister_framebuffer(sfb->fb);
1542 	framebuffer_release(sfb->fb);
1543 	pci_release_region(pdev, 0);
1544 	pci_disable_device(pdev);
1545 }
1546 
1547 static int __maybe_unused smtcfb_pci_suspend(struct device *device)
1548 {
1549 	struct pci_dev *pdev = to_pci_dev(device);
1550 	struct smtcfb_info *sfb;
1551 
1552 	sfb = pci_get_drvdata(pdev);
1553 
1554 	/* set the hw in sleep mode use external clock and self memory refresh
1555 	 * so that we can turn off internal PLLs later on
1556 	 */
1557 	smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1558 	smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1559 
1560 	console_lock();
1561 	fb_set_suspend(sfb->fb, 1);
1562 	console_unlock();
1563 
1564 	/* additionally turn off all function blocks including internal PLLs */
1565 	smtc_seqw(0x21, 0xff);
1566 
1567 	return 0;
1568 }
1569 
1570 static int __maybe_unused smtcfb_pci_resume(struct device *device)
1571 {
1572 	struct pci_dev *pdev = to_pci_dev(device);
1573 	struct smtcfb_info *sfb;
1574 
1575 	sfb = pci_get_drvdata(pdev);
1576 
1577 	/* reinit hardware */
1578 	sm7xx_init_hw();
1579 	switch (sfb->chip_id) {
1580 	case 0x710:
1581 	case 0x712:
1582 		/* set MCLK = 14.31818 *  (0x16 / 0x2) */
1583 		smtc_seqw(0x6a, 0x16);
1584 		smtc_seqw(0x6b, 0x02);
1585 		smtc_seqw(0x62, 0x3e);
1586 		/* enable PCI burst */
1587 		smtc_seqw(0x17, 0x20);
1588 		if (sfb->fb->var.bits_per_pixel == 32)
1589 			seqw17();
1590 		break;
1591 	case 0x720:
1592 		smtc_seqw(0x62, 0xff);
1593 		smtc_seqw(0x6a, 0x0d);
1594 		smtc_seqw(0x6b, 0x02);
1595 		break;
1596 	}
1597 
1598 	smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1599 	smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1600 
1601 	smtcfb_setmode(sfb);
1602 
1603 	console_lock();
1604 	fb_set_suspend(sfb->fb, 0);
1605 	console_unlock();
1606 
1607 	return 0;
1608 }
1609 
1610 static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1611 
1612 static struct pci_driver smtcfb_driver = {
1613 	.name = "smtcfb",
1614 	.id_table = smtcfb_pci_table,
1615 	.probe = smtcfb_pci_probe,
1616 	.remove = smtcfb_pci_remove,
1617 	.driver.pm  = &sm7xx_pm_ops,
1618 };
1619 
1620 static int __init sm712fb_init(void)
1621 {
1622 	char *option = NULL;
1623 
1624 	if (fb_get_options("sm712fb", &option))
1625 		return -ENODEV;
1626 	if (option && *option)
1627 		mode_option = option;
1628 	sm7xx_vga_setup(mode_option);
1629 
1630 	return pci_register_driver(&smtcfb_driver);
1631 }
1632 
1633 module_init(sm712fb_init);
1634 
1635 static void __exit sm712fb_exit(void)
1636 {
1637 	pci_unregister_driver(&smtcfb_driver);
1638 }
1639 
1640 module_exit(sm712fb_exit);
1641 
1642 MODULE_AUTHOR("Siliconmotion ");
1643 MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1644 MODULE_LICENSE("GPL");
1645