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
21 #include <linux/aperture.h>
24 #include <linux/pci.h>
25 #include <linux/init.h>
26 #include <linux/slab.h>
27 #include <linux/uaccess.h>
28 #include <linux/module.h>
29 #include <linux/console.h>
30 #include <linux/screen_info.h>
45 void __iomem *lfb; /* linear frame buffer */
46 void __iomem *dp_regs; /* drawing processor control regs */
47 void __iomem *vp_regs; /* video processor control regs */
48 void __iomem *cp_regs; /* capture processor control regs */
49 void __iomem *mmio; /* memory map IO port */
58 void __iomem *smtc_regbaseaddress; /* Memory Map IO starting address */
60 static const struct fb_var_screeninfo smtcfb_var = {
69 .activate = FB_ACTIVATE_NOW,
72 .vmode = FB_VMODE_NONINTERLACED,
74 .accel_flags = FB_ACCELF_TEXT,
77 static struct fb_fix_screeninfo smtcfb_fix = {
79 .type = FB_TYPE_PACKED_PIXELS,
80 .visual = FB_VISUAL_TRUECOLOR,
81 .line_length = 800 * 3,
82 .accel = FB_ACCEL_SMI_LYNX,
96 static const struct vesa_mode vesa_mode_table[] = {
97 {"0x301", 640, 480, 8},
98 {"0x303", 800, 600, 8},
99 {"0x305", 1024, 768, 8},
100 {"0x307", 1280, 1024, 8},
102 {"0x311", 640, 480, 16},
103 {"0x314", 800, 600, 16},
104 {"0x317", 1024, 768, 16},
105 {"0x31A", 1280, 1024, 16},
107 {"0x312", 640, 480, 24},
108 {"0x315", 800, 600, 24},
109 {"0x318", 1024, 768, 24},
110 {"0x31B", 1280, 1024, 24},
113 /**********************************************************************
115 **********************************************************************/
116 static const struct modeinit vgamode[] = {
118 /* mode#0: 640 x 480 16Bpp 60Hz */
123 0x03, 0x01, 0x0F, 0x00, 0x0E,
125 { /* Init_SR10_SR24 */
126 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
127 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128 0xC4, 0x30, 0x02, 0x01, 0x01,
130 { /* Init_SR30_SR75 */
131 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
132 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
133 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
134 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
135 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
136 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
137 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
138 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
139 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
141 { /* Init_SR80_SR93 */
142 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
143 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
144 0x00, 0x00, 0x00, 0x00,
146 { /* Init_SRA0_SRAF */
147 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
148 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
150 { /* Init_GR00_GR08 */
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
154 { /* Init_AR00_AR14 */
155 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
156 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
157 0x41, 0x00, 0x0F, 0x00, 0x00,
159 { /* Init_CR00_CR18 */
160 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
161 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
165 { /* Init_CR30_CR4D */
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
167 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
168 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
169 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
171 { /* Init_CR90_CRA7 */
172 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
173 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
174 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
178 /* mode#1: 640 x 480 24Bpp 60Hz */
183 0x03, 0x01, 0x0F, 0x00, 0x0E,
185 { /* Init_SR10_SR24 */
186 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
187 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188 0xC4, 0x30, 0x02, 0x01, 0x01,
190 { /* Init_SR30_SR75 */
191 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
192 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
193 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
194 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
195 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
196 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
197 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
198 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
199 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
201 { /* Init_SR80_SR93 */
202 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
203 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
204 0x00, 0x00, 0x00, 0x00,
206 { /* Init_SRA0_SRAF */
207 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
208 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
210 { /* Init_GR00_GR08 */
211 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
214 { /* Init_AR00_AR14 */
215 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
216 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
217 0x41, 0x00, 0x0F, 0x00, 0x00,
219 { /* Init_CR00_CR18 */
220 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
221 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
225 { /* Init_CR30_CR4D */
226 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
227 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
228 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
229 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
231 { /* Init_CR90_CRA7 */
232 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
233 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
234 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
238 /* mode#0: 640 x 480 32Bpp 60Hz */
243 0x03, 0x01, 0x0F, 0x00, 0x0E,
245 { /* Init_SR10_SR24 */
246 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
247 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 0xC4, 0x30, 0x02, 0x01, 0x01,
250 { /* Init_SR30_SR75 */
251 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
252 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
253 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
254 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
255 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
256 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
257 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
258 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
259 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
261 { /* Init_SR80_SR93 */
262 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
263 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
264 0x00, 0x00, 0x00, 0x00,
266 { /* Init_SRA0_SRAF */
267 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
268 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
270 { /* Init_GR00_GR08 */
271 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
274 { /* Init_AR00_AR14 */
275 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
276 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
277 0x41, 0x00, 0x0F, 0x00, 0x00,
279 { /* Init_CR00_CR18 */
280 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
281 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
285 { /* Init_CR30_CR4D */
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
287 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
288 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
289 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
291 { /* Init_CR90_CRA7 */
292 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
293 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
294 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
298 { /* mode#2: 800 x 600 16Bpp 60Hz */
303 0x03, 0x01, 0x0F, 0x03, 0x0E,
305 { /* Init_SR10_SR24 */
306 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
307 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0xC4, 0x30, 0x02, 0x01, 0x01,
310 { /* Init_SR30_SR75 */
311 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
312 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
313 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
314 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
315 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
316 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
317 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
318 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
319 0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
321 { /* Init_SR80_SR93 */
322 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
323 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
324 0x00, 0x00, 0x00, 0x00,
326 { /* Init_SRA0_SRAF */
327 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
328 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
330 { /* Init_GR00_GR08 */
331 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
334 { /* Init_AR00_AR14 */
335 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
336 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
337 0x41, 0x00, 0x0F, 0x00, 0x00,
339 { /* Init_CR00_CR18 */
340 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
341 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
345 { /* Init_CR30_CR4D */
346 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
347 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
348 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
349 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
351 { /* Init_CR90_CRA7 */
352 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
353 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
354 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
357 { /* mode#3: 800 x 600 24Bpp 60Hz */
361 0x03, 0x01, 0x0F, 0x03, 0x0E,
363 { /* Init_SR10_SR24 */
364 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
365 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366 0xC4, 0x30, 0x02, 0x01, 0x01,
368 { /* Init_SR30_SR75 */
369 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36,
370 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF,
371 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
372 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36,
373 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
374 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36,
375 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
376 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
377 0x02, 0x45, 0x30, 0x30, 0x40, 0x20,
379 { /* Init_SR80_SR93 */
380 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36,
381 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36,
382 0x00, 0x00, 0x00, 0x00,
384 { /* Init_SRA0_SRAF */
385 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
386 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
388 { /* Init_GR00_GR08 */
389 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
392 { /* Init_AR00_AR14 */
393 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
394 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
395 0x41, 0x00, 0x0F, 0x00, 0x00,
397 { /* Init_CR00_CR18 */
398 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
399 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
403 { /* Init_CR30_CR4D */
404 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
405 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
406 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
407 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
409 { /* Init_CR90_CRA7 */
410 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
411 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
412 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
415 { /* mode#7: 800 x 600 32Bpp 60Hz */
420 0x03, 0x01, 0x0F, 0x03, 0x0E,
422 { /* Init_SR10_SR24 */
423 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
424 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
425 0xC4, 0x30, 0x02, 0x01, 0x01,
427 { /* Init_SR30_SR75 */
428 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
429 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
430 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
431 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
432 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
433 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
434 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
435 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
436 0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
438 { /* Init_SR80_SR93 */
439 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
440 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
441 0x00, 0x00, 0x00, 0x00,
443 { /* Init_SRA0_SRAF */
444 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
445 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
447 { /* Init_GR00_GR08 */
448 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
451 { /* Init_AR00_AR14 */
452 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
453 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
454 0x41, 0x00, 0x0F, 0x00, 0x00,
456 { /* Init_CR00_CR18 */
457 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
458 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
459 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
462 { /* Init_CR30_CR4D */
463 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
464 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
465 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
466 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
468 { /* Init_CR90_CRA7 */
469 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
470 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
471 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
474 /* We use 1024x768 table to light 1024x600 panel for lemote */
475 { /* mode#4: 1024 x 600 16Bpp 60Hz */
480 0x03, 0x01, 0x0F, 0x00, 0x0E,
482 { /* Init_SR10_SR24 */
483 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20,
484 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
485 0xC4, 0x30, 0x02, 0x00, 0x01,
487 { /* Init_SR30_SR75 */
488 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22,
489 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF,
490 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
491 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22,
492 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
493 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22,
494 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
495 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02,
496 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20,
498 { /* Init_SR80_SR93 */
499 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
500 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
501 0x00, 0x00, 0x00, 0x00,
503 { /* Init_SRA0_SRAF */
504 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
505 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
507 { /* Init_GR00_GR08 */
508 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
511 { /* Init_AR00_AR14 */
512 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
513 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
514 0x41, 0x00, 0x0F, 0x00, 0x00,
516 { /* Init_CR00_CR18 */
517 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
518 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
519 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
522 { /* Init_CR30_CR4D */
523 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
524 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
525 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00,
526 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57,
528 { /* Init_CR90_CRA7 */
529 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
530 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
531 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
534 { /* 1024 x 768 16Bpp 60Hz */
539 0x03, 0x01, 0x0F, 0x03, 0x0E,
541 { /* Init_SR10_SR24 */
542 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
543 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
544 0xC4, 0x30, 0x02, 0x01, 0x01,
546 { /* Init_SR30_SR75 */
547 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
548 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
549 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
550 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
551 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
552 0x0F, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
553 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
554 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
555 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
557 { /* Init_SR80_SR93 */
558 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
559 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
560 0x00, 0x00, 0x00, 0x00,
562 { /* Init_SRA0_SRAF */
563 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
564 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
566 { /* Init_GR00_GR08 */
567 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
570 { /* Init_AR00_AR14 */
571 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
572 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
573 0x41, 0x00, 0x0F, 0x00, 0x00,
575 { /* Init_CR00_CR18 */
576 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
577 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
578 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
581 { /* Init_CR30_CR4D */
582 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
583 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
584 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
585 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
587 { /* Init_CR90_CRA7 */
588 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
589 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
590 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
593 { /* mode#5: 1024 x 768 24Bpp 60Hz */
598 0x03, 0x01, 0x0F, 0x03, 0x0E,
600 { /* Init_SR10_SR24 */
601 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
602 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
603 0xC4, 0x30, 0x02, 0x01, 0x01,
605 { /* Init_SR30_SR75 */
606 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
607 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
608 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
609 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
610 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
611 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
612 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
613 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
614 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
616 { /* Init_SR80_SR93 */
617 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
618 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
619 0x00, 0x00, 0x00, 0x00,
621 { /* Init_SRA0_SRAF */
622 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
623 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
625 { /* Init_GR00_GR08 */
626 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
629 { /* Init_AR00_AR14 */
630 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
631 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
632 0x41, 0x00, 0x0F, 0x00, 0x00,
634 { /* Init_CR00_CR18 */
635 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
636 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
640 { /* Init_CR30_CR4D */
641 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
642 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
643 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
644 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
646 { /* Init_CR90_CRA7 */
647 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
648 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
649 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
652 { /* mode#4: 1024 x 768 32Bpp 60Hz */
657 0x03, 0x01, 0x0F, 0x03, 0x0E,
659 { /* Init_SR10_SR24 */
660 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
661 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
662 0xC4, 0x32, 0x02, 0x01, 0x01,
664 { /* Init_SR30_SR75 */
665 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
666 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
667 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
668 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
669 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
670 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
671 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
672 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
673 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
675 { /* Init_SR80_SR93 */
676 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
677 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
678 0x00, 0x00, 0x00, 0x00,
680 { /* Init_SRA0_SRAF */
681 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
682 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
684 { /* Init_GR00_GR08 */
685 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
688 { /* Init_AR00_AR14 */
689 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
690 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
691 0x41, 0x00, 0x0F, 0x00, 0x00,
693 { /* Init_CR00_CR18 */
694 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
695 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
696 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
699 { /* Init_CR30_CR4D */
700 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
701 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
702 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
703 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
705 { /* Init_CR90_CRA7 */
706 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
707 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
708 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
711 { /* mode#6: 320 x 240 16Bpp 60Hz */
716 0x03, 0x01, 0x0F, 0x03, 0x0E,
718 { /* Init_SR10_SR24 */
719 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
720 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
721 0xC4, 0x32, 0x02, 0x01, 0x01,
723 { /* Init_SR30_SR75 */
724 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
725 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
726 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
727 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
728 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
729 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
730 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
731 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
732 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
734 { /* Init_SR80_SR93 */
735 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
736 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
737 0x00, 0x00, 0x00, 0x00,
739 { /* Init_SRA0_SRAF */
740 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
741 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
743 { /* Init_GR00_GR08 */
744 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
747 { /* Init_AR00_AR14 */
748 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
749 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
750 0x41, 0x00, 0x0F, 0x00, 0x00,
752 { /* Init_CR00_CR18 */
753 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
754 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
755 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
758 { /* Init_CR30_CR4D */
759 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
760 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
761 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
762 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
764 { /* Init_CR90_CRA7 */
765 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
766 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
767 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
771 { /* mode#8: 320 x 240 32Bpp 60Hz */
776 0x03, 0x01, 0x0F, 0x03, 0x0E,
778 { /* Init_SR10_SR24 */
779 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
780 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
781 0xC4, 0x32, 0x02, 0x01, 0x01,
783 { /* Init_SR30_SR75 */
784 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
785 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
786 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
787 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
788 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
789 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
790 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
791 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
792 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
794 { /* Init_SR80_SR93 */
795 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
796 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
797 0x00, 0x00, 0x00, 0x00,
799 { /* Init_SRA0_SRAF */
800 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
801 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
803 { /* Init_GR00_GR08 */
804 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
807 { /* Init_AR00_AR14 */
808 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
809 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
810 0x41, 0x00, 0x0F, 0x00, 0x00,
812 { /* Init_CR00_CR18 */
813 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
814 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
815 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
818 { /* Init_CR30_CR4D */
819 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
820 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
821 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
822 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
824 { /* Init_CR90_CRA7 */
825 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
826 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
827 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
832 static struct screen_info smtc_scr_info;
834 static char *mode_option;
836 /* process command line options, get vga parameter */
837 static void __init sm7xx_vga_setup(char *options)
841 if (!options || !*options)
844 smtc_scr_info.lfb_width = 0;
845 smtc_scr_info.lfb_height = 0;
846 smtc_scr_info.lfb_depth = 0;
848 pr_debug("%s = %s\n", __func__, options);
850 for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
851 if (strstr(options, vesa_mode_table[i].index)) {
852 smtc_scr_info.lfb_width = vesa_mode_table[i].lfb_width;
853 smtc_scr_info.lfb_height =
854 vesa_mode_table[i].lfb_height;
855 smtc_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth;
861 static void sm712_setpalette(int regno, unsigned int red, unsigned int green,
862 unsigned int blue, struct fb_info *info)
864 /* set bit 5:4 = 01 (write LCD RAM only) */
865 smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
867 smtc_mmiowb(regno, dac_reg);
868 smtc_mmiowb(red >> 10, dac_val);
869 smtc_mmiowb(green >> 10, dac_val);
870 smtc_mmiowb(blue >> 10, dac_val);
875 * convert a colour value into a field position
880 static inline unsigned int chan_to_field(unsigned int chan,
881 struct fb_bitfield *bf)
884 chan >>= 16 - bf->length;
885 return chan << bf->offset;
888 static int smtc_blank(int blank_mode, struct fb_info *info)
890 struct smtcfb_info *sfb = info->par;
892 /* clear DPMS setting */
893 switch (blank_mode) {
894 case FB_BLANK_UNBLANK:
895 /* Screen On: HSync: On, VSync : On */
897 switch (sfb->chip_id) {
900 smtc_seqw(0x6a, 0x16);
901 smtc_seqw(0x6b, 0x02);
904 smtc_seqw(0x6a, 0x0d);
905 smtc_seqw(0x6b, 0x02);
909 smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
910 smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
911 smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
912 smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
913 smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
914 smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
916 case FB_BLANK_NORMAL:
917 /* Screen Off: HSync: On, VSync : On Soft blank */
918 smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
919 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
920 smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
921 smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
922 smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
923 smtc_seqw(0x6a, 0x16);
924 smtc_seqw(0x6b, 0x02);
926 case FB_BLANK_VSYNC_SUSPEND:
927 /* Screen On: HSync: On, VSync : Off */
928 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
929 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
930 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
931 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
932 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
933 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
934 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
935 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
936 smtc_seqw(0x6a, 0x0c);
937 smtc_seqw(0x6b, 0x02);
939 case FB_BLANK_HSYNC_SUSPEND:
940 /* Screen On: HSync: Off, VSync : On */
941 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
942 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
943 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
944 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
945 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
946 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
947 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
948 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
949 smtc_seqw(0x6a, 0x0c);
950 smtc_seqw(0x6b, 0x02);
952 case FB_BLANK_POWERDOWN:
953 /* Screen On: HSync: Off, VSync : Off */
954 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
955 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
956 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
957 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
958 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
959 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
960 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
961 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
962 smtc_seqw(0x6a, 0x0c);
963 smtc_seqw(0x6b, 0x02);
972 static int smtc_setcolreg(unsigned int regno, unsigned int red,
973 unsigned int green, unsigned int blue,
974 unsigned int trans, struct fb_info *info)
976 struct smtcfb_info *sfb;
984 switch (sfb->fb->fix.visual) {
985 case FB_VISUAL_DIRECTCOLOR:
986 case FB_VISUAL_TRUECOLOR:
988 * 16/32 bit true-colour, use pseudo-palette for 16 base color
992 if (sfb->fb->var.bits_per_pixel == 16) {
993 u32 *pal = sfb->fb->pseudo_palette;
995 val = chan_to_field(red, &sfb->fb->var.red);
996 val |= chan_to_field(green, &sfb->fb->var.green);
997 val |= chan_to_field(blue, &sfb->fb->var.blue);
998 pal[regno] = pal_rgb(red, green, blue, val);
1000 u32 *pal = sfb->fb->pseudo_palette;
1002 val = chan_to_field(red, &sfb->fb->var.red);
1003 val |= chan_to_field(green, &sfb->fb->var.green);
1004 val |= chan_to_field(blue, &sfb->fb->var.blue);
1005 pal[regno] = big_swap(val);
1009 case FB_VISUAL_PSEUDOCOLOR:
1010 /* color depth 8 bit */
1011 sm712_setpalette(regno, red, green, blue, info);
1015 return 1; /* unknown type */
1021 static ssize_t smtcfb_read(struct fb_info *info, char __user *buf,
1022 size_t count, loff_t *ppos)
1024 unsigned long p = *ppos;
1028 int c, i, cnt = 0, err = 0;
1029 unsigned long total_size;
1031 if (!info || !info->screen_base)
1034 if (info->state != FBINFO_STATE_RUNNING)
1037 total_size = info->screen_size;
1039 if (total_size == 0)
1040 total_size = info->fix.smem_len;
1042 if (p >= total_size)
1045 if (count >= total_size)
1048 if (count + p > total_size)
1049 count = total_size - p;
1051 buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
1055 src = (u32 __iomem *)(info->screen_base + p);
1057 if (info->fbops->fb_sync)
1058 info->fbops->fb_sync(info);
1061 c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1063 for (i = (c + 3) >> 2; i--;) {
1066 val = fb_readl(src);
1067 *dst = big_swap(val);
1072 if (copy_to_user(buf, buffer, c)) {
1084 return (err) ? err : cnt;
1087 static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
1088 size_t count, loff_t *ppos)
1090 unsigned long p = *ppos;
1094 int c, i, cnt = 0, err = 0;
1095 unsigned long total_size;
1097 if (!info || !info->screen_base)
1100 if (info->state != FBINFO_STATE_RUNNING)
1103 total_size = info->screen_size;
1105 if (total_size == 0)
1106 total_size = info->fix.smem_len;
1111 if (count > total_size) {
1116 if (count + p > total_size) {
1120 count = total_size - p;
1123 buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
1127 dst = (u32 __iomem *)(info->screen_base + p);
1129 if (info->fbops->fb_sync)
1130 info->fbops->fb_sync(info);
1133 c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1136 if (copy_from_user(src, buf, c)) {
1141 for (i = (c + 3) >> 2; i--;) {
1142 fb_writel(big_swap(*src), dst);
1155 return (cnt) ? cnt : err;
1158 static void sm7xx_set_timing(struct smtcfb_info *sfb)
1161 u32 m_nscreenstride;
1163 dev_dbg(&sfb->pdev->dev,
1164 "sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n",
1165 sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz);
1167 for (j = 0; j < ARRAY_SIZE(vgamode); j++) {
1168 if (vgamode[j].mmsizex != sfb->width ||
1169 vgamode[j].mmsizey != sfb->height ||
1170 vgamode[j].bpp != sfb->fb->var.bits_per_pixel ||
1171 vgamode[j].hz != sfb->hz)
1174 dev_dbg(&sfb->pdev->dev,
1175 "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
1176 vgamode[j].mmsizex, vgamode[j].mmsizey,
1177 vgamode[j].bpp, vgamode[j].hz);
1179 dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
1181 smtc_mmiowb(0x0, 0x3c6);
1185 smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
1187 /* init SEQ register SR00 - SR04 */
1188 for (i = 0; i < SIZE_SR00_SR04; i++)
1189 smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
1191 /* init SEQ register SR10 - SR24 */
1192 for (i = 0; i < SIZE_SR10_SR24; i++)
1193 smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]);
1195 /* init SEQ register SR30 - SR75 */
1196 for (i = 0; i < SIZE_SR30_SR75; i++)
1197 if ((i + 0x30) != 0x30 && (i + 0x30) != 0x62 &&
1198 (i + 0x30) != 0x6a && (i + 0x30) != 0x6b &&
1199 (i + 0x30) != 0x70 && (i + 0x30) != 0x71 &&
1200 (i + 0x30) != 0x74 && (i + 0x30) != 0x75)
1202 vgamode[j].init_sr30_sr75[i]);
1204 /* init SEQ register SR80 - SR93 */
1205 for (i = 0; i < SIZE_SR80_SR93; i++)
1206 smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]);
1208 /* init SEQ register SRA0 - SRAF */
1209 for (i = 0; i < SIZE_SRA0_SRAF; i++)
1210 smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]);
1212 /* init Graphic register GR00 - GR08 */
1213 for (i = 0; i < SIZE_GR00_GR08; i++)
1214 smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
1216 /* init Attribute register AR00 - AR14 */
1217 for (i = 0; i < SIZE_AR00_AR14; i++)
1218 smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
1220 /* init CRTC register CR00 - CR18 */
1221 for (i = 0; i < SIZE_CR00_CR18; i++)
1222 smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
1224 /* init CRTC register CR30 - CR4D */
1225 for (i = 0; i < SIZE_CR30_CR4D; i++) {
1226 if ((i + 0x30) >= 0x3B && (i + 0x30) <= 0x3F)
1227 /* side-effect, don't write to CR3B-CR3F */
1229 smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
1232 /* init CRTC register CR90 - CRA7 */
1233 for (i = 0; i < SIZE_CR90_CRA7; i++)
1234 smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]);
1236 smtc_mmiowb(0x67, 0x3c2);
1238 /* set VPR registers */
1239 writel(0x0, sfb->vp_regs + 0x0C);
1240 writel(0x0, sfb->vp_regs + 0x40);
1242 /* set data width */
1243 m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64;
1244 switch (sfb->fb->var.bits_per_pixel) {
1246 writel(0x0, sfb->vp_regs + 0x0);
1249 writel(0x00020000, sfb->vp_regs + 0x0);
1252 writel(0x00040000, sfb->vp_regs + 0x0);
1255 writel(0x00030000, sfb->vp_regs + 0x0);
1258 writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride),
1259 sfb->vp_regs + 0x10);
1262 static void smtc_set_timing(struct smtcfb_info *sfb)
1264 switch (sfb->chip_id) {
1268 sm7xx_set_timing(sfb);
1273 static void smtcfb_setmode(struct smtcfb_info *sfb)
1275 switch (sfb->fb->var.bits_per_pixel) {
1277 sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR;
1278 sfb->fb->fix.line_length = sfb->fb->var.xres * 4;
1279 sfb->fb->var.red.length = 8;
1280 sfb->fb->var.green.length = 8;
1281 sfb->fb->var.blue.length = 8;
1282 sfb->fb->var.red.offset = 16;
1283 sfb->fb->var.green.offset = 8;
1284 sfb->fb->var.blue.offset = 0;
1287 sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR;
1288 sfb->fb->fix.line_length = sfb->fb->var.xres * 3;
1289 sfb->fb->var.red.length = 8;
1290 sfb->fb->var.green.length = 8;
1291 sfb->fb->var.blue.length = 8;
1292 sfb->fb->var.red.offset = 16;
1293 sfb->fb->var.green.offset = 8;
1294 sfb->fb->var.blue.offset = 0;
1297 sfb->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
1298 sfb->fb->fix.line_length = sfb->fb->var.xres;
1299 sfb->fb->var.red.length = 3;
1300 sfb->fb->var.green.length = 3;
1301 sfb->fb->var.blue.length = 2;
1302 sfb->fb->var.red.offset = 5;
1303 sfb->fb->var.green.offset = 2;
1304 sfb->fb->var.blue.offset = 0;
1308 sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR;
1309 sfb->fb->fix.line_length = sfb->fb->var.xres * 2;
1310 sfb->fb->var.red.length = 5;
1311 sfb->fb->var.green.length = 6;
1312 sfb->fb->var.blue.length = 5;
1313 sfb->fb->var.red.offset = 11;
1314 sfb->fb->var.green.offset = 5;
1315 sfb->fb->var.blue.offset = 0;
1319 sfb->width = sfb->fb->var.xres;
1320 sfb->height = sfb->fb->var.yres;
1322 smtc_set_timing(sfb);
1325 static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1328 if (var->xres_virtual < var->xres)
1329 var->xres_virtual = var->xres;
1331 if (var->yres_virtual < var->yres)
1332 var->yres_virtual = var->yres;
1334 /* set valid default bpp */
1335 if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) &&
1336 (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
1337 var->bits_per_pixel = 16;
1342 static int smtc_set_par(struct fb_info *info)
1344 smtcfb_setmode(info->par);
1349 static const struct fb_ops smtcfb_ops = {
1350 .owner = THIS_MODULE,
1351 .fb_check_var = smtc_check_var,
1352 .fb_set_par = smtc_set_par,
1353 .fb_setcolreg = smtc_setcolreg,
1354 .fb_blank = smtc_blank,
1355 .fb_fillrect = cfb_fillrect,
1356 .fb_imageblit = cfb_imageblit,
1357 .fb_copyarea = cfb_copyarea,
1358 .fb_read = smtcfb_read,
1359 .fb_write = smtcfb_write,
1363 * Unmap in the memory mapped IO registers
1366 static void smtc_unmap_mmio(struct smtcfb_info *sfb)
1368 if (sfb && smtc_regbaseaddress)
1369 smtc_regbaseaddress = NULL;
1373 * Map in the screen memory
1376 static int smtc_map_smem(struct smtcfb_info *sfb,
1377 struct pci_dev *pdev, u_long smem_len)
1379 sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
1381 if (sfb->chip_id == 0x720)
1382 /* on SM720, the framebuffer starts at the 1 MB offset */
1383 sfb->fb->fix.smem_start += 0x00200000;
1385 /* XXX: is it safe for SM720 on Big-Endian? */
1386 if (sfb->fb->var.bits_per_pixel == 32)
1387 sfb->fb->fix.smem_start += big_addr;
1389 sfb->fb->fix.smem_len = smem_len;
1391 sfb->fb->screen_base = sfb->lfb;
1393 if (!sfb->fb->screen_base) {
1395 "%s: unable to map screen memory\n", sfb->fb->fix.id);
1403 * Unmap in the screen memory
1406 static void smtc_unmap_smem(struct smtcfb_info *sfb)
1408 if (sfb && sfb->fb->screen_base) {
1409 if (sfb->chip_id == 0x720)
1410 sfb->fb->screen_base -= 0x00200000;
1411 iounmap(sfb->fb->screen_base);
1412 sfb->fb->screen_base = NULL;
1417 * We need to wake up the device and make sure its in linear memory mode.
1419 static inline void sm7xx_init_hw(void)
1421 outb_p(0x18, 0x3c4);
1422 outb_p(0x11, 0x3c5);
1425 static u_long sm7xx_vram_probe(struct smtcfb_info *sfb)
1429 switch (sfb->chip_id) {
1433 * Assume SM712 graphics chip has 4MB VRAM.
1435 * FIXME: SM712 can have 2MB VRAM, which is used on earlier
1436 * laptops, such as IBM Thinkpad 240X. This driver would
1437 * probably crash on those machines. If anyone gets one of
1438 * those and is willing to help, run "git blame" and send me
1443 outb_p(0x76, 0x3c4);
1444 vram = inb_p(0x3c5) >> 6;
1447 return 0x00800000; /* 8 MB */
1448 else if (vram == 0x01)
1449 return 0x01000000; /* 16 MB */
1450 else if (vram == 0x02)
1451 return 0x00400000; /* illegal, fallback to 4 MB */
1452 else if (vram == 0x03)
1453 return 0x00400000; /* 4 MB */
1455 return 0; /* unknown hardware */
1458 static void sm7xx_resolution_probe(struct smtcfb_info *sfb)
1460 /* get mode parameter from smtc_scr_info */
1461 if (smtc_scr_info.lfb_width != 0) {
1462 sfb->fb->var.xres = smtc_scr_info.lfb_width;
1463 sfb->fb->var.yres = smtc_scr_info.lfb_height;
1464 sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
1469 * No parameter, default resolution is 1024x768-16.
1471 * FIXME: earlier laptops, such as IBM Thinkpad 240X, has a 800x600
1472 * panel, also see the comments about Thinkpad 240X above.
1474 sfb->fb->var.xres = SCREEN_X_RES;
1475 sfb->fb->var.yres = SCREEN_Y_RES_PC;
1476 sfb->fb->var.bits_per_pixel = SCREEN_BPP;
1480 * Loongson MIPS netbooks use 1024x600 LCD panels, which is the original
1481 * target platform of this driver, but nearly all old x86 laptops have
1482 * 1024x768. Lighting 768 panels using 600's timings would partially
1483 * garble the display, so we don't want that. But it's not possible to
1484 * distinguish them reliably.
1486 * So we change the default to 768, but keep 600 as-is on MIPS.
1488 sfb->fb->var.yres = SCREEN_Y_RES_NETBOOK;
1492 big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth);
1495 static int smtcfb_pci_probe(struct pci_dev *pdev,
1496 const struct pci_device_id *ent)
1498 struct smtcfb_info *sfb;
1499 struct fb_info *info;
1502 unsigned long mmio_base;
1504 dev_info(&pdev->dev, "Silicon Motion display driver.\n");
1506 err = aperture_remove_conflicting_pci_devices(pdev, "smtcfb");
1510 err = pci_enable_device(pdev); /* enable SMTC chip */
1514 err = pci_request_region(pdev, 0, "sm7xxfb");
1516 dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
1517 goto failed_regions;
1520 sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
1522 info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
1530 sfb->chip_id = ent->device;
1532 info->flags = FBINFO_FLAG_DEFAULT;
1533 info->fbops = &smtcfb_ops;
1534 info->fix = smtcfb_fix;
1535 info->var = smtcfb_var;
1536 info->pseudo_palette = sfb->colreg;
1539 pci_set_drvdata(pdev, sfb);
1543 /* Map address and memory detection */
1544 mmio_base = pci_resource_start(pdev, 0);
1545 pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
1547 smem_size = sm7xx_vram_probe(sfb);
1548 dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n",
1549 smem_size / 1048576);
1551 switch (sfb->chip_id) {
1554 sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
1555 sfb->fb->fix.mmio_len = 0x00400000;
1556 sfb->lfb = ioremap(mmio_base, mmio_addr);
1559 "%s: unable to map memory mapped IO!\n",
1565 sfb->mmio = (smtc_regbaseaddress =
1566 sfb->lfb + 0x00700000);
1567 sfb->dp_regs = sfb->lfb + 0x00408000;
1568 sfb->vp_regs = sfb->lfb + 0x0040c000;
1569 if (sfb->fb->var.bits_per_pixel == 32) {
1570 sfb->lfb += big_addr;
1571 dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
1574 /* set MCLK = 14.31818 * (0x16 / 0x2) */
1575 smtc_seqw(0x6a, 0x16);
1576 smtc_seqw(0x6b, 0x02);
1577 smtc_seqw(0x62, 0x3e);
1578 /* enable PCI burst */
1579 smtc_seqw(0x17, 0x20);
1580 /* enable word swap */
1581 if (sfb->fb->var.bits_per_pixel == 32)
1585 sfb->fb->fix.mmio_start = mmio_base;
1586 sfb->fb->fix.mmio_len = 0x00200000;
1587 sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
1588 if (!sfb->dp_regs) {
1590 "%s: unable to map memory mapped IO!\n",
1596 sfb->lfb = sfb->dp_regs + 0x00200000;
1597 sfb->mmio = (smtc_regbaseaddress =
1598 sfb->dp_regs + 0x000c0000);
1599 sfb->vp_regs = sfb->dp_regs + 0x800;
1601 smtc_seqw(0x62, 0xff);
1602 smtc_seqw(0x6a, 0x0d);
1603 smtc_seqw(0x6b, 0x02);
1607 "No valid Silicon Motion display chip was detected!\n");
1612 /* probe and decide resolution */
1613 sm7xx_resolution_probe(sfb);
1615 /* can support 32 bpp */
1616 if (sfb->fb->var.bits_per_pixel == 15)
1617 sfb->fb->var.bits_per_pixel = 16;
1619 sfb->fb->var.xres_virtual = sfb->fb->var.xres;
1620 sfb->fb->var.yres_virtual = sfb->fb->var.yres;
1621 err = smtc_map_smem(sfb, pdev, smem_size);
1626 * The screen would be temporarily garbled when sm712fb takes over
1627 * vesafb or VGA text mode. Zero the framebuffer.
1629 memset_io(sfb->lfb, 0, sfb->fb->fix.smem_len);
1631 err = register_framebuffer(info);
1635 dev_info(&pdev->dev,
1636 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n",
1637 sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
1638 sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
1643 dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n");
1645 smtc_unmap_smem(sfb);
1646 smtc_unmap_mmio(sfb);
1648 framebuffer_release(info);
1651 pci_release_region(pdev, 0);
1654 pci_disable_device(pdev);
1662 * 0x720 (Lynx3DM, Lynx3DM+)
1664 static const struct pci_device_id smtcfb_pci_table[] = {
1665 { PCI_DEVICE(0x126f, 0x710), },
1666 { PCI_DEVICE(0x126f, 0x712), },
1667 { PCI_DEVICE(0x126f, 0x720), },
1671 MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
1673 static void smtcfb_pci_remove(struct pci_dev *pdev)
1675 struct smtcfb_info *sfb;
1677 sfb = pci_get_drvdata(pdev);
1678 smtc_unmap_smem(sfb);
1679 smtc_unmap_mmio(sfb);
1680 unregister_framebuffer(sfb->fb);
1681 framebuffer_release(sfb->fb);
1682 pci_release_region(pdev, 0);
1683 pci_disable_device(pdev);
1686 static int __maybe_unused smtcfb_pci_suspend(struct device *device)
1688 struct smtcfb_info *sfb = dev_get_drvdata(device);
1691 /* set the hw in sleep mode use external clock and self memory refresh
1692 * so that we can turn off internal PLLs later on
1694 smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1695 smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1698 fb_set_suspend(sfb->fb, 1);
1701 /* additionally turn off all function blocks including internal PLLs */
1702 smtc_seqw(0x21, 0xff);
1707 static int __maybe_unused smtcfb_pci_resume(struct device *device)
1709 struct smtcfb_info *sfb = dev_get_drvdata(device);
1712 /* reinit hardware */
1714 switch (sfb->chip_id) {
1717 /* set MCLK = 14.31818 * (0x16 / 0x2) */
1718 smtc_seqw(0x6a, 0x16);
1719 smtc_seqw(0x6b, 0x02);
1720 smtc_seqw(0x62, 0x3e);
1721 /* enable PCI burst */
1722 smtc_seqw(0x17, 0x20);
1723 if (sfb->fb->var.bits_per_pixel == 32)
1727 smtc_seqw(0x62, 0xff);
1728 smtc_seqw(0x6a, 0x0d);
1729 smtc_seqw(0x6b, 0x02);
1733 smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1734 smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1736 smtcfb_setmode(sfb);
1739 fb_set_suspend(sfb->fb, 0);
1745 static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1747 static struct pci_driver smtcfb_driver = {
1749 .id_table = smtcfb_pci_table,
1750 .probe = smtcfb_pci_probe,
1751 .remove = smtcfb_pci_remove,
1752 .driver.pm = &sm7xx_pm_ops,
1755 static int __init sm712fb_init(void)
1757 char *option = NULL;
1759 if (fb_get_options("sm712fb", &option))
1761 if (option && *option)
1762 mode_option = option;
1763 sm7xx_vga_setup(mode_option);
1765 return pci_register_driver(&smtcfb_driver);
1768 module_init(sm712fb_init);
1770 static void __exit sm712fb_exit(void)
1772 pci_unregister_driver(&smtcfb_driver);
1775 module_exit(sm712fb_exit);
1777 MODULE_AUTHOR("Siliconmotion ");
1778 MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1779 MODULE_LICENSE("GPL");