2 * Silicon Motion SM7XX frame buffer device
4 * Copyright (C) 2006 Silicon Motion Technology Corp.
5 * Authors: Ge Wang, gewang@siliconmotion.com
6 * Boyod boyod.yang@siliconmotion.com.cn
8 * Copyright (C) 2009 Lemote, Inc.
9 * Author: Wu Zhangjin, wuzhangjin@gmail.com
11 * Copyright (C) 2011 Igalia, S.L.
12 * Author: Javier M. Mellid <jmunhoz@igalia.com>
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
18 * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips
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>
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 */
57 void __iomem *smtc_regbaseaddress; /* Memory Map IO starting address */
59 static const struct fb_var_screeninfo smtcfb_var = {
68 .activate = FB_ACTIVATE_NOW,
71 .vmode = FB_VMODE_NONINTERLACED,
73 .accel_flags = FB_ACCELF_TEXT,
76 static struct fb_fix_screeninfo smtcfb_fix = {
78 .type = FB_TYPE_PACKED_PIXELS,
79 .visual = FB_VISUAL_TRUECOLOR,
80 .line_length = 800 * 3,
81 .accel = FB_ACCEL_SMI_LYNX,
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},
101 {"0x311", 640, 480, 16},
102 {"0x314", 800, 600, 16},
103 {"0x317", 1024, 768, 16},
104 {"0x31A", 1280, 1024, 16},
106 {"0x312", 640, 480, 24},
107 {"0x315", 800, 600, 24},
108 {"0x318", 1024, 768, 24},
109 {"0x31B", 1280, 1024, 24},
112 /**********************************************************************
114 **********************************************************************/
115 static const struct modeinit vgamode[] = {
117 /* mode#0: 640 x 480 16Bpp 60Hz */
122 0x03, 0x01, 0x0F, 0x00, 0x0E,
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,
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,
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,
145 { /* Init_SRA0_SRAF */
146 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
147 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
149 { /* Init_GR00_GR08 */
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
177 /* mode#1: 640 x 480 24Bpp 60Hz */
182 0x03, 0x01, 0x0F, 0x00, 0x0E,
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,
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,
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,
205 { /* Init_SRA0_SRAF */
206 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
207 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
209 { /* Init_GR00_GR08 */
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
237 /* mode#0: 640 x 480 32Bpp 60Hz */
242 0x03, 0x01, 0x0F, 0x00, 0x0E,
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,
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,
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,
265 { /* Init_SRA0_SRAF */
266 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
267 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
269 { /* Init_GR00_GR08 */
270 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
297 { /* mode#2: 800 x 600 16Bpp 60Hz */
302 0x03, 0x01, 0x0F, 0x03, 0x0E,
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,
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,
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,
325 { /* Init_SRA0_SRAF */
326 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
327 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
329 { /* Init_GR00_GR08 */
330 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
356 { /* mode#3: 800 x 600 24Bpp 60Hz */
360 0x03, 0x01, 0x0F, 0x03, 0x0E,
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,
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,
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,
383 { /* Init_SRA0_SRAF */
384 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
385 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
387 { /* Init_GR00_GR08 */
388 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
414 { /* mode#7: 800 x 600 32Bpp 60Hz */
419 0x03, 0x01, 0x0F, 0x03, 0x0E,
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,
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,
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,
442 { /* Init_SRA0_SRAF */
443 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
444 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
446 { /* Init_GR00_GR08 */
447 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
473 /* We use 1024x768 table to light 1024x600 panel for lemote */
474 { /* mode#4: 1024 x 600 16Bpp 60Hz */
479 0x03, 0x01, 0x0F, 0x00, 0x0E,
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,
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,
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,
502 { /* Init_SRA0_SRAF */
503 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
504 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
506 { /* Init_GR00_GR08 */
507 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
533 { /* 1024 x 768 16Bpp 60Hz */
538 0x03, 0x01, 0x0F, 0x03, 0x0E,
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,
545 { /* Init_SR30_SR75 */
546 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
547 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
548 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
549 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
550 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
551 0x0F, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
552 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
553 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
554 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
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,
561 { /* Init_SRA0_SRAF */
562 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
563 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
565 { /* Init_GR00_GR08 */
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
592 { /* mode#5: 1024 x 768 24Bpp 60Hz */
597 0x03, 0x01, 0x0F, 0x03, 0x0E,
599 { /* Init_SR10_SR24 */
600 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
601 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
602 0xC4, 0x30, 0x02, 0x01, 0x01,
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,
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,
620 { /* Init_SRA0_SRAF */
621 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
622 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
624 { /* Init_GR00_GR08 */
625 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
651 { /* mode#4: 1024 x 768 32Bpp 60Hz */
656 0x03, 0x01, 0x0F, 0x03, 0x0E,
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,
663 { /* Init_SR30_SR75 */
664 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
665 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
666 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
667 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
668 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
669 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
670 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
671 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
672 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
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,
679 { /* Init_SRA0_SRAF */
680 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
681 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
683 { /* Init_GR00_GR08 */
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
698 { /* Init_CR30_CR4D */
699 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
700 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
701 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
702 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
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,
710 { /* mode#6: 320 x 240 16Bpp 60Hz */
715 0x03, 0x01, 0x0F, 0x03, 0x0E,
717 { /* Init_SR10_SR24 */
718 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
719 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
720 0xC4, 0x32, 0x02, 0x01, 0x01,
722 { /* Init_SR30_SR75 */
723 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
724 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
725 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
726 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
727 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
728 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
729 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
730 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
731 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
733 { /* Init_SR80_SR93 */
734 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
735 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
736 0x00, 0x00, 0x00, 0x00,
738 { /* Init_SRA0_SRAF */
739 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
740 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
742 { /* Init_GR00_GR08 */
743 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
746 { /* Init_AR00_AR14 */
747 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
748 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
749 0x41, 0x00, 0x0F, 0x00, 0x00,
751 { /* Init_CR00_CR18 */
752 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
753 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
754 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
757 { /* Init_CR30_CR4D */
758 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
759 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
760 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
761 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
763 { /* Init_CR90_CRA7 */
764 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
765 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
766 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
770 { /* mode#8: 320 x 240 32Bpp 60Hz */
775 0x03, 0x01, 0x0F, 0x03, 0x0E,
777 { /* Init_SR10_SR24 */
778 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
779 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
780 0xC4, 0x32, 0x02, 0x01, 0x01,
782 { /* Init_SR30_SR75 */
783 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
784 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
785 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
786 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
787 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
788 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
789 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
790 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
791 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
793 { /* Init_SR80_SR93 */
794 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
795 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
796 0x00, 0x00, 0x00, 0x00,
798 { /* Init_SRA0_SRAF */
799 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
800 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
802 { /* Init_GR00_GR08 */
803 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
806 { /* Init_AR00_AR14 */
807 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
808 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
809 0x41, 0x00, 0x0F, 0x00, 0x00,
811 { /* Init_CR00_CR18 */
812 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
813 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
817 { /* Init_CR30_CR4D */
818 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
819 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
820 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
821 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
823 { /* Init_CR90_CRA7 */
824 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
825 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
826 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
831 static struct screen_info smtc_scr_info;
833 static char *mode_option;
835 /* process command line options, get vga parameter */
836 static void __init sm7xx_vga_setup(char *options)
840 if (!options || !*options)
843 smtc_scr_info.lfb_width = 0;
844 smtc_scr_info.lfb_height = 0;
845 smtc_scr_info.lfb_depth = 0;
847 pr_debug("sm7xx_vga_setup = %s\n", options);
849 for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
850 if (strstr(options, vesa_mode_table[i].index)) {
851 smtc_scr_info.lfb_width = vesa_mode_table[i].lfb_width;
852 smtc_scr_info.lfb_height =
853 vesa_mode_table[i].lfb_height;
854 smtc_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth;
860 static void sm712_setpalette(int regno, unsigned red, unsigned green,
861 unsigned blue, struct fb_info *info)
863 /* set bit 5:4 = 01 (write LCD RAM only) */
864 smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
866 smtc_mmiowb(regno, dac_reg);
867 smtc_mmiowb(red >> 10, dac_val);
868 smtc_mmiowb(green >> 10, dac_val);
869 smtc_mmiowb(blue >> 10, dac_val);
874 * convert a colour value into a field position
879 static inline unsigned int chan_to_field(unsigned int chan,
880 struct fb_bitfield *bf)
883 chan >>= 16 - bf->length;
884 return chan << bf->offset;
887 static int smtc_blank(int blank_mode, struct fb_info *info)
889 struct smtcfb_info *sfb = info->par;
891 /* clear DPMS setting */
892 switch (blank_mode) {
893 case FB_BLANK_UNBLANK:
894 /* Screen On: HSync: On, VSync : On */
896 switch (sfb->chip_id) {
899 smtc_seqw(0x6a, 0x16);
900 smtc_seqw(0x6b, 0x02);
903 smtc_seqw(0x6a, 0x0d);
904 smtc_seqw(0x6b, 0x02);
908 smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
909 smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
910 smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
911 smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
912 smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
913 smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
915 case FB_BLANK_NORMAL:
916 /* Screen Off: HSync: On, VSync : On Soft blank */
917 smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
918 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
919 smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
920 smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
921 smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
922 smtc_seqw(0x6a, 0x16);
923 smtc_seqw(0x6b, 0x02);
925 case FB_BLANK_VSYNC_SUSPEND:
926 /* Screen On: HSync: On, VSync : Off */
927 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
928 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
929 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
930 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
931 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
932 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
933 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
934 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
935 smtc_seqw(0x6a, 0x0c);
936 smtc_seqw(0x6b, 0x02);
938 case FB_BLANK_HSYNC_SUSPEND:
939 /* Screen On: HSync: Off, VSync : On */
940 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
941 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
942 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
943 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
944 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
945 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
946 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
947 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
948 smtc_seqw(0x6a, 0x0c);
949 smtc_seqw(0x6b, 0x02);
951 case FB_BLANK_POWERDOWN:
952 /* Screen On: HSync: Off, VSync : Off */
953 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
954 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
955 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
956 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
957 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
958 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
959 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
960 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
961 smtc_seqw(0x6a, 0x0c);
962 smtc_seqw(0x6b, 0x02);
971 static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
972 unsigned blue, unsigned trans, struct fb_info *info)
974 struct smtcfb_info *sfb;
982 switch (sfb->fb->fix.visual) {
983 case FB_VISUAL_DIRECTCOLOR:
984 case FB_VISUAL_TRUECOLOR:
986 * 16/32 bit true-colour, use pseudo-palette for 16 base color
990 if (sfb->fb->var.bits_per_pixel == 16) {
991 u32 *pal = sfb->fb->pseudo_palette;
993 val = chan_to_field(red, &sfb->fb->var.red);
994 val |= chan_to_field(green, &sfb->fb->var.green);
995 val |= chan_to_field(blue, &sfb->fb->var.blue);
996 pal[regno] = pal_rgb(red, green, blue, val);
998 u32 *pal = sfb->fb->pseudo_palette;
1000 val = chan_to_field(red, &sfb->fb->var.red);
1001 val |= chan_to_field(green, &sfb->fb->var.green);
1002 val |= chan_to_field(blue, &sfb->fb->var.blue);
1003 pal[regno] = big_swap(val);
1007 case FB_VISUAL_PSEUDOCOLOR:
1008 /* color depth 8 bit */
1009 sm712_setpalette(regno, red, green, blue, info);
1013 return 1; /* unknown type */
1019 static ssize_t smtcfb_read(struct fb_info *info, char __user *buf,
1020 size_t count, loff_t *ppos)
1022 unsigned long p = *ppos;
1026 int c, i, cnt = 0, err = 0;
1027 unsigned long total_size;
1029 if (!info || !info->screen_base)
1032 if (info->state != FBINFO_STATE_RUNNING)
1035 total_size = info->screen_size;
1037 if (total_size == 0)
1038 total_size = info->fix.smem_len;
1040 if (p >= total_size)
1043 if (count >= total_size)
1046 if (count + p > total_size)
1047 count = total_size - p;
1049 buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
1053 src = (u32 __iomem *)(info->screen_base + p);
1055 if (info->fbops->fb_sync)
1056 info->fbops->fb_sync(info);
1059 c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1061 for (i = (c + 3) >> 2; i--;) {
1064 val = fb_readl(src);
1065 *dst = big_swap(val);
1070 if (copy_to_user(buf, buffer, c)) {
1082 return (err) ? err : cnt;
1085 static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
1086 size_t count, loff_t *ppos)
1088 unsigned long p = *ppos;
1092 int c, i, cnt = 0, err = 0;
1093 unsigned long total_size;
1095 if (!info || !info->screen_base)
1098 if (info->state != FBINFO_STATE_RUNNING)
1101 total_size = info->screen_size;
1103 if (total_size == 0)
1104 total_size = info->fix.smem_len;
1109 if (count > total_size) {
1114 if (count + p > total_size) {
1118 count = total_size - p;
1121 buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
1125 dst = (u32 __iomem *)(info->screen_base + p);
1127 if (info->fbops->fb_sync)
1128 info->fbops->fb_sync(info);
1131 c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1134 if (copy_from_user(src, buf, c)) {
1139 for (i = (c + 3) >> 2; i--;) {
1140 fb_writel(big_swap(*src), dst);
1153 return (cnt) ? cnt : err;
1156 static void sm7xx_set_timing(struct smtcfb_info *sfb)
1159 u32 m_nscreenstride;
1161 dev_dbg(&sfb->pdev->dev,
1162 "sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n",
1163 sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz);
1165 for (j = 0; j < ARRAY_SIZE(vgamode); j++) {
1166 if (vgamode[j].mmsizex != sfb->width ||
1167 vgamode[j].mmsizey != sfb->height ||
1168 vgamode[j].bpp != sfb->fb->var.bits_per_pixel ||
1169 vgamode[j].hz != sfb->hz)
1172 dev_dbg(&sfb->pdev->dev,
1173 "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
1174 vgamode[j].mmsizex, vgamode[j].mmsizey,
1175 vgamode[j].bpp, vgamode[j].hz);
1177 dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
1179 smtc_mmiowb(0x0, 0x3c6);
1183 smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
1185 /* init SEQ register SR00 - SR04 */
1186 for (i = 0; i < SIZE_SR00_SR04; i++)
1187 smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
1189 /* init SEQ register SR10 - SR24 */
1190 for (i = 0; i < SIZE_SR10_SR24; i++)
1191 smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]);
1193 /* init SEQ register SR30 - SR75 */
1194 for (i = 0; i < SIZE_SR30_SR75; i++)
1195 if ((i + 0x30) != 0x30 && (i + 0x30) != 0x62 &&
1196 (i + 0x30) != 0x6a && (i + 0x30) != 0x6b &&
1197 (i + 0x30) != 0x70 && (i + 0x30) != 0x71 &&
1198 (i + 0x30) != 0x74 && (i + 0x30) != 0x75)
1200 vgamode[j].init_sr30_sr75[i]);
1202 /* init SEQ register SR80 - SR93 */
1203 for (i = 0; i < SIZE_SR80_SR93; i++)
1204 smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]);
1206 /* init SEQ register SRA0 - SRAF */
1207 for (i = 0; i < SIZE_SRA0_SRAF; i++)
1208 smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]);
1210 /* init Graphic register GR00 - GR08 */
1211 for (i = 0; i < SIZE_GR00_GR08; i++)
1212 smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
1214 /* init Attribute register AR00 - AR14 */
1215 for (i = 0; i < SIZE_AR00_AR14; i++)
1216 smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
1218 /* init CRTC register CR00 - CR18 */
1219 for (i = 0; i < SIZE_CR00_CR18; i++)
1220 smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
1222 /* init CRTC register CR30 - CR4D */
1223 for (i = 0; i < SIZE_CR30_CR4D; i++) {
1224 if ((i + 0x30) >= 0x3B && (i + 0x30) <= 0x3F)
1225 /* side-effect, don't write to CR3B-CR3F */
1227 smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
1230 /* init CRTC register CR90 - CRA7 */
1231 for (i = 0; i < SIZE_CR90_CRA7; i++)
1232 smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]);
1234 smtc_mmiowb(0x67, 0x3c2);
1236 /* set VPR registers */
1237 writel(0x0, sfb->vp_regs + 0x0C);
1238 writel(0x0, sfb->vp_regs + 0x40);
1240 /* set data width */
1241 m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64;
1242 switch (sfb->fb->var.bits_per_pixel) {
1244 writel(0x0, sfb->vp_regs + 0x0);
1247 writel(0x00020000, sfb->vp_regs + 0x0);
1250 writel(0x00040000, sfb->vp_regs + 0x0);
1253 writel(0x00030000, sfb->vp_regs + 0x0);
1256 writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride),
1257 sfb->vp_regs + 0x10);
1260 static void smtc_set_timing(struct smtcfb_info *sfb)
1262 switch (sfb->chip_id) {
1266 sm7xx_set_timing(sfb);
1271 static void smtcfb_setmode(struct smtcfb_info *sfb)
1273 switch (sfb->fb->var.bits_per_pixel) {
1275 sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR;
1276 sfb->fb->fix.line_length = sfb->fb->var.xres * 4;
1277 sfb->fb->var.red.length = 8;
1278 sfb->fb->var.green.length = 8;
1279 sfb->fb->var.blue.length = 8;
1280 sfb->fb->var.red.offset = 16;
1281 sfb->fb->var.green.offset = 8;
1282 sfb->fb->var.blue.offset = 0;
1285 sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR;
1286 sfb->fb->fix.line_length = sfb->fb->var.xres * 3;
1287 sfb->fb->var.red.length = 8;
1288 sfb->fb->var.green.length = 8;
1289 sfb->fb->var.blue.length = 8;
1290 sfb->fb->var.red.offset = 16;
1291 sfb->fb->var.green.offset = 8;
1292 sfb->fb->var.blue.offset = 0;
1295 sfb->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
1296 sfb->fb->fix.line_length = sfb->fb->var.xres;
1297 sfb->fb->var.red.length = 3;
1298 sfb->fb->var.green.length = 3;
1299 sfb->fb->var.blue.length = 2;
1300 sfb->fb->var.red.offset = 5;
1301 sfb->fb->var.green.offset = 2;
1302 sfb->fb->var.blue.offset = 0;
1306 sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR;
1307 sfb->fb->fix.line_length = sfb->fb->var.xres * 2;
1308 sfb->fb->var.red.length = 5;
1309 sfb->fb->var.green.length = 6;
1310 sfb->fb->var.blue.length = 5;
1311 sfb->fb->var.red.offset = 11;
1312 sfb->fb->var.green.offset = 5;
1313 sfb->fb->var.blue.offset = 0;
1317 sfb->width = sfb->fb->var.xres;
1318 sfb->height = sfb->fb->var.yres;
1320 smtc_set_timing(sfb);
1323 static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1326 if (var->xres_virtual < var->xres)
1327 var->xres_virtual = var->xres;
1329 if (var->yres_virtual < var->yres)
1330 var->yres_virtual = var->yres;
1332 /* set valid default bpp */
1333 if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) &&
1334 (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
1335 var->bits_per_pixel = 16;
1340 static int smtc_set_par(struct fb_info *info)
1342 smtcfb_setmode(info->par);
1347 static struct fb_ops smtcfb_ops = {
1348 .owner = THIS_MODULE,
1349 .fb_check_var = smtc_check_var,
1350 .fb_set_par = smtc_set_par,
1351 .fb_setcolreg = smtc_setcolreg,
1352 .fb_blank = smtc_blank,
1353 .fb_fillrect = cfb_fillrect,
1354 .fb_imageblit = cfb_imageblit,
1355 .fb_copyarea = cfb_copyarea,
1356 .fb_read = smtcfb_read,
1357 .fb_write = smtcfb_write,
1361 * Unmap in the memory mapped IO registers
1364 static void smtc_unmap_mmio(struct smtcfb_info *sfb)
1366 if (sfb && smtc_regbaseaddress)
1367 smtc_regbaseaddress = NULL;
1371 * Map in the screen memory
1374 static int smtc_map_smem(struct smtcfb_info *sfb,
1375 struct pci_dev *pdev, u_long smem_len)
1377 sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
1379 if (sfb->chip_id == 0x720)
1380 /* on SM720, the framebuffer starts at the 1 MB offset */
1381 sfb->fb->fix.smem_start += 0x00200000;
1383 /* XXX: is it safe for SM720 on Big-Endian? */
1384 if (sfb->fb->var.bits_per_pixel == 32)
1385 sfb->fb->fix.smem_start += big_addr;
1387 sfb->fb->fix.smem_len = smem_len;
1389 sfb->fb->screen_base = sfb->lfb;
1391 if (!sfb->fb->screen_base) {
1393 "%s: unable to map screen memory\n", sfb->fb->fix.id);
1401 * Unmap in the screen memory
1404 static void smtc_unmap_smem(struct smtcfb_info *sfb)
1406 if (sfb && sfb->fb->screen_base) {
1407 if (sfb->chip_id == 0x720)
1408 sfb->fb->screen_base -= 0x00200000;
1409 iounmap(sfb->fb->screen_base);
1410 sfb->fb->screen_base = NULL;
1415 * We need to wake up the device and make sure its in linear memory mode.
1417 static inline void sm7xx_init_hw(void)
1419 outb_p(0x18, 0x3c4);
1420 outb_p(0x11, 0x3c5);
1423 static u_long sm7xx_vram_probe(struct smtcfb_info *sfb)
1427 switch (sfb->chip_id) {
1431 * Assume SM712 graphics chip has 4MB VRAM.
1433 * FIXME: SM712 can have 2MB VRAM, which is used on earlier
1434 * laptops, such as IBM Thinkpad 240X. This driver would
1435 * probably crash on those machines. If anyone gets one of
1436 * those and is willing to help, run "git blame" and send me
1441 outb_p(0x76, 0x3c4);
1442 vram = inb_p(0x3c5) >> 6;
1445 return 0x00800000; /* 8 MB */
1446 else if (vram == 0x01)
1447 return 0x01000000; /* 16 MB */
1448 else if (vram == 0x02)
1449 return 0x00400000; /* illegal, fallback to 4 MB */
1450 else if (vram == 0x03)
1451 return 0x00400000; /* 4 MB */
1453 return 0; /* unknown hardware */
1456 static void sm7xx_resolution_probe(struct smtcfb_info *sfb)
1458 /* get mode parameter from smtc_scr_info */
1459 if (smtc_scr_info.lfb_width != 0) {
1460 sfb->fb->var.xres = smtc_scr_info.lfb_width;
1461 sfb->fb->var.yres = smtc_scr_info.lfb_height;
1462 sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
1467 * No parameter, default resolution is 1024x768-16.
1469 * FIXME: earlier laptops, such as IBM Thinkpad 240X, has a 800x600
1470 * panel, also see the comments about Thinkpad 240X above.
1472 sfb->fb->var.xres = SCREEN_X_RES;
1473 sfb->fb->var.yres = SCREEN_Y_RES_PC;
1474 sfb->fb->var.bits_per_pixel = SCREEN_BPP;
1478 * Loongson MIPS netbooks use 1024x600 LCD panels, which is the original
1479 * target platform of this driver, but nearly all old x86 laptops have
1480 * 1024x768. Lighting 768 panels using 600's timings would partially
1481 * garble the display, so we don't want that. But it's not possible to
1482 * distinguish them reliably.
1484 * So we change the default to 768, but keep 600 as-is on MIPS.
1486 sfb->fb->var.yres = SCREEN_Y_RES_NETBOOK;
1490 big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
1493 static int smtcfb_pci_probe(struct pci_dev *pdev,
1494 const struct pci_device_id *ent)
1496 struct smtcfb_info *sfb;
1497 struct fb_info *info;
1500 unsigned long mmio_base;
1502 dev_info(&pdev->dev, "Silicon Motion display driver.\n");
1504 err = pci_enable_device(pdev); /* enable SMTC chip */
1508 err = pci_request_region(pdev, 0, "sm7xxfb");
1510 dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
1511 goto failed_regions;
1514 sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
1516 info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
1518 dev_err(&pdev->dev, "framebuffer_alloc failed\n");
1525 sfb->chip_id = ent->device;
1527 info->flags = FBINFO_FLAG_DEFAULT;
1528 info->fbops = &smtcfb_ops;
1529 info->fix = smtcfb_fix;
1530 info->var = smtcfb_var;
1531 info->pseudo_palette = sfb->colreg;
1534 pci_set_drvdata(pdev, sfb);
1538 /* Map address and memory detection */
1539 mmio_base = pci_resource_start(pdev, 0);
1540 pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
1542 smem_size = sm7xx_vram_probe(sfb);
1543 dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n",
1544 smem_size / 1048576);
1546 switch (sfb->chip_id) {
1549 sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
1550 sfb->fb->fix.mmio_len = 0x00400000;
1551 sfb->lfb = ioremap(mmio_base, mmio_addr);
1554 "%s: unable to map memory mapped IO!\n",
1560 sfb->mmio = (smtc_regbaseaddress =
1561 sfb->lfb + 0x00700000);
1562 sfb->dp_regs = sfb->lfb + 0x00408000;
1563 sfb->vp_regs = sfb->lfb + 0x0040c000;
1564 if (sfb->fb->var.bits_per_pixel == 32) {
1565 sfb->lfb += big_addr;
1566 dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
1569 /* set MCLK = 14.31818 * (0x16 / 0x2) */
1570 smtc_seqw(0x6a, 0x16);
1571 smtc_seqw(0x6b, 0x02);
1572 smtc_seqw(0x62, 0x3e);
1573 /* enable PCI burst */
1574 smtc_seqw(0x17, 0x20);
1575 /* enable word swap */
1576 if (sfb->fb->var.bits_per_pixel == 32)
1580 sfb->fb->fix.mmio_start = mmio_base;
1581 sfb->fb->fix.mmio_len = 0x00200000;
1582 sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
1583 sfb->lfb = sfb->dp_regs + 0x00200000;
1584 sfb->mmio = (smtc_regbaseaddress =
1585 sfb->dp_regs + 0x000c0000);
1586 sfb->vp_regs = sfb->dp_regs + 0x800;
1588 smtc_seqw(0x62, 0xff);
1589 smtc_seqw(0x6a, 0x0d);
1590 smtc_seqw(0x6b, 0x02);
1594 "No valid Silicon Motion display chip was detected!\n");
1599 /* probe and decide resolution */
1600 sm7xx_resolution_probe(sfb);
1602 /* can support 32 bpp */
1603 if (15 == sfb->fb->var.bits_per_pixel)
1604 sfb->fb->var.bits_per_pixel = 16;
1606 sfb->fb->var.xres_virtual = sfb->fb->var.xres;
1607 sfb->fb->var.yres_virtual = sfb->fb->var.yres;
1608 err = smtc_map_smem(sfb, pdev, smem_size);
1613 * The screen would be temporarily garbled when sm712fb takes over
1614 * vesafb or VGA text mode. Zero the framebuffer.
1616 memset_io(sfb->lfb, 0, sfb->fb->fix.smem_len);
1618 err = register_framebuffer(info);
1622 dev_info(&pdev->dev,
1623 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n",
1624 sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
1625 sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
1630 dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n");
1632 smtc_unmap_smem(sfb);
1633 smtc_unmap_mmio(sfb);
1635 framebuffer_release(info);
1638 pci_release_region(pdev, 0);
1641 pci_disable_device(pdev);
1649 * 0x720 (Lynx3DM, Lynx3DM+)
1651 static const struct pci_device_id smtcfb_pci_table[] = {
1652 { PCI_DEVICE(0x126f, 0x710), },
1653 { PCI_DEVICE(0x126f, 0x712), },
1654 { PCI_DEVICE(0x126f, 0x720), },
1658 MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
1660 static void smtcfb_pci_remove(struct pci_dev *pdev)
1662 struct smtcfb_info *sfb;
1664 sfb = pci_get_drvdata(pdev);
1665 smtc_unmap_smem(sfb);
1666 smtc_unmap_mmio(sfb);
1667 unregister_framebuffer(sfb->fb);
1668 framebuffer_release(sfb->fb);
1669 pci_release_region(pdev, 0);
1670 pci_disable_device(pdev);
1673 static int __maybe_unused smtcfb_pci_suspend(struct device *device)
1675 struct pci_dev *pdev = to_pci_dev(device);
1676 struct smtcfb_info *sfb;
1678 sfb = pci_get_drvdata(pdev);
1680 /* set the hw in sleep mode use external clock and self memory refresh
1681 * so that we can turn off internal PLLs later on
1683 smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1684 smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1687 fb_set_suspend(sfb->fb, 1);
1690 /* additionally turn off all function blocks including internal PLLs */
1691 smtc_seqw(0x21, 0xff);
1696 static int __maybe_unused smtcfb_pci_resume(struct device *device)
1698 struct pci_dev *pdev = to_pci_dev(device);
1699 struct smtcfb_info *sfb;
1701 sfb = pci_get_drvdata(pdev);
1703 /* reinit hardware */
1705 switch (sfb->chip_id) {
1708 /* set MCLK = 14.31818 * (0x16 / 0x2) */
1709 smtc_seqw(0x6a, 0x16);
1710 smtc_seqw(0x6b, 0x02);
1711 smtc_seqw(0x62, 0x3e);
1712 /* enable PCI burst */
1713 smtc_seqw(0x17, 0x20);
1714 if (sfb->fb->var.bits_per_pixel == 32)
1718 smtc_seqw(0x62, 0xff);
1719 smtc_seqw(0x6a, 0x0d);
1720 smtc_seqw(0x6b, 0x02);
1724 smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1725 smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1727 smtcfb_setmode(sfb);
1730 fb_set_suspend(sfb->fb, 0);
1736 static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1738 static struct pci_driver smtcfb_driver = {
1740 .id_table = smtcfb_pci_table,
1741 .probe = smtcfb_pci_probe,
1742 .remove = smtcfb_pci_remove,
1743 .driver.pm = &sm7xx_pm_ops,
1746 static int __init sm712fb_init(void)
1748 char *option = NULL;
1750 if (fb_get_options("sm712fb", &option))
1752 if (option && *option)
1753 mode_option = option;
1754 sm7xx_vga_setup(mode_option);
1756 return pci_register_driver(&smtcfb_driver);
1759 module_init(sm712fb_init);
1761 static void __exit sm712fb_exit(void)
1763 pci_unregister_driver(&smtcfb_driver);
1766 module_exit(sm712fb_exit);
1768 MODULE_AUTHOR("Siliconmotion ");
1769 MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1770 MODULE_LICENSE("GPL");