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