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