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>
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 */
59 void __iomem *smtc_regbaseaddress; /* Memory Map IO starting address */
61 static struct fb_var_screeninfo smtcfb_var = {
70 .activate = FB_ACTIVATE_NOW,
73 .vmode = FB_VMODE_NONINTERLACED,
75 .accel_flags = FB_ACCELF_TEXT,
78 static struct fb_fix_screeninfo smtcfb_fix = {
80 .type = FB_TYPE_PACKED_PIXELS,
81 .visual = FB_VISUAL_TRUECOLOR,
82 .line_length = 800 * 3,
83 .accel = FB_ACCEL_SMI_LYNX,
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},
103 {"0x311", 640, 480, 16},
104 {"0x314", 800, 600, 16},
105 {"0x317", 1024, 768, 16},
106 {"0x31A", 1280, 1024, 16},
108 {"0x312", 640, 480, 24},
109 {"0x315", 800, 600, 24},
110 {"0x318", 1024, 768, 24},
111 {"0x31B", 1280, 1024, 24},
114 /**********************************************************************
116 **********************************************************************/
117 static const struct modeinit vgamode[] = {
119 /* mode#0: 640 x 480 16Bpp 60Hz */
124 0x03, 0x01, 0x0F, 0x00, 0x0E,
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,
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,
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,
147 { /* Init_SRA0_SRAF */
148 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
149 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
151 { /* Init_GR00_GR08 */
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
179 /* mode#1: 640 x 480 24Bpp 60Hz */
184 0x03, 0x01, 0x0F, 0x00, 0x0E,
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,
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,
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,
207 { /* Init_SRA0_SRAF */
208 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
209 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
211 { /* Init_GR00_GR08 */
212 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
239 /* mode#0: 640 x 480 32Bpp 60Hz */
244 0x03, 0x01, 0x0F, 0x00, 0x0E,
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,
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,
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,
267 { /* Init_SRA0_SRAF */
268 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
269 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
271 { /* Init_GR00_GR08 */
272 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
299 { /* mode#2: 800 x 600 16Bpp 60Hz */
304 0x03, 0x01, 0x0F, 0x03, 0x0E,
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,
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,
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,
327 { /* Init_SRA0_SRAF */
328 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
329 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
331 { /* Init_GR00_GR08 */
332 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
358 { /* mode#3: 800 x 600 24Bpp 60Hz */
362 0x03, 0x01, 0x0F, 0x03, 0x0E,
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,
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,
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,
385 { /* Init_SRA0_SRAF */
386 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
387 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
389 { /* Init_GR00_GR08 */
390 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
416 { /* mode#7: 800 x 600 32Bpp 60Hz */
421 0x03, 0x01, 0x0F, 0x03, 0x0E,
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,
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,
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,
444 { /* Init_SRA0_SRAF */
445 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
446 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
448 { /* Init_GR00_GR08 */
449 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
475 /* We use 1024x768 table to light 1024x600 panel for lemote */
476 { /* mode#4: 1024 x 600 16Bpp 60Hz */
481 0x03, 0x01, 0x0F, 0x00, 0x0E,
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,
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,
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,
504 { /* Init_SRA0_SRAF */
505 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
506 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
508 { /* Init_GR00_GR08 */
509 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
535 { /* mode#5: 1024 x 768 24Bpp 60Hz */
540 0x03, 0x01, 0x0F, 0x03, 0x0E,
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,
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,
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,
563 { /* Init_SRA0_SRAF */
564 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
565 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
567 { /* Init_GR00_GR08 */
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
594 { /* mode#4: 1024 x 768 32Bpp 60Hz */
599 0x03, 0x01, 0x0F, 0x03, 0x0E,
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,
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,
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,
622 { /* Init_SRA0_SRAF */
623 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
624 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
626 { /* Init_GR00_GR08 */
627 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
653 { /* mode#6: 320 x 240 16Bpp 60Hz */
658 0x03, 0x01, 0x0F, 0x03, 0x0E,
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,
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,
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,
681 { /* Init_SRA0_SRAF */
682 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
683 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
685 { /* Init_GR00_GR08 */
686 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
713 { /* mode#8: 320 x 240 32Bpp 60Hz */
718 0x03, 0x01, 0x0F, 0x03, 0x0E,
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,
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,
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,
741 { /* Init_SRA0_SRAF */
742 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
743 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
745 { /* Init_GR00_GR08 */
746 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
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,
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,
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,
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,
774 static struct screen_info smtc_scr_info;
776 static char *mode_option;
778 /* process command line options, get vga parameter */
779 static void __init sm7xx_vga_setup(char *options)
783 if (!options || !*options)
786 smtc_scr_info.lfb_width = 0;
787 smtc_scr_info.lfb_height = 0;
788 smtc_scr_info.lfb_depth = 0;
790 pr_debug("sm7xx_vga_setup = %s\n", options);
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;
803 static void sm712_setpalette(int regno, unsigned red, unsigned green,
804 unsigned blue, struct fb_info *info)
806 /* set bit 5:4 = 01 (write LCD RAM only) */
807 smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
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);
817 * convert a colour value into a field position
822 static inline unsigned int chan_to_field(unsigned int chan,
823 struct fb_bitfield *bf)
826 chan >>= 16 - bf->length;
827 return chan << bf->offset;
830 static int smtc_blank(int blank_mode, struct fb_info *info)
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));
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));
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));
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));
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));
901 static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
902 unsigned blue, unsigned trans, struct fb_info *info)
904 struct smtcfb_info *sfb;
912 switch (sfb->fb->fix.visual) {
913 case FB_VISUAL_DIRECTCOLOR:
914 case FB_VISUAL_TRUECOLOR:
916 * 16/32 bit true-colour, use pseudo-palette for 16 base color
920 if (sfb->fb->var.bits_per_pixel == 16) {
921 u32 *pal = sfb->fb->pseudo_palette;
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);
927 pal[regno] = ((red & 0xf800) >> 8) |
928 ((green & 0xe000) >> 13) |
929 ((green & 0x1c00) << 3) |
930 ((blue & 0xf800) >> 3);
935 u32 *pal = sfb->fb->pseudo_palette;
937 val = chan_to_field(red, &sfb->fb->var.red);
938 val |= chan_to_field(green, &sfb->fb->var.green);
939 val |= chan_to_field(blue, &sfb->fb->var.blue);
941 val = (val & 0xff00ff00 >> 8) |
942 (val & 0x00ff00ff << 8);
948 case FB_VISUAL_PSEUDOCOLOR:
949 /* color depth 8 bit */
950 sm712_setpalette(regno, red, green, blue, info);
954 return 1; /* unknown type */
961 static ssize_t smtcfb_read(struct fb_info *info, char __user *buf,
962 size_t count, loff_t *ppos)
964 unsigned long p = *ppos;
968 int c, i, cnt = 0, err = 0;
969 unsigned long total_size;
971 if (!info || !info->screen_base)
974 if (info->state != FBINFO_STATE_RUNNING)
977 total_size = info->screen_size;
980 total_size = info->fix.smem_len;
985 if (count >= total_size)
988 if (count + p > total_size)
989 count = total_size - p;
991 buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
995 src = (u32 __iomem *)(info->screen_base + p);
997 if (info->fbops->fb_sync)
998 info->fbops->fb_sync(info);
1001 c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1003 for (i = c >> 2; i--;) {
1004 *dst = fb_readl(src++);
1005 *dst = (*dst & 0xff00ff00 >> 8) |
1006 (*dst & 0x00ff00ff << 8);
1010 u8 *dst8 = (u8 *)dst;
1011 u8 __iomem *src8 = (u8 __iomem *)src;
1013 for (i = c & 3; i--;) {
1015 *dst8++ = fb_readb(++src8);
1017 *dst8++ = fb_readb(--src8);
1021 src = (u32 __iomem *)src8;
1024 if (copy_to_user(buf, buffer, c)) {
1036 return (err) ? err : cnt;
1039 static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf,
1040 size_t count, loff_t *ppos)
1042 unsigned long p = *ppos;
1046 int c, i, cnt = 0, err = 0;
1047 unsigned long total_size;
1049 if (!info || !info->screen_base)
1052 if (info->state != FBINFO_STATE_RUNNING)
1055 total_size = info->screen_size;
1057 if (total_size == 0)
1058 total_size = info->fix.smem_len;
1063 if (count > total_size) {
1068 if (count + p > total_size) {
1072 count = total_size - p;
1075 buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
1079 dst = (u32 __iomem *)(info->screen_base + p);
1081 if (info->fbops->fb_sync)
1082 info->fbops->fb_sync(info);
1085 c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
1088 if (copy_from_user(src, buf, c)) {
1093 for (i = c >> 2; i--;) {
1094 fb_writel((*src & 0xff00ff00 >> 8) |
1095 (*src & 0x00ff00ff << 8), dst++);
1099 u8 *src8 = (u8 *)src;
1100 u8 __iomem *dst8 = (u8 __iomem *)dst;
1102 for (i = c & 3; i--;) {
1104 fb_writeb(*src8++, ++dst8);
1106 fb_writeb(*src8++, --dst8);
1110 dst = (u32 __iomem *)dst8;
1121 return (cnt) ? cnt : err;
1123 #endif /* ! __BIG_ENDIAN */
1125 static void sm7xx_set_timing(struct smtcfb_info *sfb)
1128 u32 m_nscreenstride;
1130 dev_dbg(&sfb->pdev->dev,
1131 "sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n",
1132 sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz);
1134 for (j = 0; j < ARRAY_SIZE(vgamode); j++) {
1135 if (vgamode[j].mmsizex != sfb->width ||
1136 vgamode[j].mmsizey != sfb->height ||
1137 vgamode[j].bpp != sfb->fb->var.bits_per_pixel ||
1138 vgamode[j].hz != sfb->hz)
1141 dev_dbg(&sfb->pdev->dev,
1142 "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
1143 vgamode[j].mmsizex, vgamode[j].mmsizey,
1144 vgamode[j].bpp, vgamode[j].hz);
1146 dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
1148 smtc_mmiowb(0x0, 0x3c6);
1152 smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
1154 /* init SEQ register SR00 - SR04 */
1155 for (i = 0; i < SIZE_SR00_SR04; i++)
1156 smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
1158 /* init SEQ register SR10 - SR24 */
1159 for (i = 0; i < SIZE_SR10_SR24; i++)
1160 smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]);
1162 /* init SEQ register SR30 - SR75 */
1163 for (i = 0; i < SIZE_SR30_SR75; i++)
1164 if ((i + 0x30) != 0x62 && (i + 0x30) != 0x6a &&
1167 vgamode[j].init_sr30_sr75[i]);
1169 /* init SEQ register SR80 - SR93 */
1170 for (i = 0; i < SIZE_SR80_SR93; i++)
1171 smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]);
1173 /* init SEQ register SRA0 - SRAF */
1174 for (i = 0; i < SIZE_SRA0_SRAF; i++)
1175 smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]);
1177 /* init Graphic register GR00 - GR08 */
1178 for (i = 0; i < SIZE_GR00_GR08; i++)
1179 smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
1181 /* init Attribute register AR00 - AR14 */
1182 for (i = 0; i < SIZE_AR00_AR14; i++)
1183 smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
1185 /* init CRTC register CR00 - CR18 */
1186 for (i = 0; i < SIZE_CR00_CR18; i++)
1187 smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
1189 /* init CRTC register CR30 - CR4D */
1190 for (i = 0; i < SIZE_CR30_CR4D; i++)
1191 smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]);
1193 /* init CRTC register CR90 - CRA7 */
1194 for (i = 0; i < SIZE_CR90_CRA7; i++)
1195 smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]);
1197 smtc_mmiowb(0x67, 0x3c2);
1199 /* set VPR registers */
1200 writel(0x0, sfb->vp_regs + 0x0C);
1201 writel(0x0, sfb->vp_regs + 0x40);
1203 /* set data width */
1204 m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64;
1205 switch (sfb->fb->var.bits_per_pixel) {
1207 writel(0x0, sfb->vp_regs + 0x0);
1210 writel(0x00020000, sfb->vp_regs + 0x0);
1213 writel(0x00040000, sfb->vp_regs + 0x0);
1216 writel(0x00030000, sfb->vp_regs + 0x0);
1219 writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride),
1220 sfb->vp_regs + 0x10);
1223 static void smtc_set_timing(struct smtcfb_info *sfb)
1225 switch (sfb->chip_id) {
1229 sm7xx_set_timing(sfb);
1234 static void smtcfb_setmode(struct smtcfb_info *sfb)
1236 switch (sfb->fb->var.bits_per_pixel) {
1238 sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR;
1239 sfb->fb->fix.line_length = sfb->fb->var.xres * 4;
1240 sfb->fb->var.red.length = 8;
1241 sfb->fb->var.green.length = 8;
1242 sfb->fb->var.blue.length = 8;
1243 sfb->fb->var.red.offset = 16;
1244 sfb->fb->var.green.offset = 8;
1245 sfb->fb->var.blue.offset = 0;
1248 sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR;
1249 sfb->fb->fix.line_length = sfb->fb->var.xres * 3;
1250 sfb->fb->var.red.length = 8;
1251 sfb->fb->var.green.length = 8;
1252 sfb->fb->var.blue.length = 8;
1253 sfb->fb->var.red.offset = 16;
1254 sfb->fb->var.green.offset = 8;
1255 sfb->fb->var.blue.offset = 0;
1258 sfb->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
1259 sfb->fb->fix.line_length = sfb->fb->var.xres;
1260 sfb->fb->var.red.length = 3;
1261 sfb->fb->var.green.length = 3;
1262 sfb->fb->var.blue.length = 2;
1263 sfb->fb->var.red.offset = 5;
1264 sfb->fb->var.green.offset = 2;
1265 sfb->fb->var.blue.offset = 0;
1269 sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR;
1270 sfb->fb->fix.line_length = sfb->fb->var.xres * 2;
1271 sfb->fb->var.red.length = 5;
1272 sfb->fb->var.green.length = 6;
1273 sfb->fb->var.blue.length = 5;
1274 sfb->fb->var.red.offset = 11;
1275 sfb->fb->var.green.offset = 5;
1276 sfb->fb->var.blue.offset = 0;
1280 sfb->width = sfb->fb->var.xres;
1281 sfb->height = sfb->fb->var.yres;
1283 smtc_set_timing(sfb);
1286 static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1289 if (var->xres_virtual < var->xres)
1290 var->xres_virtual = var->xres;
1292 if (var->yres_virtual < var->yres)
1293 var->yres_virtual = var->yres;
1295 /* set valid default bpp */
1296 if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) &&
1297 (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
1298 var->bits_per_pixel = 16;
1303 static int smtc_set_par(struct fb_info *info)
1305 smtcfb_setmode(info->par);
1310 static struct fb_ops smtcfb_ops = {
1311 .owner = THIS_MODULE,
1312 .fb_check_var = smtc_check_var,
1313 .fb_set_par = smtc_set_par,
1314 .fb_setcolreg = smtc_setcolreg,
1315 .fb_blank = smtc_blank,
1316 .fb_fillrect = cfb_fillrect,
1317 .fb_imageblit = cfb_imageblit,
1318 .fb_copyarea = cfb_copyarea,
1320 .fb_read = smtcfb_read,
1321 .fb_write = smtcfb_write,
1326 * Unmap in the memory mapped IO registers
1329 static void smtc_unmap_mmio(struct smtcfb_info *sfb)
1331 if (sfb && smtc_regbaseaddress)
1332 smtc_regbaseaddress = NULL;
1336 * Map in the screen memory
1339 static int smtc_map_smem(struct smtcfb_info *sfb,
1340 struct pci_dev *pdev, u_long smem_len)
1342 sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
1345 if (sfb->fb->var.bits_per_pixel == 32)
1346 sfb->fb->fix.smem_start += 0x800000;
1349 sfb->fb->fix.smem_len = smem_len;
1351 sfb->fb->screen_base = sfb->lfb;
1353 if (!sfb->fb->screen_base) {
1355 "%s: unable to map screen memory\n", sfb->fb->fix.id);
1363 * Unmap in the screen memory
1366 static void smtc_unmap_smem(struct smtcfb_info *sfb)
1368 if (sfb && sfb->fb->screen_base) {
1369 iounmap(sfb->fb->screen_base);
1370 sfb->fb->screen_base = NULL;
1375 * We need to wake up the device and make sure its in linear memory mode.
1377 static inline void sm7xx_init_hw(void)
1379 outb_p(0x18, 0x3c4);
1380 outb_p(0x11, 0x3c5);
1383 static int smtcfb_pci_probe(struct pci_dev *pdev,
1384 const struct pci_device_id *ent)
1386 struct smtcfb_info *sfb;
1387 struct fb_info *info;
1388 u_long smem_size = 0x00800000; /* default 8MB */
1390 unsigned long mmio_base;
1392 dev_info(&pdev->dev, "Silicon Motion display driver.\n");
1394 err = pci_enable_device(pdev); /* enable SMTC chip */
1398 err = pci_request_region(pdev, 0, "sm7xxfb");
1400 dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
1401 goto failed_regions;
1404 sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
1406 info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
1408 dev_err(&pdev->dev, "framebuffer_alloc failed\n");
1415 sfb->chip_id = ent->device;
1417 info->flags = FBINFO_FLAG_DEFAULT;
1418 info->fbops = &smtcfb_ops;
1419 info->fix = smtcfb_fix;
1420 info->var = smtcfb_var;
1421 info->pseudo_palette = sfb->colreg;
1424 pci_set_drvdata(pdev, sfb);
1428 /* get mode parameter from smtc_scr_info */
1429 if (smtc_scr_info.lfb_width != 0) {
1430 sfb->fb->var.xres = smtc_scr_info.lfb_width;
1431 sfb->fb->var.yres = smtc_scr_info.lfb_height;
1432 sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth;
1434 /* default resolution 1024x600 16bit mode */
1435 sfb->fb->var.xres = SCREEN_X_RES;
1436 sfb->fb->var.yres = SCREEN_Y_RES;
1437 sfb->fb->var.bits_per_pixel = SCREEN_BPP;
1441 if (sfb->fb->var.bits_per_pixel == 24)
1442 sfb->fb->var.bits_per_pixel = (smtc_scr_info.lfb_depth = 32);
1444 /* Map address and memory detection */
1445 mmio_base = pci_resource_start(pdev, 0);
1446 pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
1448 switch (sfb->chip_id) {
1451 sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
1452 sfb->fb->fix.mmio_len = 0x00400000;
1453 smem_size = SM712_VIDEOMEMORYSIZE;
1455 sfb->lfb = ioremap(mmio_base, 0x00c00000);
1457 sfb->lfb = ioremap(mmio_base, 0x00800000);
1459 sfb->mmio = (smtc_regbaseaddress =
1460 sfb->lfb + 0x00700000);
1461 sfb->dp_regs = sfb->lfb + 0x00408000;
1462 sfb->vp_regs = sfb->lfb + 0x0040c000;
1464 if (sfb->fb->var.bits_per_pixel == 32) {
1465 sfb->lfb += 0x800000;
1466 dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb);
1469 if (!smtc_regbaseaddress) {
1471 "%s: unable to map memory mapped IO!\n",
1477 /* set MCLK = 14.31818 * (0x16 / 0x2) */
1478 smtc_seqw(0x6a, 0x16);
1479 smtc_seqw(0x6b, 0x02);
1480 smtc_seqw(0x62, 0x3e);
1481 /* enable PCI burst */
1482 smtc_seqw(0x17, 0x20);
1483 /* enable word swap */
1485 if (sfb->fb->var.bits_per_pixel == 32)
1486 smtc_seqw(0x17, 0x30);
1490 sfb->fb->fix.mmio_start = mmio_base;
1491 sfb->fb->fix.mmio_len = 0x00200000;
1492 smem_size = SM722_VIDEOMEMORYSIZE;
1493 sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
1494 sfb->lfb = sfb->dp_regs + 0x00200000;
1495 sfb->mmio = (smtc_regbaseaddress =
1496 sfb->dp_regs + 0x000c0000);
1497 sfb->vp_regs = sfb->dp_regs + 0x800;
1499 smtc_seqw(0x62, 0xff);
1500 smtc_seqw(0x6a, 0x0d);
1501 smtc_seqw(0x6b, 0x02);
1505 "No valid Silicon Motion display chip was detected!\n");
1510 /* can support 32 bpp */
1511 if (15 == sfb->fb->var.bits_per_pixel)
1512 sfb->fb->var.bits_per_pixel = 16;
1514 sfb->fb->var.xres_virtual = sfb->fb->var.xres;
1515 sfb->fb->var.yres_virtual = sfb->fb->var.yres;
1516 err = smtc_map_smem(sfb, pdev, smem_size);
1520 smtcfb_setmode(sfb);
1522 err = register_framebuffer(info);
1526 dev_info(&pdev->dev,
1527 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n",
1528 sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres,
1529 sfb->fb->var.yres, sfb->fb->var.bits_per_pixel);
1534 dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n");
1536 smtc_unmap_smem(sfb);
1537 smtc_unmap_mmio(sfb);
1539 framebuffer_release(info);
1542 pci_release_region(pdev, 0);
1545 pci_disable_device(pdev);
1553 * 0x720 (Lynx3DM, Lynx3DM+)
1555 static const struct pci_device_id smtcfb_pci_table[] = {
1556 { PCI_DEVICE(0x126f, 0x710), },
1557 { PCI_DEVICE(0x126f, 0x712), },
1558 { PCI_DEVICE(0x126f, 0x720), },
1562 MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
1564 static void smtcfb_pci_remove(struct pci_dev *pdev)
1566 struct smtcfb_info *sfb;
1568 sfb = pci_get_drvdata(pdev);
1569 smtc_unmap_smem(sfb);
1570 smtc_unmap_mmio(sfb);
1571 unregister_framebuffer(sfb->fb);
1572 framebuffer_release(sfb->fb);
1573 pci_release_region(pdev, 0);
1574 pci_disable_device(pdev);
1578 static int smtcfb_pci_suspend(struct device *device)
1580 struct pci_dev *pdev = to_pci_dev(device);
1581 struct smtcfb_info *sfb;
1583 sfb = pci_get_drvdata(pdev);
1585 /* set the hw in sleep mode use external clock and self memory refresh
1586 * so that we can turn off internal PLLs later on
1588 smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1589 smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1592 fb_set_suspend(sfb->fb, 1);
1595 /* additionally turn off all function blocks including internal PLLs */
1596 smtc_seqw(0x21, 0xff);
1601 static int smtcfb_pci_resume(struct device *device)
1603 struct pci_dev *pdev = to_pci_dev(device);
1604 struct smtcfb_info *sfb;
1606 sfb = pci_get_drvdata(pdev);
1608 /* reinit hardware */
1610 switch (sfb->chip_id) {
1613 /* set MCLK = 14.31818 * (0x16 / 0x2) */
1614 smtc_seqw(0x6a, 0x16);
1615 smtc_seqw(0x6b, 0x02);
1616 smtc_seqw(0x62, 0x3e);
1617 /* enable PCI burst */
1618 smtc_seqw(0x17, 0x20);
1620 if (sfb->fb->var.bits_per_pixel == 32)
1621 smtc_seqw(0x17, 0x30);
1625 smtc_seqw(0x62, 0xff);
1626 smtc_seqw(0x6a, 0x0d);
1627 smtc_seqw(0x6b, 0x02);
1631 smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1632 smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1634 smtcfb_setmode(sfb);
1637 fb_set_suspend(sfb->fb, 0);
1643 static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1644 #define SM7XX_PM_OPS (&sm7xx_pm_ops)
1646 #else /* !CONFIG_PM */
1648 #define SM7XX_PM_OPS NULL
1650 #endif /* !CONFIG_PM */
1652 static struct pci_driver smtcfb_driver = {
1654 .id_table = smtcfb_pci_table,
1655 .probe = smtcfb_pci_probe,
1656 .remove = smtcfb_pci_remove,
1657 .driver.pm = SM7XX_PM_OPS,
1660 static int __init sm712fb_init(void)
1663 char *option = NULL;
1665 if (fb_get_options("sm712fb", &option))
1667 if (option && *option)
1668 mode_option = option;
1670 sm7xx_vga_setup(mode_option);
1672 return pci_register_driver(&smtcfb_driver);
1675 module_init(sm712fb_init);
1677 static void __exit sm712fb_exit(void)
1679 pci_unregister_driver(&smtcfb_driver);
1682 module_exit(sm712fb_exit);
1684 MODULE_AUTHOR("Siliconmotion ");
1685 MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1686 MODULE_LICENSE("GPL");