xref: /openbmc/linux/drivers/video/fbdev/sm712fb.c (revision bc5aa3a0)
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 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("sm7xx_vga_setup = %s\n", 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 red, unsigned green,
802 			     unsigned 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 regno, unsigned red, unsigned green,
900 			  unsigned blue, unsigned trans, struct fb_info *info)
901 {
902 	struct smtcfb_info *sfb;
903 	u32 val;
904 
905 	sfb = info->par;
906 
907 	if (regno > 255)
908 		return 1;
909 
910 	switch (sfb->fb->fix.visual) {
911 	case FB_VISUAL_DIRECTCOLOR:
912 	case FB_VISUAL_TRUECOLOR:
913 		/*
914 		 * 16/32 bit true-colour, use pseudo-palette for 16 base color
915 		 */
916 		if (regno >= 16)
917 			break;
918 		if (sfb->fb->var.bits_per_pixel == 16) {
919 			u32 *pal = sfb->fb->pseudo_palette;
920 
921 			val = chan_to_field(red, &sfb->fb->var.red);
922 			val |= chan_to_field(green, &sfb->fb->var.green);
923 			val |= chan_to_field(blue, &sfb->fb->var.blue);
924 			pal[regno] = pal_rgb(red, green, blue, val);
925 		} else {
926 			u32 *pal = sfb->fb->pseudo_palette;
927 
928 			val = chan_to_field(red, &sfb->fb->var.red);
929 			val |= chan_to_field(green, &sfb->fb->var.green);
930 			val |= chan_to_field(blue, &sfb->fb->var.blue);
931 			pal[regno] = big_swap(val);
932 		}
933 		break;
934 
935 	case FB_VISUAL_PSEUDOCOLOR:
936 		/* color depth 8 bit */
937 		sm712_setpalette(regno, red, green, blue, info);
938 		break;
939 
940 	default:
941 		return 1;	/* unknown type */
942 	}
943 
944 	return 0;
945 }
946 
947 static ssize_t smtcfb_read(struct fb_info *info, char __user *buf,
948 			   size_t count, loff_t *ppos)
949 {
950 	unsigned long p = *ppos;
951 
952 	u32 *buffer, *dst;
953 	u32 __iomem *src;
954 	int c, i, cnt = 0, err = 0;
955 	unsigned long total_size;
956 
957 	if (!info || !info->screen_base)
958 		return -ENODEV;
959 
960 	if (info->state != FBINFO_STATE_RUNNING)
961 		return -EPERM;
962 
963 	total_size = info->screen_size;
964 
965 	if (total_size == 0)
966 		total_size = info->fix.smem_len;
967 
968 	if (p >= total_size)
969 		return 0;
970 
971 	if (count >= total_size)
972 		count = total_size;
973 
974 	if (count + p > total_size)
975 		count = total_size - p;
976 
977 	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
978 	if (!buffer)
979 		return -ENOMEM;
980 
981 	src = (u32 __iomem *)(info->screen_base + p);
982 
983 	if (info->fbops->fb_sync)
984 		info->fbops->fb_sync(info);
985 
986 	while (count) {
987 		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
988 		dst = buffer;
989 		for (i = c >> 2; i--;) {
990 			*dst = fb_readl(src++);
991 			*dst = big_swap(*dst);
992 			dst++;
993 		}
994 		if (c & 3) {
995 			u8 *dst8 = (u8 *)dst;
996 			u8 __iomem *src8 = (u8 __iomem *)src;
997 
998 			for (i = c & 3; i--;) {
999 				if (i & 1) {
1000 					*dst8++ = fb_readb(++src8);
1001 				} else {
1002 					*dst8++ = fb_readb(--src8);
1003 					src8 += 2;
1004 				}
1005 			}
1006 			src = (u32 __iomem *)src8;
1007 		}
1008 
1009 		if (copy_to_user(buf, buffer, c)) {
1010 			err = -EFAULT;
1011 			break;
1012 		}
1013 		*ppos += c;
1014 		buf += c;
1015 		cnt += c;
1016 		count -= c;
1017 	}
1018 
1019 	kfree(buffer);
1020 
1021 	return (err) ? err : cnt;
1022 }
1023 
1024 static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
1025 			    size_t count, loff_t *ppos)
1026 {
1027 	unsigned long p = *ppos;
1028 
1029 	u32 *buffer, *src;
1030 	u32 __iomem *dst;
1031 	int c, i, cnt = 0, err = 0;
1032 	unsigned long total_size;
1033 
1034 	if (!info || !info->screen_base)
1035 		return -ENODEV;
1036 
1037 	if (info->state != FBINFO_STATE_RUNNING)
1038 		return -EPERM;
1039 
1040 	total_size = info->screen_size;
1041 
1042 	if (total_size == 0)
1043 		total_size = info->fix.smem_len;
1044 
1045 	if (p > total_size)
1046 		return -EFBIG;
1047 
1048 	if (count > total_size) {
1049 		err = -EFBIG;
1050 		count = total_size;
1051 	}
1052 
1053 	if (count + p > total_size) {
1054 		if (!err)
1055 			err = -ENOSPC;
1056 
1057 		count = total_size - p;
1058 	}
1059 
1060 	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
1061 	if (!buffer)
1062 		return -ENOMEM;
1063 
1064 	dst = (u32 __iomem *)(info->screen_base + p);
1065 
1066 	if (info->fbops->fb_sync)
1067 		info->fbops->fb_sync(info);
1068 
1069 	while (count) {
1070 		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1071 		src = buffer;
1072 
1073 		if (copy_from_user(src, buf, c)) {
1074 			err = -EFAULT;
1075 			break;
1076 		}
1077 
1078 		for (i = c >> 2; i--;) {
1079 			fb_writel(big_swap(*src), dst++);
1080 			src++;
1081 		}
1082 		if (c & 3) {
1083 			u8 *src8 = (u8 *)src;
1084 			u8 __iomem *dst8 = (u8 __iomem *)dst;
1085 
1086 			for (i = c & 3; i--;) {
1087 				if (i & 1) {
1088 					fb_writeb(*src8++, ++dst8);
1089 				} else {
1090 					fb_writeb(*src8++, --dst8);
1091 					dst8 += 2;
1092 				}
1093 			}
1094 			dst = (u32 __iomem *)dst8;
1095 		}
1096 
1097 		*ppos += c;
1098 		buf += c;
1099 		cnt += c;
1100 		count -= c;
1101 	}
1102 
1103 	kfree(buffer);
1104 
1105 	return (cnt) ? cnt : err;
1106 }
1107 
1108 static void sm7xx_set_timing(struct smtcfb_info *sfb)
1109 {
1110 	int i = 0, j = 0;
1111 	u32 m_nscreenstride;
1112 
1113 	dev_dbg(&sfb->pdev->dev,
1114 		"sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n",
1115 		sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz);
1116 
1117 	for (j = 0; j < ARRAY_SIZE(vgamode); j++) {
1118 		if (vgamode[j].mmsizex != sfb->width ||
1119 		    vgamode[j].mmsizey != sfb->height ||
1120 		    vgamode[j].bpp != sfb->fb->var.bits_per_pixel ||
1121 		    vgamode[j].hz != sfb->hz)
1122 			continue;
1123 
1124 		dev_dbg(&sfb->pdev->dev,
1125 			"vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
1126 			vgamode[j].mmsizex, vgamode[j].mmsizey,
1127 			vgamode[j].bpp, vgamode[j].hz);
1128 
1129 		dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
1130 
1131 		smtc_mmiowb(0x0, 0x3c6);
1132 
1133 		smtc_seqw(0, 0x1);
1134 
1135 		smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
1136 
1137 		/* init SEQ register SR00 - SR04 */
1138 		for (i = 0; i < SIZE_SR00_SR04; i++)
1139 			smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
1140 
1141 		/* init SEQ register SR10 - SR24 */
1142 		for (i = 0; i < SIZE_SR10_SR24; i++)
1143 			smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]);
1144 
1145 		/* init SEQ register SR30 - SR75 */
1146 		for (i = 0; i < SIZE_SR30_SR75; i++)
1147 			if ((i + 0x30) != 0x62 && (i + 0x30) != 0x6a &&
1148 			    (i + 0x30) != 0x6b)
1149 				smtc_seqw(i + 0x30,
1150 					  vgamode[j].init_sr30_sr75[i]);
1151 
1152 		/* init SEQ register SR80 - SR93 */
1153 		for (i = 0; i < SIZE_SR80_SR93; i++)
1154 			smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]);
1155 
1156 		/* init SEQ register SRA0 - SRAF */
1157 		for (i = 0; i < SIZE_SRA0_SRAF; i++)
1158 			smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]);
1159 
1160 		/* init Graphic register GR00 - GR08 */
1161 		for (i = 0; i < SIZE_GR00_GR08; i++)
1162 			smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
1163 
1164 		/* init Attribute register AR00 - AR14 */
1165 		for (i = 0; i < SIZE_AR00_AR14; i++)
1166 			smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
1167 
1168 		/* init CRTC register CR00 - CR18 */
1169 		for (i = 0; i < SIZE_CR00_CR18; i++)
1170 			smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
1171 
1172 		/* init CRTC register CR30 - CR4D */
1173 		for (i = 0; i < SIZE_CR30_CR4D; i++)
1174 			smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
1175 
1176 		/* init CRTC register CR90 - CRA7 */
1177 		for (i = 0; i < SIZE_CR90_CRA7; i++)
1178 			smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]);
1179 	}
1180 	smtc_mmiowb(0x67, 0x3c2);
1181 
1182 	/* set VPR registers */
1183 	writel(0x0, sfb->vp_regs + 0x0C);
1184 	writel(0x0, sfb->vp_regs + 0x40);
1185 
1186 	/* set data width */
1187 	m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64;
1188 	switch (sfb->fb->var.bits_per_pixel) {
1189 	case 8:
1190 		writel(0x0, sfb->vp_regs + 0x0);
1191 		break;
1192 	case 16:
1193 		writel(0x00020000, sfb->vp_regs + 0x0);
1194 		break;
1195 	case 24:
1196 		writel(0x00040000, sfb->vp_regs + 0x0);
1197 		break;
1198 	case 32:
1199 		writel(0x00030000, sfb->vp_regs + 0x0);
1200 		break;
1201 	}
1202 	writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride),
1203 	       sfb->vp_regs + 0x10);
1204 }
1205 
1206 static void smtc_set_timing(struct smtcfb_info *sfb)
1207 {
1208 	switch (sfb->chip_id) {
1209 	case 0x710:
1210 	case 0x712:
1211 	case 0x720:
1212 		sm7xx_set_timing(sfb);
1213 		break;
1214 	}
1215 }
1216 
1217 static void smtcfb_setmode(struct smtcfb_info *sfb)
1218 {
1219 	switch (sfb->fb->var.bits_per_pixel) {
1220 	case 32:
1221 		sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1222 		sfb->fb->fix.line_length  = sfb->fb->var.xres * 4;
1223 		sfb->fb->var.red.length   = 8;
1224 		sfb->fb->var.green.length = 8;
1225 		sfb->fb->var.blue.length  = 8;
1226 		sfb->fb->var.red.offset   = 16;
1227 		sfb->fb->var.green.offset = 8;
1228 		sfb->fb->var.blue.offset  = 0;
1229 		break;
1230 	case 24:
1231 		sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1232 		sfb->fb->fix.line_length  = sfb->fb->var.xres * 3;
1233 		sfb->fb->var.red.length   = 8;
1234 		sfb->fb->var.green.length = 8;
1235 		sfb->fb->var.blue.length  = 8;
1236 		sfb->fb->var.red.offset   = 16;
1237 		sfb->fb->var.green.offset = 8;
1238 		sfb->fb->var.blue.offset  = 0;
1239 		break;
1240 	case 8:
1241 		sfb->fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
1242 		sfb->fb->fix.line_length  = sfb->fb->var.xres;
1243 		sfb->fb->var.red.length   = 3;
1244 		sfb->fb->var.green.length = 3;
1245 		sfb->fb->var.blue.length  = 2;
1246 		sfb->fb->var.red.offset   = 5;
1247 		sfb->fb->var.green.offset = 2;
1248 		sfb->fb->var.blue.offset  = 0;
1249 		break;
1250 	case 16:
1251 	default:
1252 		sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1253 		sfb->fb->fix.line_length  = sfb->fb->var.xres * 2;
1254 		sfb->fb->var.red.length   = 5;
1255 		sfb->fb->var.green.length = 6;
1256 		sfb->fb->var.blue.length  = 5;
1257 		sfb->fb->var.red.offset   = 11;
1258 		sfb->fb->var.green.offset = 5;
1259 		sfb->fb->var.blue.offset  = 0;
1260 		break;
1261 	}
1262 
1263 	sfb->width  = sfb->fb->var.xres;
1264 	sfb->height = sfb->fb->var.yres;
1265 	sfb->hz = 60;
1266 	smtc_set_timing(sfb);
1267 }
1268 
1269 static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1270 {
1271 	/* sanity checks */
1272 	if (var->xres_virtual < var->xres)
1273 		var->xres_virtual = var->xres;
1274 
1275 	if (var->yres_virtual < var->yres)
1276 		var->yres_virtual = var->yres;
1277 
1278 	/* set valid default bpp */
1279 	if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
1280 	    (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
1281 		var->bits_per_pixel = 16;
1282 
1283 	return 0;
1284 }
1285 
1286 static int smtc_set_par(struct fb_info *info)
1287 {
1288 	smtcfb_setmode(info->par);
1289 
1290 	return 0;
1291 }
1292 
1293 static struct fb_ops smtcfb_ops = {
1294 	.owner        = THIS_MODULE,
1295 	.fb_check_var = smtc_check_var,
1296 	.fb_set_par   = smtc_set_par,
1297 	.fb_setcolreg = smtc_setcolreg,
1298 	.fb_blank     = smtc_blank,
1299 	.fb_fillrect  = cfb_fillrect,
1300 	.fb_imageblit = cfb_imageblit,
1301 	.fb_copyarea  = cfb_copyarea,
1302 	.fb_read      = smtcfb_read,
1303 	.fb_write     = smtcfb_write,
1304 };
1305 
1306 /*
1307  * Unmap in the memory mapped IO registers
1308  */
1309 
1310 static void smtc_unmap_mmio(struct smtcfb_info *sfb)
1311 {
1312 	if (sfb && smtc_regbaseaddress)
1313 		smtc_regbaseaddress = NULL;
1314 }
1315 
1316 /*
1317  * Map in the screen memory
1318  */
1319 
1320 static int smtc_map_smem(struct smtcfb_info *sfb,
1321 			 struct pci_dev *pdev, u_long smem_len)
1322 {
1323 	sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
1324 
1325 	if (sfb->fb->var.bits_per_pixel == 32)
1326 		sfb->fb->fix.smem_start += big_addr;
1327 
1328 	sfb->fb->fix.smem_len = smem_len;
1329 
1330 	sfb->fb->screen_base = sfb->lfb;
1331 
1332 	if (!sfb->fb->screen_base) {
1333 		dev_err(&pdev->dev,
1334 			"%s: unable to map screen memory\n", sfb->fb->fix.id);
1335 		return -ENOMEM;
1336 	}
1337 
1338 	return 0;
1339 }
1340 
1341 /*
1342  * Unmap in the screen memory
1343  *
1344  */
1345 static void smtc_unmap_smem(struct smtcfb_info *sfb)
1346 {
1347 	if (sfb && sfb->fb->screen_base) {
1348 		iounmap(sfb->fb->screen_base);
1349 		sfb->fb->screen_base = NULL;
1350 	}
1351 }
1352 
1353 /*
1354  * We need to wake up the device and make sure its in linear memory mode.
1355  */
1356 static inline void sm7xx_init_hw(void)
1357 {
1358 	outb_p(0x18, 0x3c4);
1359 	outb_p(0x11, 0x3c5);
1360 }
1361 
1362 static int smtcfb_pci_probe(struct pci_dev *pdev,
1363 			    const struct pci_device_id *ent)
1364 {
1365 	struct smtcfb_info *sfb;
1366 	struct fb_info *info;
1367 	u_long smem_size = 0x00800000;	/* default 8MB */
1368 	int err;
1369 	unsigned long mmio_base;
1370 
1371 	dev_info(&pdev->dev, "Silicon Motion display driver.\n");
1372 
1373 	err = pci_enable_device(pdev);	/* enable SMTC chip */
1374 	if (err)
1375 		return err;
1376 
1377 	err = pci_request_region(pdev, 0, "sm7xxfb");
1378 	if (err < 0) {
1379 		dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
1380 		goto failed_regions;
1381 	}
1382 
1383 	sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
1384 
1385 	info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
1386 	if (!info) {
1387 		dev_err(&pdev->dev, "framebuffer_alloc failed\n");
1388 		err = -ENOMEM;
1389 		goto failed_free;
1390 	}
1391 
1392 	sfb = info->par;
1393 	sfb->fb = info;
1394 	sfb->chip_id = ent->device;
1395 	sfb->pdev = pdev;
1396 	info->flags = FBINFO_FLAG_DEFAULT;
1397 	info->fbops = &smtcfb_ops;
1398 	info->fix = smtcfb_fix;
1399 	info->var = smtcfb_var;
1400 	info->pseudo_palette = sfb->colreg;
1401 	info->par = sfb;
1402 
1403 	pci_set_drvdata(pdev, sfb);
1404 
1405 	sm7xx_init_hw();
1406 
1407 	/* get mode parameter from smtc_scr_info */
1408 	if (smtc_scr_info.lfb_width != 0) {
1409 		sfb->fb->var.xres = smtc_scr_info.lfb_width;
1410 		sfb->fb->var.yres = smtc_scr_info.lfb_height;
1411 		sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
1412 	} else {
1413 		/* default resolution 1024x600 16bit mode */
1414 		sfb->fb->var.xres = SCREEN_X_RES;
1415 		sfb->fb->var.yres = SCREEN_Y_RES;
1416 		sfb->fb->var.bits_per_pixel = SCREEN_BPP;
1417 	}
1418 
1419 	big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
1420 	/* Map address and memory detection */
1421 	mmio_base = pci_resource_start(pdev, 0);
1422 	pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
1423 
1424 	switch (sfb->chip_id) {
1425 	case 0x710:
1426 	case 0x712:
1427 		sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
1428 		sfb->fb->fix.mmio_len = 0x00400000;
1429 		smem_size = SM712_VIDEOMEMORYSIZE;
1430 		sfb->lfb = ioremap(mmio_base, mmio_addr);
1431 		if (!sfb->lfb) {
1432 			dev_err(&pdev->dev,
1433 				"%s: unable to map memory mapped IO!\n",
1434 				sfb->fb->fix.id);
1435 			err = -ENOMEM;
1436 			goto failed_fb;
1437 		}
1438 
1439 		sfb->mmio = (smtc_regbaseaddress =
1440 		    sfb->lfb + 0x00700000);
1441 		sfb->dp_regs = sfb->lfb + 0x00408000;
1442 		sfb->vp_regs = sfb->lfb + 0x0040c000;
1443 		if (sfb->fb->var.bits_per_pixel == 32) {
1444 			sfb->lfb += big_addr;
1445 			dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
1446 		}
1447 
1448 		/* set MCLK = 14.31818 * (0x16 / 0x2) */
1449 		smtc_seqw(0x6a, 0x16);
1450 		smtc_seqw(0x6b, 0x02);
1451 		smtc_seqw(0x62, 0x3e);
1452 		/* enable PCI burst */
1453 		smtc_seqw(0x17, 0x20);
1454 		/* enable word swap */
1455 		if (sfb->fb->var.bits_per_pixel == 32)
1456 			seqw17();
1457 		break;
1458 	case 0x720:
1459 		sfb->fb->fix.mmio_start = mmio_base;
1460 		sfb->fb->fix.mmio_len = 0x00200000;
1461 		smem_size = SM722_VIDEOMEMORYSIZE;
1462 		sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
1463 		sfb->lfb = sfb->dp_regs + 0x00200000;
1464 		sfb->mmio = (smtc_regbaseaddress =
1465 		    sfb->dp_regs + 0x000c0000);
1466 		sfb->vp_regs = sfb->dp_regs + 0x800;
1467 
1468 		smtc_seqw(0x62, 0xff);
1469 		smtc_seqw(0x6a, 0x0d);
1470 		smtc_seqw(0x6b, 0x02);
1471 		break;
1472 	default:
1473 		dev_err(&pdev->dev,
1474 			"No valid Silicon Motion display chip was detected!\n");
1475 
1476 		goto failed_fb;
1477 	}
1478 
1479 	/* can support 32 bpp */
1480 	if (15 == sfb->fb->var.bits_per_pixel)
1481 		sfb->fb->var.bits_per_pixel = 16;
1482 
1483 	sfb->fb->var.xres_virtual = sfb->fb->var.xres;
1484 	sfb->fb->var.yres_virtual = sfb->fb->var.yres;
1485 	err = smtc_map_smem(sfb, pdev, smem_size);
1486 	if (err)
1487 		goto failed;
1488 
1489 	smtcfb_setmode(sfb);
1490 
1491 	err = register_framebuffer(info);
1492 	if (err < 0)
1493 		goto failed;
1494 
1495 	dev_info(&pdev->dev,
1496 		 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n",
1497 		 sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
1498 		 sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
1499 
1500 	return 0;
1501 
1502 failed:
1503 	dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n");
1504 
1505 	smtc_unmap_smem(sfb);
1506 	smtc_unmap_mmio(sfb);
1507 failed_fb:
1508 	framebuffer_release(info);
1509 
1510 failed_free:
1511 	pci_release_region(pdev, 0);
1512 
1513 failed_regions:
1514 	pci_disable_device(pdev);
1515 
1516 	return err;
1517 }
1518 
1519 /*
1520  * 0x710 (LynxEM)
1521  * 0x712 (LynxEM+)
1522  * 0x720 (Lynx3DM, Lynx3DM+)
1523  */
1524 static const struct pci_device_id smtcfb_pci_table[] = {
1525 	{ PCI_DEVICE(0x126f, 0x710), },
1526 	{ PCI_DEVICE(0x126f, 0x712), },
1527 	{ PCI_DEVICE(0x126f, 0x720), },
1528 	{0,}
1529 };
1530 
1531 MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
1532 
1533 static void smtcfb_pci_remove(struct pci_dev *pdev)
1534 {
1535 	struct smtcfb_info *sfb;
1536 
1537 	sfb = pci_get_drvdata(pdev);
1538 	smtc_unmap_smem(sfb);
1539 	smtc_unmap_mmio(sfb);
1540 	unregister_framebuffer(sfb->fb);
1541 	framebuffer_release(sfb->fb);
1542 	pci_release_region(pdev, 0);
1543 	pci_disable_device(pdev);
1544 }
1545 
1546 static int __maybe_unused smtcfb_pci_suspend(struct device *device)
1547 {
1548 	struct pci_dev *pdev = to_pci_dev(device);
1549 	struct smtcfb_info *sfb;
1550 
1551 	sfb = pci_get_drvdata(pdev);
1552 
1553 	/* set the hw in sleep mode use external clock and self memory refresh
1554 	 * so that we can turn off internal PLLs later on
1555 	 */
1556 	smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1557 	smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1558 
1559 	console_lock();
1560 	fb_set_suspend(sfb->fb, 1);
1561 	console_unlock();
1562 
1563 	/* additionally turn off all function blocks including internal PLLs */
1564 	smtc_seqw(0x21, 0xff);
1565 
1566 	return 0;
1567 }
1568 
1569 static int __maybe_unused smtcfb_pci_resume(struct device *device)
1570 {
1571 	struct pci_dev *pdev = to_pci_dev(device);
1572 	struct smtcfb_info *sfb;
1573 
1574 	sfb = pci_get_drvdata(pdev);
1575 
1576 	/* reinit hardware */
1577 	sm7xx_init_hw();
1578 	switch (sfb->chip_id) {
1579 	case 0x710:
1580 	case 0x712:
1581 		/* set MCLK = 14.31818 *  (0x16 / 0x2) */
1582 		smtc_seqw(0x6a, 0x16);
1583 		smtc_seqw(0x6b, 0x02);
1584 		smtc_seqw(0x62, 0x3e);
1585 		/* enable PCI burst */
1586 		smtc_seqw(0x17, 0x20);
1587 		if (sfb->fb->var.bits_per_pixel == 32)
1588 			seqw17();
1589 		break;
1590 	case 0x720:
1591 		smtc_seqw(0x62, 0xff);
1592 		smtc_seqw(0x6a, 0x0d);
1593 		smtc_seqw(0x6b, 0x02);
1594 		break;
1595 	}
1596 
1597 	smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1598 	smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1599 
1600 	smtcfb_setmode(sfb);
1601 
1602 	console_lock();
1603 	fb_set_suspend(sfb->fb, 0);
1604 	console_unlock();
1605 
1606 	return 0;
1607 }
1608 
1609 static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1610 
1611 static struct pci_driver smtcfb_driver = {
1612 	.name = "smtcfb",
1613 	.id_table = smtcfb_pci_table,
1614 	.probe = smtcfb_pci_probe,
1615 	.remove = smtcfb_pci_remove,
1616 	.driver.pm  = &sm7xx_pm_ops,
1617 };
1618 
1619 static int __init sm712fb_init(void)
1620 {
1621 	char *option = NULL;
1622 
1623 	if (fb_get_options("sm712fb", &option))
1624 		return -ENODEV;
1625 	if (option && *option)
1626 		mode_option = option;
1627 	sm7xx_vga_setup(mode_option);
1628 
1629 	return pci_register_driver(&smtcfb_driver);
1630 }
1631 
1632 module_init(sm712fb_init);
1633 
1634 static void __exit sm712fb_exit(void)
1635 {
1636 	pci_unregister_driver(&smtcfb_driver);
1637 }
1638 
1639 module_exit(sm712fb_exit);
1640 
1641 MODULE_AUTHOR("Siliconmotion ");
1642 MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1643 MODULE_LICENSE("GPL");
1644