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