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