Merge tag 'fbdev-v4.15' of git://github.com/bzolnier/linux
[sfrench/cifs-2.6.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         {       /*  mode#5: 1024 x 768  24Bpp  60Hz */
534                 1024, 768, 24, 60,
535                 /*  Init_MISC */
536                 0xEB,
537                 {       /*  Init_SR0_SR4 */
538                         0x03, 0x01, 0x0F, 0x03, 0x0E,
539                 },
540                 {       /*  Init_SR10_SR24 */
541                         0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
542                         0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
543                         0xC4, 0x30, 0x02, 0x01, 0x01,
544                 },
545                 {       /*  Init_SR30_SR75 */
546                         0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
547                         0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
548                         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
549                         0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
550                         0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
551                         0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
552                         0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
553                         0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
554                         0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
555                 },
556                 {       /*  Init_SR80_SR93 */
557                         0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
558                         0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
559                         0x00, 0x00, 0x00, 0x00,
560                 },
561                 {       /*  Init_SRA0_SRAF */
562                         0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
563                         0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
564                 },
565                 {       /*  Init_GR00_GR08 */
566                         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
567                         0xFF,
568                 },
569                 {       /*  Init_AR00_AR14 */
570                         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
571                         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
572                         0x41, 0x00, 0x0F, 0x00, 0x00,
573                 },
574                 {       /*  Init_CR00_CR18 */
575                         0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
576                         0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
577                         0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
578                         0xFF,
579                 },
580                 {       /*  Init_CR30_CR4D */
581                         0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
582                         0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
583                         0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
584                         0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
585                 },
586                 {       /*  Init_CR90_CRA7 */
587                         0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
588                         0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
589                         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
590                 },
591         },
592         {       /*  mode#4: 1024 x 768  32Bpp  60Hz */
593                 1024, 768, 32, 60,
594                 /*  Init_MISC */
595                 0xEB,
596                 {       /*  Init_SR0_SR4 */
597                         0x03, 0x01, 0x0F, 0x03, 0x0E,
598                 },
599                 {       /*  Init_SR10_SR24 */
600                         0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
601                         0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
602                         0xC4, 0x32, 0x02, 0x01, 0x01,
603                 },
604                 {       /*  Init_SR30_SR75 */
605                         0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
606                         0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
607                         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
608                         0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
609                         0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
610                         0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
611                         0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
612                         0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
613                         0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
614                 },
615                 {       /*  Init_SR80_SR93 */
616                         0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
617                         0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
618                         0x00, 0x00, 0x00, 0x00,
619                 },
620                 {       /*  Init_SRA0_SRAF */
621                         0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
622                         0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
623                 },
624                 {       /*  Init_GR00_GR08 */
625                         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
626                         0xFF,
627                 },
628                 {       /*  Init_AR00_AR14 */
629                         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
630                         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
631                         0x41, 0x00, 0x0F, 0x00, 0x00,
632                 },
633                 {       /*  Init_CR00_CR18 */
634                         0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
635                         0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636                         0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
637                         0xFF,
638                 },
639                 {       /*  Init_CR30_CR4D */
640                         0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
641                         0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
642                         0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
643                         0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
644                 },
645                 {       /*  Init_CR90_CRA7 */
646                         0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
647                         0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
648                         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
649                 },
650         },
651         {       /*  mode#6: 320 x 240  16Bpp  60Hz */
652                 320, 240, 16, 60,
653                 /*  Init_MISC */
654                 0xEB,
655                 {       /*  Init_SR0_SR4 */
656                         0x03, 0x01, 0x0F, 0x03, 0x0E,
657                 },
658                 {       /*  Init_SR10_SR24 */
659                         0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
660                         0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
661                         0xC4, 0x32, 0x02, 0x01, 0x01,
662                 },
663                 {       /*  Init_SR30_SR75 */
664                         0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
665                         0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
666                         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
667                         0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
668                         0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
669                         0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
670                         0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
671                         0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
672                         0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
673                 },
674                 {       /*  Init_SR80_SR93 */
675                         0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
676                         0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
677                         0x00, 0x00, 0x00, 0x00,
678                 },
679                 {       /*  Init_SRA0_SRAF */
680                         0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
681                         0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
682                 },
683                 {       /*  Init_GR00_GR08 */
684                         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
685                         0xFF,
686                 },
687                 {       /*  Init_AR00_AR14 */
688                         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
689                         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
690                         0x41, 0x00, 0x0F, 0x00, 0x00,
691                 },
692                 {       /*  Init_CR00_CR18 */
693                         0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
694                         0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695                         0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
696                         0xFF,
697                 },
698                 {       /*  Init_CR30_CR4D */
699                         0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
700                         0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
701                         0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
702                         0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
703                 },
704                 {       /*  Init_CR90_CRA7 */
705                         0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
706                         0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
707                         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
708                 },
709         },
710
711         {       /*  mode#8: 320 x 240  32Bpp  60Hz */
712                 320, 240, 32, 60,
713                 /*  Init_MISC */
714                 0xEB,
715                 {       /*  Init_SR0_SR4 */
716                         0x03, 0x01, 0x0F, 0x03, 0x0E,
717                 },
718                 {       /*  Init_SR10_SR24 */
719                         0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
720                         0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
721                         0xC4, 0x32, 0x02, 0x01, 0x01,
722                 },
723                 {       /*  Init_SR30_SR75 */
724                         0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
725                         0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
726                         0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
727                         0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
728                         0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
729                         0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
730                         0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
731                         0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
732                         0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
733                 },
734                 {       /*  Init_SR80_SR93 */
735                         0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
736                         0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
737                         0x00, 0x00, 0x00, 0x00,
738                 },
739                 {       /*  Init_SRA0_SRAF */
740                         0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
741                         0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
742                 },
743                 {       /*  Init_GR00_GR08 */
744                         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
745                         0xFF,
746                 },
747                 {       /*  Init_AR00_AR14 */
748                         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
749                         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
750                         0x41, 0x00, 0x0F, 0x00, 0x00,
751                 },
752                 {       /*  Init_CR00_CR18 */
753                         0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
754                         0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
755                         0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
756                         0xFF,
757                 },
758                 {       /*  Init_CR30_CR4D */
759                         0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
760                         0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
761                         0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
762                         0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
763                 },
764                 {       /*  Init_CR90_CRA7 */
765                         0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
766                         0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
767                         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
768                 },
769         },
770 };
771
772 static struct screen_info smtc_scr_info;
773
774 static char *mode_option;
775
776 /* process command line options, get vga parameter */
777 static void __init sm7xx_vga_setup(char *options)
778 {
779         int i;
780
781         if (!options || !*options)
782                 return;
783
784         smtc_scr_info.lfb_width = 0;
785         smtc_scr_info.lfb_height = 0;
786         smtc_scr_info.lfb_depth = 0;
787
788         pr_debug("%s = %s\n", __func__, options);
789
790         for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
791                 if (strstr(options, vesa_mode_table[i].index)) {
792                         smtc_scr_info.lfb_width  = vesa_mode_table[i].lfb_width;
793                         smtc_scr_info.lfb_height =
794                                                 vesa_mode_table[i].lfb_height;
795                         smtc_scr_info.lfb_depth  = vesa_mode_table[i].lfb_depth;
796                         return;
797                 }
798         }
799 }
800
801 static void sm712_setpalette(int regno, unsigned int red, unsigned int green,
802                              unsigned int blue, struct fb_info *info)
803 {
804         /* set bit 5:4 = 01 (write LCD RAM only) */
805         smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
806
807         smtc_mmiowb(regno, dac_reg);
808         smtc_mmiowb(red >> 10, dac_val);
809         smtc_mmiowb(green >> 10, dac_val);
810         smtc_mmiowb(blue >> 10, dac_val);
811 }
812
813 /* chan_to_field
814  *
815  * convert a colour value into a field position
816  *
817  * from pxafb.c
818  */
819
820 static inline unsigned int chan_to_field(unsigned int chan,
821                                          struct fb_bitfield *bf)
822 {
823         chan &= 0xffff;
824         chan >>= 16 - bf->length;
825         return chan << bf->offset;
826 }
827
828 static int smtc_blank(int blank_mode, struct fb_info *info)
829 {
830         /* clear DPMS setting */
831         switch (blank_mode) {
832         case FB_BLANK_UNBLANK:
833                 /* Screen On: HSync: On, VSync : On */
834                 smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
835                 smtc_seqw(0x6a, 0x16);
836                 smtc_seqw(0x6b, 0x02);
837                 smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
838                 smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
839                 smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
840                 smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
841                 smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
842                 break;
843         case FB_BLANK_NORMAL:
844                 /* Screen Off: HSync: On, VSync : On   Soft blank */
845                 smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
846                 smtc_seqw(0x6a, 0x16);
847                 smtc_seqw(0x6b, 0x02);
848                 smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
849                 smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
850                 smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
851                 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
852                 break;
853         case FB_BLANK_VSYNC_SUSPEND:
854                 /* Screen On: HSync: On, VSync : Off */
855                 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
856                 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
857                 smtc_seqw(0x6a, 0x0c);
858                 smtc_seqw(0x6b, 0x02);
859                 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
860                 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
861                 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
862                 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
863                 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
864                 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
865                 break;
866         case FB_BLANK_HSYNC_SUSPEND:
867                 /* Screen On: HSync: Off, VSync : On */
868                 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
869                 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
870                 smtc_seqw(0x6a, 0x0c);
871                 smtc_seqw(0x6b, 0x02);
872                 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
873                 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
874                 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
875                 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
876                 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
877                 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
878                 break;
879         case FB_BLANK_POWERDOWN:
880                 /* Screen On: HSync: Off, VSync : Off */
881                 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
882                 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
883                 smtc_seqw(0x6a, 0x0c);
884                 smtc_seqw(0x6b, 0x02);
885                 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
886                 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
887                 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
888                 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
889                 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
890                 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
891                 break;
892         default:
893                 return -EINVAL;
894         }
895
896         return 0;
897 }
898
899 static int smtc_setcolreg(unsigned int regno, unsigned int red,
900                           unsigned int green, unsigned int blue,
901                           unsigned int trans, struct fb_info *info)
902 {
903         struct smtcfb_info *sfb;
904         u32 val;
905
906         sfb = info->par;
907
908         if (regno > 255)
909                 return 1;
910
911         switch (sfb->fb->fix.visual) {
912         case FB_VISUAL_DIRECTCOLOR:
913         case FB_VISUAL_TRUECOLOR:
914                 /*
915                  * 16/32 bit true-colour, use pseudo-palette for 16 base color
916                  */
917                 if (regno >= 16)
918                         break;
919                 if (sfb->fb->var.bits_per_pixel == 16) {
920                         u32 *pal = sfb->fb->pseudo_palette;
921
922                         val = chan_to_field(red, &sfb->fb->var.red);
923                         val |= chan_to_field(green, &sfb->fb->var.green);
924                         val |= chan_to_field(blue, &sfb->fb->var.blue);
925                         pal[regno] = pal_rgb(red, green, blue, val);
926                 } else {
927                         u32 *pal = sfb->fb->pseudo_palette;
928
929                         val = chan_to_field(red, &sfb->fb->var.red);
930                         val |= chan_to_field(green, &sfb->fb->var.green);
931                         val |= chan_to_field(blue, &sfb->fb->var.blue);
932                         pal[regno] = big_swap(val);
933                 }
934                 break;
935
936         case FB_VISUAL_PSEUDOCOLOR:
937                 /* color depth 8 bit */
938                 sm712_setpalette(regno, red, green, blue, info);
939                 break;
940
941         default:
942                 return 1;       /* unknown type */
943         }
944
945         return 0;
946 }
947
948 static ssize_t smtcfb_read(struct fb_info *info, char __user *buf,
949                            size_t count, loff_t *ppos)
950 {
951         unsigned long p = *ppos;
952
953         u32 *buffer, *dst;
954         u32 __iomem *src;
955         int c, i, cnt = 0, err = 0;
956         unsigned long total_size;
957
958         if (!info || !info->screen_base)
959                 return -ENODEV;
960
961         if (info->state != FBINFO_STATE_RUNNING)
962                 return -EPERM;
963
964         total_size = info->screen_size;
965
966         if (total_size == 0)
967                 total_size = info->fix.smem_len;
968
969         if (p >= total_size)
970                 return 0;
971
972         if (count >= total_size)
973                 count = total_size;
974
975         if (count + p > total_size)
976                 count = total_size - p;
977
978         buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
979         if (!buffer)
980                 return -ENOMEM;
981
982         src = (u32 __iomem *)(info->screen_base + p);
983
984         if (info->fbops->fb_sync)
985                 info->fbops->fb_sync(info);
986
987         while (count) {
988                 c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
989                 dst = buffer;
990                 for (i = c >> 2; i--;) {
991                         *dst = fb_readl(src++);
992                         *dst = big_swap(*dst);
993                         dst++;
994                 }
995                 if (c & 3) {
996                         u8 *dst8 = (u8 *)dst;
997                         u8 __iomem *src8 = (u8 __iomem *)src;
998
999                         for (i = c & 3; i--;) {
1000                                 if (i & 1) {
1001                                         *dst8++ = fb_readb(++src8);
1002                                 } else {
1003                                         *dst8++ = fb_readb(--src8);
1004                                         src8 += 2;
1005                                 }
1006                         }
1007                         src = (u32 __iomem *)src8;
1008                 }
1009
1010                 if (copy_to_user(buf, buffer, c)) {
1011                         err = -EFAULT;
1012                         break;
1013                 }
1014                 *ppos += c;
1015                 buf += c;
1016                 cnt += c;
1017                 count -= c;
1018         }
1019
1020         kfree(buffer);
1021
1022         return (err) ? err : cnt;
1023 }
1024
1025 static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
1026                             size_t count, loff_t *ppos)
1027 {
1028         unsigned long p = *ppos;
1029
1030         u32 *buffer, *src;
1031         u32 __iomem *dst;
1032         int c, i, cnt = 0, err = 0;
1033         unsigned long total_size;
1034
1035         if (!info || !info->screen_base)
1036                 return -ENODEV;
1037
1038         if (info->state != FBINFO_STATE_RUNNING)
1039                 return -EPERM;
1040
1041         total_size = info->screen_size;
1042
1043         if (total_size == 0)
1044                 total_size = info->fix.smem_len;
1045
1046         if (p > total_size)
1047                 return -EFBIG;
1048
1049         if (count > total_size) {
1050                 err = -EFBIG;
1051                 count = total_size;
1052         }
1053
1054         if (count + p > total_size) {
1055                 if (!err)
1056                         err = -ENOSPC;
1057
1058                 count = total_size - p;
1059         }
1060
1061         buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
1062         if (!buffer)
1063                 return -ENOMEM;
1064
1065         dst = (u32 __iomem *)(info->screen_base + p);
1066
1067         if (info->fbops->fb_sync)
1068                 info->fbops->fb_sync(info);
1069
1070         while (count) {
1071                 c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1072                 src = buffer;
1073
1074                 if (copy_from_user(src, buf, c)) {
1075                         err = -EFAULT;
1076                         break;
1077                 }
1078
1079                 for (i = c >> 2; i--;) {
1080                         fb_writel(big_swap(*src), dst++);
1081                         src++;
1082                 }
1083                 if (c & 3) {
1084                         u8 *src8 = (u8 *)src;
1085                         u8 __iomem *dst8 = (u8 __iomem *)dst;
1086
1087                         for (i = c & 3; i--;) {
1088                                 if (i & 1) {
1089                                         fb_writeb(*src8++, ++dst8);
1090                                 } else {
1091                                         fb_writeb(*src8++, --dst8);
1092                                         dst8 += 2;
1093                                 }
1094                         }
1095                         dst = (u32 __iomem *)dst8;
1096                 }
1097
1098                 *ppos += c;
1099                 buf += c;
1100                 cnt += c;
1101                 count -= c;
1102         }
1103
1104         kfree(buffer);
1105
1106         return (cnt) ? cnt : err;
1107 }
1108
1109 static void sm7xx_set_timing(struct smtcfb_info *sfb)
1110 {
1111         int i = 0, j = 0;
1112         u32 m_nscreenstride;
1113
1114         dev_dbg(&sfb->pdev->dev,
1115                 "sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n",
1116                 sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz);
1117
1118         for (j = 0; j < ARRAY_SIZE(vgamode); j++) {
1119                 if (vgamode[j].mmsizex != sfb->width ||
1120                     vgamode[j].mmsizey != sfb->height ||
1121                     vgamode[j].bpp != sfb->fb->var.bits_per_pixel ||
1122                     vgamode[j].hz != sfb->hz)
1123                         continue;
1124
1125                 dev_dbg(&sfb->pdev->dev,
1126                         "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
1127                         vgamode[j].mmsizex, vgamode[j].mmsizey,
1128                         vgamode[j].bpp, vgamode[j].hz);
1129
1130                 dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
1131
1132                 smtc_mmiowb(0x0, 0x3c6);
1133
1134                 smtc_seqw(0, 0x1);
1135
1136                 smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
1137
1138                 /* init SEQ register SR00 - SR04 */
1139                 for (i = 0; i < SIZE_SR00_SR04; i++)
1140                         smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
1141
1142                 /* init SEQ register SR10 - SR24 */
1143                 for (i = 0; i < SIZE_SR10_SR24; i++)
1144                         smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]);
1145
1146                 /* init SEQ register SR30 - SR75 */
1147                 for (i = 0; i < SIZE_SR30_SR75; i++)
1148                         if ((i + 0x30) != 0x62 && (i + 0x30) != 0x6a &&
1149                             (i + 0x30) != 0x6b)
1150                                 smtc_seqw(i + 0x30,
1151                                           vgamode[j].init_sr30_sr75[i]);
1152
1153                 /* init SEQ register SR80 - SR93 */
1154                 for (i = 0; i < SIZE_SR80_SR93; i++)
1155                         smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]);
1156
1157                 /* init SEQ register SRA0 - SRAF */
1158                 for (i = 0; i < SIZE_SRA0_SRAF; i++)
1159                         smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]);
1160
1161                 /* init Graphic register GR00 - GR08 */
1162                 for (i = 0; i < SIZE_GR00_GR08; i++)
1163                         smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
1164
1165                 /* init Attribute register AR00 - AR14 */
1166                 for (i = 0; i < SIZE_AR00_AR14; i++)
1167                         smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
1168
1169                 /* init CRTC register CR00 - CR18 */
1170                 for (i = 0; i < SIZE_CR00_CR18; i++)
1171                         smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
1172
1173                 /* init CRTC register CR30 - CR4D */
1174                 for (i = 0; i < SIZE_CR30_CR4D; i++)
1175                         smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
1176
1177                 /* init CRTC register CR90 - CRA7 */
1178                 for (i = 0; i < SIZE_CR90_CRA7; i++)
1179                         smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]);
1180         }
1181         smtc_mmiowb(0x67, 0x3c2);
1182
1183         /* set VPR registers */
1184         writel(0x0, sfb->vp_regs + 0x0C);
1185         writel(0x0, sfb->vp_regs + 0x40);
1186
1187         /* set data width */
1188         m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64;
1189         switch (sfb->fb->var.bits_per_pixel) {
1190         case 8:
1191                 writel(0x0, sfb->vp_regs + 0x0);
1192                 break;
1193         case 16:
1194                 writel(0x00020000, sfb->vp_regs + 0x0);
1195                 break;
1196         case 24:
1197                 writel(0x00040000, sfb->vp_regs + 0x0);
1198                 break;
1199         case 32:
1200                 writel(0x00030000, sfb->vp_regs + 0x0);
1201                 break;
1202         }
1203         writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride),
1204                sfb->vp_regs + 0x10);
1205 }
1206
1207 static void smtc_set_timing(struct smtcfb_info *sfb)
1208 {
1209         switch (sfb->chip_id) {
1210         case 0x710:
1211         case 0x712:
1212         case 0x720:
1213                 sm7xx_set_timing(sfb);
1214                 break;
1215         }
1216 }
1217
1218 static void smtcfb_setmode(struct smtcfb_info *sfb)
1219 {
1220         switch (sfb->fb->var.bits_per_pixel) {
1221         case 32:
1222                 sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1223                 sfb->fb->fix.line_length  = sfb->fb->var.xres * 4;
1224                 sfb->fb->var.red.length   = 8;
1225                 sfb->fb->var.green.length = 8;
1226                 sfb->fb->var.blue.length  = 8;
1227                 sfb->fb->var.red.offset   = 16;
1228                 sfb->fb->var.green.offset = 8;
1229                 sfb->fb->var.blue.offset  = 0;
1230                 break;
1231         case 24:
1232                 sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1233                 sfb->fb->fix.line_length  = sfb->fb->var.xres * 3;
1234                 sfb->fb->var.red.length   = 8;
1235                 sfb->fb->var.green.length = 8;
1236                 sfb->fb->var.blue.length  = 8;
1237                 sfb->fb->var.red.offset   = 16;
1238                 sfb->fb->var.green.offset = 8;
1239                 sfb->fb->var.blue.offset  = 0;
1240                 break;
1241         case 8:
1242                 sfb->fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
1243                 sfb->fb->fix.line_length  = sfb->fb->var.xres;
1244                 sfb->fb->var.red.length   = 3;
1245                 sfb->fb->var.green.length = 3;
1246                 sfb->fb->var.blue.length  = 2;
1247                 sfb->fb->var.red.offset   = 5;
1248                 sfb->fb->var.green.offset = 2;
1249                 sfb->fb->var.blue.offset  = 0;
1250                 break;
1251         case 16:
1252         default:
1253                 sfb->fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1254                 sfb->fb->fix.line_length  = sfb->fb->var.xres * 2;
1255                 sfb->fb->var.red.length   = 5;
1256                 sfb->fb->var.green.length = 6;
1257                 sfb->fb->var.blue.length  = 5;
1258                 sfb->fb->var.red.offset   = 11;
1259                 sfb->fb->var.green.offset = 5;
1260                 sfb->fb->var.blue.offset  = 0;
1261                 break;
1262         }
1263
1264         sfb->width  = sfb->fb->var.xres;
1265         sfb->height = sfb->fb->var.yres;
1266         sfb->hz = 60;
1267         smtc_set_timing(sfb);
1268 }
1269
1270 static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1271 {
1272         /* sanity checks */
1273         if (var->xres_virtual < var->xres)
1274                 var->xres_virtual = var->xres;
1275
1276         if (var->yres_virtual < var->yres)
1277                 var->yres_virtual = var->yres;
1278
1279         /* set valid default bpp */
1280         if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
1281             (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
1282                 var->bits_per_pixel = 16;
1283
1284         return 0;
1285 }
1286
1287 static int smtc_set_par(struct fb_info *info)
1288 {
1289         smtcfb_setmode(info->par);
1290
1291         return 0;
1292 }
1293
1294 static struct fb_ops smtcfb_ops = {
1295         .owner        = THIS_MODULE,
1296         .fb_check_var = smtc_check_var,
1297         .fb_set_par   = smtc_set_par,
1298         .fb_setcolreg = smtc_setcolreg,
1299         .fb_blank     = smtc_blank,
1300         .fb_fillrect  = cfb_fillrect,
1301         .fb_imageblit = cfb_imageblit,
1302         .fb_copyarea  = cfb_copyarea,
1303         .fb_read      = smtcfb_read,
1304         .fb_write     = smtcfb_write,
1305 };
1306
1307 /*
1308  * Unmap in the memory mapped IO registers
1309  */
1310
1311 static void smtc_unmap_mmio(struct smtcfb_info *sfb)
1312 {
1313         if (sfb && smtc_regbaseaddress)
1314                 smtc_regbaseaddress = NULL;
1315 }
1316
1317 /*
1318  * Map in the screen memory
1319  */
1320
1321 static int smtc_map_smem(struct smtcfb_info *sfb,
1322                          struct pci_dev *pdev, u_long smem_len)
1323 {
1324         sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
1325
1326         if (sfb->fb->var.bits_per_pixel == 32)
1327                 sfb->fb->fix.smem_start += big_addr;
1328
1329         sfb->fb->fix.smem_len = smem_len;
1330
1331         sfb->fb->screen_base = sfb->lfb;
1332
1333         if (!sfb->fb->screen_base) {
1334                 dev_err(&pdev->dev,
1335                         "%s: unable to map screen memory\n", sfb->fb->fix.id);
1336                 return -ENOMEM;
1337         }
1338
1339         return 0;
1340 }
1341
1342 /*
1343  * Unmap in the screen memory
1344  *
1345  */
1346 static void smtc_unmap_smem(struct smtcfb_info *sfb)
1347 {
1348         if (sfb && sfb->fb->screen_base) {
1349                 iounmap(sfb->fb->screen_base);
1350                 sfb->fb->screen_base = NULL;
1351         }
1352 }
1353
1354 /*
1355  * We need to wake up the device and make sure its in linear memory mode.
1356  */
1357 static inline void sm7xx_init_hw(void)
1358 {
1359         outb_p(0x18, 0x3c4);
1360         outb_p(0x11, 0x3c5);
1361 }
1362
1363 static int smtcfb_pci_probe(struct pci_dev *pdev,
1364                             const struct pci_device_id *ent)
1365 {
1366         struct smtcfb_info *sfb;
1367         struct fb_info *info;
1368         u_long smem_size = 0x00800000;  /* default 8MB */
1369         int err;
1370         unsigned long mmio_base;
1371
1372         dev_info(&pdev->dev, "Silicon Motion display driver.\n");
1373
1374         err = pci_enable_device(pdev);  /* enable SMTC chip */
1375         if (err)
1376                 return err;
1377
1378         err = pci_request_region(pdev, 0, "sm7xxfb");
1379         if (err < 0) {
1380                 dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
1381                 goto failed_regions;
1382         }
1383
1384         sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
1385
1386         info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
1387         if (!info) {
1388                 dev_err(&pdev->dev, "framebuffer_alloc failed\n");
1389                 err = -ENOMEM;
1390                 goto failed_free;
1391         }
1392
1393         sfb = info->par;
1394         sfb->fb = info;
1395         sfb->chip_id = ent->device;
1396         sfb->pdev = pdev;
1397         info->flags = FBINFO_FLAG_DEFAULT;
1398         info->fbops = &smtcfb_ops;
1399         info->fix = smtcfb_fix;
1400         info->var = smtcfb_var;
1401         info->pseudo_palette = sfb->colreg;
1402         info->par = sfb;
1403
1404         pci_set_drvdata(pdev, sfb);
1405
1406         sm7xx_init_hw();
1407
1408         /* get mode parameter from smtc_scr_info */
1409         if (smtc_scr_info.lfb_width != 0) {
1410                 sfb->fb->var.xres = smtc_scr_info.lfb_width;
1411                 sfb->fb->var.yres = smtc_scr_info.lfb_height;
1412                 sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
1413         } else {
1414                 /* default resolution 1024x600 16bit mode */
1415                 sfb->fb->var.xres = SCREEN_X_RES;
1416                 sfb->fb->var.yres = SCREEN_Y_RES;
1417                 sfb->fb->var.bits_per_pixel = SCREEN_BPP;
1418         }
1419
1420         big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
1421         /* Map address and memory detection */
1422         mmio_base = pci_resource_start(pdev, 0);
1423         pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
1424
1425         switch (sfb->chip_id) {
1426         case 0x710:
1427         case 0x712:
1428                 sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
1429                 sfb->fb->fix.mmio_len = 0x00400000;
1430                 smem_size = SM712_VIDEOMEMORYSIZE;
1431                 sfb->lfb = ioremap(mmio_base, mmio_addr);
1432                 if (!sfb->lfb) {
1433                         dev_err(&pdev->dev,
1434                                 "%s: unable to map memory mapped IO!\n",
1435                                 sfb->fb->fix.id);
1436                         err = -ENOMEM;
1437                         goto failed_fb;
1438                 }
1439
1440                 sfb->mmio = (smtc_regbaseaddress =
1441                     sfb->lfb + 0x00700000);
1442                 sfb->dp_regs = sfb->lfb + 0x00408000;
1443                 sfb->vp_regs = sfb->lfb + 0x0040c000;
1444                 if (sfb->fb->var.bits_per_pixel == 32) {
1445                         sfb->lfb += big_addr;
1446                         dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
1447                 }
1448
1449                 /* set MCLK = 14.31818 * (0x16 / 0x2) */
1450                 smtc_seqw(0x6a, 0x16);
1451                 smtc_seqw(0x6b, 0x02);
1452                 smtc_seqw(0x62, 0x3e);
1453                 /* enable PCI burst */
1454                 smtc_seqw(0x17, 0x20);
1455                 /* enable word swap */
1456                 if (sfb->fb->var.bits_per_pixel == 32)
1457                         seqw17();
1458                 break;
1459         case 0x720:
1460                 sfb->fb->fix.mmio_start = mmio_base;
1461                 sfb->fb->fix.mmio_len = 0x00200000;
1462                 smem_size = SM722_VIDEOMEMORYSIZE;
1463                 sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
1464                 sfb->lfb = sfb->dp_regs + 0x00200000;
1465                 sfb->mmio = (smtc_regbaseaddress =
1466                     sfb->dp_regs + 0x000c0000);
1467                 sfb->vp_regs = sfb->dp_regs + 0x800;
1468
1469                 smtc_seqw(0x62, 0xff);
1470                 smtc_seqw(0x6a, 0x0d);
1471                 smtc_seqw(0x6b, 0x02);
1472                 break;
1473         default:
1474                 dev_err(&pdev->dev,
1475                         "No valid Silicon Motion display chip was detected!\n");
1476
1477                 goto failed_fb;
1478         }
1479
1480         /* can support 32 bpp */
1481         if (sfb->fb->var.bits_per_pixel == 15)
1482                 sfb->fb->var.bits_per_pixel = 16;
1483
1484         sfb->fb->var.xres_virtual = sfb->fb->var.xres;
1485         sfb->fb->var.yres_virtual = sfb->fb->var.yres;
1486         err = smtc_map_smem(sfb, pdev, smem_size);
1487         if (err)
1488                 goto failed;
1489
1490         smtcfb_setmode(sfb);
1491
1492         err = register_framebuffer(info);
1493         if (err < 0)
1494                 goto failed;
1495
1496         dev_info(&pdev->dev,
1497                  "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n",
1498                  sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
1499                  sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
1500
1501         return 0;
1502
1503 failed:
1504         dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n");
1505
1506         smtc_unmap_smem(sfb);
1507         smtc_unmap_mmio(sfb);
1508 failed_fb:
1509         framebuffer_release(info);
1510
1511 failed_free:
1512         pci_release_region(pdev, 0);
1513
1514 failed_regions:
1515         pci_disable_device(pdev);
1516
1517         return err;
1518 }
1519
1520 /*
1521  * 0x710 (LynxEM)
1522  * 0x712 (LynxEM+)
1523  * 0x720 (Lynx3DM, Lynx3DM+)
1524  */
1525 static const struct pci_device_id smtcfb_pci_table[] = {
1526         { PCI_DEVICE(0x126f, 0x710), },
1527         { PCI_DEVICE(0x126f, 0x712), },
1528         { PCI_DEVICE(0x126f, 0x720), },
1529         {0,}
1530 };
1531
1532 MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
1533
1534 static void smtcfb_pci_remove(struct pci_dev *pdev)
1535 {
1536         struct smtcfb_info *sfb;
1537
1538         sfb = pci_get_drvdata(pdev);
1539         smtc_unmap_smem(sfb);
1540         smtc_unmap_mmio(sfb);
1541         unregister_framebuffer(sfb->fb);
1542         framebuffer_release(sfb->fb);
1543         pci_release_region(pdev, 0);
1544         pci_disable_device(pdev);
1545 }
1546
1547 static int __maybe_unused smtcfb_pci_suspend(struct device *device)
1548 {
1549         struct pci_dev *pdev = to_pci_dev(device);
1550         struct smtcfb_info *sfb;
1551
1552         sfb = pci_get_drvdata(pdev);
1553
1554         /* set the hw in sleep mode use external clock and self memory refresh
1555          * so that we can turn off internal PLLs later on
1556          */
1557         smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1558         smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1559
1560         console_lock();
1561         fb_set_suspend(sfb->fb, 1);
1562         console_unlock();
1563
1564         /* additionally turn off all function blocks including internal PLLs */
1565         smtc_seqw(0x21, 0xff);
1566
1567         return 0;
1568 }
1569
1570 static int __maybe_unused smtcfb_pci_resume(struct device *device)
1571 {
1572         struct pci_dev *pdev = to_pci_dev(device);
1573         struct smtcfb_info *sfb;
1574
1575         sfb = pci_get_drvdata(pdev);
1576
1577         /* reinit hardware */
1578         sm7xx_init_hw();
1579         switch (sfb->chip_id) {
1580         case 0x710:
1581         case 0x712:
1582                 /* set MCLK = 14.31818 *  (0x16 / 0x2) */
1583                 smtc_seqw(0x6a, 0x16);
1584                 smtc_seqw(0x6b, 0x02);
1585                 smtc_seqw(0x62, 0x3e);
1586                 /* enable PCI burst */
1587                 smtc_seqw(0x17, 0x20);
1588                 if (sfb->fb->var.bits_per_pixel == 32)
1589                         seqw17();
1590                 break;
1591         case 0x720:
1592                 smtc_seqw(0x62, 0xff);
1593                 smtc_seqw(0x6a, 0x0d);
1594                 smtc_seqw(0x6b, 0x02);
1595                 break;
1596         }
1597
1598         smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1599         smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1600
1601         smtcfb_setmode(sfb);
1602
1603         console_lock();
1604         fb_set_suspend(sfb->fb, 0);
1605         console_unlock();
1606
1607         return 0;
1608 }
1609
1610 static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1611
1612 static struct pci_driver smtcfb_driver = {
1613         .name = "smtcfb",
1614         .id_table = smtcfb_pci_table,
1615         .probe = smtcfb_pci_probe,
1616         .remove = smtcfb_pci_remove,
1617         .driver.pm  = &sm7xx_pm_ops,
1618 };
1619
1620 static int __init sm712fb_init(void)
1621 {
1622         char *option = NULL;
1623
1624         if (fb_get_options("sm712fb", &option))
1625                 return -ENODEV;
1626         if (option && *option)
1627                 mode_option = option;
1628         sm7xx_vga_setup(mode_option);
1629
1630         return pci_register_driver(&smtcfb_driver);
1631 }
1632
1633 module_init(sm712fb_init);
1634
1635 static void __exit sm712fb_exit(void)
1636 {
1637         pci_unregister_driver(&smtcfb_driver);
1638 }
1639
1640 module_exit(sm712fb_exit);
1641
1642 MODULE_AUTHOR("Siliconmotion ");
1643 MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1644 MODULE_LICENSE("GPL");