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