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