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

source code of linux/drivers/video/fbdev/sm712fb.c