aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/sis/sis_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/sis/sis_main.c')
-rw-r--r--drivers/video/sis/sis_main.c6027
1 files changed, 6027 insertions, 0 deletions
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
new file mode 100644
index 000000000000..b773c98f6513
--- /dev/null
+++ b/drivers/video/sis/sis_main.c
@@ -0,0 +1,6027 @@
1/*
2 * SiS 300/305/540/630(S)/730(S)
3 * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760
4 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
5 *
6 * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the named License,
11 * or any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
21 *
22 * Author: Thomas Winischhofer <thomas@winischhofer.net>
23 *
24 * Author of (practically wiped) code base:
25 * SiS (www.sis.com)
26 * Copyright (C) 1999 Silicon Integrated Systems, Inc.
27 *
28 * See http://www.winischhofer.net/ for more information and updates
29 *
30 * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
31 * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
32 *
33 */
34
35#include <linux/config.h>
36#include <linux/version.h>
37#include <linux/module.h>
38#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
39#include <linux/moduleparam.h>
40#endif
41#include <linux/kernel.h>
42#include <linux/smp_lock.h>
43#include <linux/spinlock.h>
44#include <linux/errno.h>
45#include <linux/string.h>
46#include <linux/mm.h>
47#include <linux/tty.h>
48#include <linux/slab.h>
49#include <linux/delay.h>
50#include <linux/fb.h>
51#include <linux/console.h>
52#include <linux/selection.h>
53#include <linux/smp_lock.h>
54#include <linux/ioport.h>
55#include <linux/init.h>
56#include <linux/pci.h>
57#include <linux/vmalloc.h>
58#include <linux/vt_kern.h>
59#include <linux/capability.h>
60#include <linux/fs.h>
61#include <linux/types.h>
62#include <asm/uaccess.h>
63#include <asm/io.h>
64#ifdef CONFIG_MTRR
65#include <asm/mtrr.h>
66#endif
67
68#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
69#include <video/fbcon.h>
70#include <video/fbcon-cfb8.h>
71#include <video/fbcon-cfb16.h>
72#include <video/fbcon-cfb24.h>
73#include <video/fbcon-cfb32.h>
74#endif
75
76#include "sis.h"
77#include "sis_main.h"
78
79#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
80#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
81#error "This version of sisfb requires at least 2.6.3"
82#endif
83#endif
84
85#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
86#ifdef FBCON_HAS_CFB8
87extern struct display_switch fbcon_sis8;
88#endif
89#ifdef FBCON_HAS_CFB16
90extern struct display_switch fbcon_sis16;
91#endif
92#ifdef FBCON_HAS_CFB32
93extern struct display_switch fbcon_sis32;
94#endif
95#endif
96
97/* ------------------ Internal helper routines ----------------- */
98
99static void __init
100sisfb_setdefaultparms(void)
101{
102 sisfb_off = 0;
103 sisfb_parm_mem = 0;
104 sisfb_accel = -1;
105 sisfb_ypan = -1;
106 sisfb_max = -1;
107 sisfb_userom = -1;
108 sisfb_useoem = -1;
109#ifdef MODULE
110 /* Module: "None" for 2.4, default mode for 2.5+ */
111#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
112 sisfb_mode_idx = -1;
113#else
114 sisfb_mode_idx = MODE_INDEX_NONE;
115#endif
116#else
117 /* Static: Default mode */
118 sisfb_mode_idx = -1;
119#endif
120 sisfb_parm_rate = -1;
121 sisfb_crt1off = 0;
122 sisfb_forcecrt1 = -1;
123 sisfb_crt2type = -1;
124 sisfb_crt2flags = 0;
125 sisfb_pdc = 0xff;
126 sisfb_pdca = 0xff;
127 sisfb_scalelcd = -1;
128 sisfb_specialtiming = CUT_NONE;
129 sisfb_lvdshl = -1;
130 sisfb_dstn = 0;
131 sisfb_fstn = 0;
132 sisfb_tvplug = -1;
133 sisfb_tvstd = -1;
134 sisfb_tvxposoffset = 0;
135 sisfb_tvyposoffset = 0;
136 sisfb_filter = -1;
137 sisfb_nocrt2rate = 0;
138#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
139 sisfb_inverse = 0;
140 sisfb_fontname[0] = 0;
141#endif
142#if !defined(__i386__) && !defined(__x86_64__)
143 sisfb_resetcard = 0;
144 sisfb_videoram = 0;
145#endif
146}
147
148static void __devinit
149sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
150{
151 int i = 0, j = 0;
152
153 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
154
155 if(vesamode == 0) {
156#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
157 sisfb_mode_idx = MODE_INDEX_NONE;
158#else
159 if(!quiet) {
160 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
161 }
162 sisfb_mode_idx = DEFAULT_MODE;
163#endif
164 return;
165 }
166
167 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
168
169 while(sisbios_mode[i++].mode_no[0] != 0) {
170 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
171 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
172 if(sisfb_fstn) {
173 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
174 sisbios_mode[i-1].mode_no[1] == 0x56 ||
175 sisbios_mode[i-1].mode_no[1] == 0x53) continue;
176 } else {
177 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
178 sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
179 }
180 sisfb_mode_idx = i - 1;
181 j = 1;
182 break;
183 }
184 }
185 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
186}
187
188static void
189sisfb_search_mode(char *name, BOOLEAN quiet)
190{
191 int i = 0;
192 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
193 char strbuf[16], strbuf1[20];
194 char *nameptr = name;
195
196 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
197
198 if(name == NULL) {
199 if(!quiet) {
200 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
201 }
202 sisfb_mode_idx = DEFAULT_MODE;
203 return;
204 }
205
206#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
207 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
208 if(!quiet) {
209 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
210 }
211 sisfb_mode_idx = DEFAULT_MODE;
212 return;
213 }
214#endif
215 if(strlen(name) <= 19) {
216 strcpy(strbuf1, name);
217 for(i=0; i<strlen(strbuf1); i++) {
218 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
219 }
220
221 /* This does some fuzzy mode naming detection */
222 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
223 if((rate <= 32) || (depth > 32)) {
224 j = rate; rate = depth; depth = j;
225 }
226 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
227 nameptr = strbuf;
228 sisfb_parm_rate = rate;
229 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
230 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
231 nameptr = strbuf;
232 } else {
233 xres = 0;
234 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
235 sprintf(strbuf, "%ux%ux8", xres, yres);
236 nameptr = strbuf;
237 } else {
238 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
239 return;
240 }
241 }
242 }
243
244 i = 0; j = 0;
245 while(sisbios_mode[i].mode_no[0] != 0) {
246 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
247 if(sisfb_fstn) {
248 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
249 sisbios_mode[i-1].mode_no[1] == 0x56 ||
250 sisbios_mode[i-1].mode_no[1] == 0x53) continue;
251 } else {
252 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
253 sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
254 }
255 sisfb_mode_idx = i - 1;
256 j = 1;
257 break;
258 }
259 }
260 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
261}
262
263#ifndef MODULE
264static void __devinit
265sisfb_get_vga_mode_from_kernel(void)
266{
267#if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
268 char mymode[32];
269 int mydepth = screen_info.lfb_depth;
270
271 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
272
273 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
274 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
275 (mydepth >= 8) && (mydepth <= 32) ) {
276
277 if(mydepth == 24) mydepth = 32;
278
279 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
280 screen_info.lfb_height,
281 mydepth);
282
283 printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode);
284
285 sisfb_search_mode(mymode, TRUE);
286 }
287#endif
288 return;
289}
290#endif
291
292static void __init
293sisfb_search_crt2type(const char *name)
294{
295 int i = 0;
296
297 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
298
299 if(name == NULL) return;
300
301 while(sis_crt2type[i].type_no != -1) {
302 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
303 sisfb_crt2type = sis_crt2type[i].type_no;
304 sisfb_tvplug = sis_crt2type[i].tvplug_no;
305 sisfb_crt2flags = sis_crt2type[i].flags;
306 break;
307 }
308 i++;
309 }
310
311 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
312 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
313
314 if(sisfb_crt2type < 0) {
315 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
316 }
317}
318
319static void __init
320sisfb_search_tvstd(const char *name)
321{
322 int i = 0;
323
324 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
325
326 if(name == NULL) return;
327
328 while(sis_tvtype[i].type_no != -1) {
329 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
330 sisfb_tvstd = sis_tvtype[i].type_no;
331 break;
332 }
333 i++;
334 }
335}
336
337static void __init
338sisfb_search_specialtiming(const char *name)
339{
340 int i = 0;
341 BOOLEAN found = FALSE;
342
343 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
344
345 if(name == NULL) return;
346
347 if(!strnicmp(name, "none", 4)) {
348 sisfb_specialtiming = CUT_FORCENONE;
349 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
350 } else {
351 while(mycustomttable[i].chipID != 0) {
352 if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {
353 sisfb_specialtiming = mycustomttable[i].SpecialID;
354 found = TRUE;
355 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
356 mycustomttable[i].vendorName, mycustomttable[i].cardName,
357 mycustomttable[i].optionName);
358 break;
359 }
360 i++;
361 }
362 if(!found) {
363 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
364 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
365 i = 0;
366 while(mycustomttable[i].chipID != 0) {
367 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
368 mycustomttable[i].optionName,
369 mycustomttable[i].vendorName,
370 mycustomttable[i].cardName);
371 i++;
372 }
373 }
374 }
375}
376
377static BOOLEAN __devinit
378sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
379{
380 int i, j, xres, yres, refresh, index;
381 u32 emodes;
382
383 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
384 buffer[2] != 0xff || buffer[3] != 0xff ||
385 buffer[4] != 0xff || buffer[5] != 0xff ||
386 buffer[6] != 0xff || buffer[7] != 0x00) {
387 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
388 return FALSE;
389 }
390
391 if(buffer[0x12] != 0x01) {
392 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
393 buffer[0x12]);
394 return FALSE;
395 }
396
397 monitor->feature = buffer[0x18];
398
399 if(!buffer[0x14] & 0x80) {
400 if(!(buffer[0x14] & 0x08)) {
401 printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n");
402 }
403 }
404
405 if(buffer[0x13] >= 0x01) {
406 /* EDID V1 rev 1 and 2: Search for monitor descriptor
407 * to extract ranges
408 */
409 j = 0x36;
410 for(i=0; i<4; i++) {
411 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
412 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
413 buffer[j + 4] == 0x00) {
414 monitor->hmin = buffer[j + 7];
415 monitor->hmax = buffer[j + 8];
416 monitor->vmin = buffer[j + 5];
417 monitor->vmax = buffer[j + 6];
418 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
419 monitor->datavalid = TRUE;
420 break;
421 }
422 j += 18;
423 }
424 }
425
426 if(!monitor->datavalid) {
427 /* Otherwise: Get a range from the list of supported
428 * Estabished Timings. This is not entirely accurate,
429 * because fixed frequency monitors are not supported
430 * that way.
431 */
432 monitor->hmin = 65535; monitor->hmax = 0;
433 monitor->vmin = 65535; monitor->vmax = 0;
434 monitor->dclockmax = 0;
435 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
436 for(i = 0; i < 13; i++) {
437 if(emodes & sisfb_ddcsmodes[i].mask) {
438 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
439 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
440 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
441 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
442 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
443 }
444 }
445 index = 0x26;
446 for(i = 0; i < 8; i++) {
447 xres = (buffer[index] + 31) * 8;
448 switch(buffer[index + 1] & 0xc0) {
449 case 0xc0: yres = (xres * 9) / 16; break;
450 case 0x80: yres = (xres * 4) / 5; break;
451 case 0x40: yres = (xres * 3) / 4; break;
452 default: yres = xres; break;
453 }
454 refresh = (buffer[index + 1] & 0x3f) + 60;
455 if((xres >= 640) && (yres >= 480)) {
456 for(j = 0; j < 8; j++) {
457 if((xres == sisfb_ddcfmodes[j].x) &&
458 (yres == sisfb_ddcfmodes[j].y) &&
459 (refresh == sisfb_ddcfmodes[j].v)) {
460 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
461 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
462 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
463 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
464 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
465 }
466 }
467 }
468 index += 2;
469 }
470 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
471 monitor->datavalid = TRUE;
472 }
473 }
474
475 return(monitor->datavalid);
476}
477
478static void __devinit
479sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
480{
481 USHORT temp, i, realcrtno = crtno;
482 u8 buffer[256];
483
484 monitor->datavalid = FALSE;
485
486 if(crtno) {
487 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
488 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
489 else return;
490 }
491
492 if((ivideo->sisfb_crt1off) && (!crtno)) return;
493
494 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
495 realcrtno, 0, &buffer[0]);
496 if((!temp) || (temp == 0xffff)) {
497 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
498 return;
499 } else {
500 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
501 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
502 crtno + 1,
503 (temp & 0x1a) ? "" : "[none of the supported]",
504 (temp & 0x02) ? "2 " : "",
505 (temp & 0x08) ? "D&P" : "",
506 (temp & 0x10) ? "FPDI-2" : "");
507 if(temp & 0x02) {
508 i = 3; /* Number of retrys */
509 do {
510 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
511 realcrtno, 1, &buffer[0]);
512 } while((temp) && i--);
513 if(!temp) {
514 if(sisfb_interpret_edid(monitor, &buffer[0])) {
515 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
516 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
517 monitor->dclockmax / 1000);
518 } else {
519 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
520 }
521 } else {
522 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
523 }
524 } else {
525 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
526 }
527 }
528}
529
530static BOOLEAN
531sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
532 int mode_idx, int rate_idx, int rate)
533{
534 int htotal, vtotal;
535 unsigned int dclock, hsync;
536
537 if(!monitor->datavalid) return TRUE;
538
539 if(mode_idx < 0) return FALSE;
540
541 /* Skip for 320x200, 320x240, 640x400 */
542 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
543 case 0x59:
544 case 0x41:
545 case 0x4f:
546 case 0x50:
547 case 0x56:
548 case 0x53:
549 case 0x2f:
550 case 0x5d:
551 case 0x5e:
552 return TRUE;
553#ifdef CONFIG_FB_SIS_315
554 case 0x5a:
555 case 0x5b:
556 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
557#endif
558 }
559
560 if(rate < (monitor->vmin - 1)) return FALSE;
561 if(rate > (monitor->vmax + 1)) return FALSE;
562
563 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, &ivideo->sishw_ext,
564 sisbios_mode[mode_idx].mode_no[ivideo->mni],
565 &htotal, &vtotal, rate_idx)) {
566 dclock = (htotal * vtotal * rate) / 1000;
567 if(dclock > (monitor->dclockmax + 1000)) return FALSE;
568 hsync = dclock / htotal;
569 if(hsync < (monitor->hmin - 1)) return FALSE;
570 if(hsync > (monitor->hmax + 1)) return FALSE;
571 } else {
572 return FALSE;
573 }
574 return TRUE;
575}
576
577static int
578sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
579{
580 u16 xres=0, yres, myres;
581
582#ifdef CONFIG_FB_SIS_300
583 if(ivideo->sisvga_engine == SIS_300_VGA) {
584 if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1);
585 }
586#endif
587#ifdef CONFIG_FB_SIS_315
588 if(ivideo->sisvga_engine == SIS_315_VGA) {
589 if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1);
590 }
591#endif
592
593 myres = sisbios_mode[myindex].yres;
594
595 switch(vbflags & VB_DISPTYPE_DISP2) {
596
597 case CRT2_LCD:
598
599 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
600
601 if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) {
602 if(sisbios_mode[myindex].xres > xres) return(-1);
603 if(myres > yres) return(-1);
604 }
605
606 if(vbflags & (VB_LVDS | VB_30xBDH)) {
607 if(sisbios_mode[myindex].xres == 320) {
608 if((myres == 240) || (myres == 480)) {
609 if(!ivideo->sisfb_fstn) {
610 if(sisbios_mode[myindex].mode_no[1] == 0x5a ||
611 sisbios_mode[myindex].mode_no[1] == 0x5b)
612 return(-1);
613 } else {
614 if(sisbios_mode[myindex].mode_no[1] == 0x50 ||
615 sisbios_mode[myindex].mode_no[1] == 0x56 ||
616 sisbios_mode[myindex].mode_no[1] == 0x53)
617 return(-1);
618 }
619 }
620 }
621 }
622
623 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
624 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
625 ivideo->SiS_Pr.SiS_CustomT, xres, yres) < 0x14) {
626 return(-1);
627 }
628 break;
629
630 case CRT2_TV:
631 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
632 sisbios_mode[myindex].yres, 0) < 0x14) {
633 return(-1);
634 }
635 break;
636
637 case CRT2_VGA:
638 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
639 sisbios_mode[myindex].yres, 0) < 0x14) {
640 return(-1);
641 }
642 break;
643 }
644
645 return(myindex);
646}
647
648static u8
649sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
650{
651 u16 xres, yres;
652 int i = 0;
653
654 xres = sisbios_mode[mode_idx].xres;
655 yres = sisbios_mode[mode_idx].yres;
656
657 ivideo->rate_idx = 0;
658 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
659 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
660 if(sisfb_vrate[i].refresh == rate) {
661 ivideo->rate_idx = sisfb_vrate[i].idx;
662 break;
663 } else if(sisfb_vrate[i].refresh > rate) {
664 if((sisfb_vrate[i].refresh - rate) <= 3) {
665 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
666 rate, sisfb_vrate[i].refresh);
667 ivideo->rate_idx = sisfb_vrate[i].idx;
668 ivideo->refresh_rate = sisfb_vrate[i].refresh;
669 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
670 && (sisfb_vrate[i].idx != 1)) {
671 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
672 rate, sisfb_vrate[i-1].refresh);
673 ivideo->rate_idx = sisfb_vrate[i-1].idx;
674 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
675 }
676 break;
677 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
678 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
679 rate, sisfb_vrate[i].refresh);
680 ivideo->rate_idx = sisfb_vrate[i].idx;
681 break;
682 }
683 }
684 i++;
685 }
686 if(ivideo->rate_idx > 0) {
687 return ivideo->rate_idx;
688 } else {
689 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
690 rate, xres, yres);
691 return 0;
692 }
693}
694
695static BOOLEAN
696sisfb_bridgeisslave(struct sis_video_info *ivideo)
697{
698 unsigned char P1_00;
699
700 if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE;
701
702 inSISIDXREG(SISPART1,0x00,P1_00);
703 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
704 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
705 return TRUE;
706 } else {
707 return FALSE;
708 }
709}
710
711static BOOLEAN
712sisfballowretracecrt1(struct sis_video_info *ivideo)
713{
714 u8 temp;
715
716 inSISIDXREG(SISCR,0x17,temp);
717 if(!(temp & 0x80)) return FALSE;
718
719 inSISIDXREG(SISSR,0x1f,temp);
720 if(temp & 0xc0) return FALSE;
721
722 return TRUE;
723}
724
725static BOOLEAN
726sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
727{
728 if(!sisfballowretracecrt1(ivideo)) return FALSE;
729
730 if(inSISREG(SISINPSTAT) & 0x08) return TRUE;
731 else return FALSE;
732}
733
734static void
735sisfbwaitretracecrt1(struct sis_video_info *ivideo)
736{
737 int watchdog;
738
739 if(!sisfballowretracecrt1(ivideo)) return;
740
741 watchdog = 65536;
742 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
743 watchdog = 65536;
744 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
745}
746
747static BOOLEAN
748sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
749{
750 unsigned char temp, reg;
751
752 switch(ivideo->sisvga_engine) {
753 case SIS_300_VGA: reg = 0x25; break;
754 case SIS_315_VGA: reg = 0x30; break;
755 default: return FALSE;
756 }
757
758 inSISIDXREG(SISPART1, reg, temp);
759 if(temp & 0x02) return TRUE;
760 else return FALSE;
761}
762
763static BOOLEAN
764sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
765{
766 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
767 if(sisfb_bridgeisslave(ivideo)) {
768 return(sisfbcheckvretracecrt1(ivideo));
769 } else {
770 return(sisfbcheckvretracecrt2(ivideo));
771 }
772 }
773 return(sisfbcheckvretracecrt1(ivideo));
774}
775
776static u32
777sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
778{
779 u8 idx, reg1, reg2, reg3, reg4;
780 u32 ret = 0;
781
782 (*vcount) = (*hcount) = 0;
783
784 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
785 ret |= (FB_VBLANK_HAVE_VSYNC |
786 FB_VBLANK_HAVE_HBLANK |
787 FB_VBLANK_HAVE_VBLANK |
788 FB_VBLANK_HAVE_VCOUNT |
789 FB_VBLANK_HAVE_HCOUNT);
790 switch(ivideo->sisvga_engine) {
791 case SIS_300_VGA: idx = 0x25; break;
792 default:
793 case SIS_315_VGA: idx = 0x30; break;
794 }
795 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
796 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
797 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
798 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
799 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
800 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
801 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
802 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
803 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
804 } else if(sisfballowretracecrt1(ivideo)) {
805 ret |= (FB_VBLANK_HAVE_VSYNC |
806 FB_VBLANK_HAVE_VBLANK |
807 FB_VBLANK_HAVE_VCOUNT |
808 FB_VBLANK_HAVE_HCOUNT);
809 reg1 = inSISREG(SISINPSTAT);
810 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
811 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
812 inSISIDXREG(SISCR,0x20,reg1);
813 inSISIDXREG(SISCR,0x1b,reg1);
814 inSISIDXREG(SISCR,0x1c,reg2);
815 inSISIDXREG(SISCR,0x1d,reg3);
816 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
817 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
818 }
819 return ret;
820}
821
822static int
823sisfb_myblank(struct sis_video_info *ivideo, int blank)
824{
825 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
826 BOOLEAN backlight = TRUE;
827
828 switch(blank) {
829 case FB_BLANK_UNBLANK: /* on */
830 sr01 = 0x00;
831 sr11 = 0x00;
832 sr1f = 0x00;
833 cr63 = 0x00;
834 p2_0 = 0x20;
835 p1_13 = 0x00;
836 backlight = TRUE;
837 break;
838 case FB_BLANK_NORMAL: /* blank */
839 sr01 = 0x20;
840 sr11 = 0x00;
841 sr1f = 0x00;
842 cr63 = 0x00;
843 p2_0 = 0x20;
844 p1_13 = 0x00;
845 backlight = TRUE;
846 break;
847 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
848 sr01 = 0x20;
849 sr11 = 0x08;
850 sr1f = 0x80;
851 cr63 = 0x40;
852 p2_0 = 0x40;
853 p1_13 = 0x80;
854 backlight = FALSE;
855 break;
856 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
857 sr01 = 0x20;
858 sr11 = 0x08;
859 sr1f = 0x40;
860 cr63 = 0x40;
861 p2_0 = 0x80;
862 p1_13 = 0x40;
863 backlight = FALSE;
864 break;
865 case FB_BLANK_POWERDOWN: /* off */
866 sr01 = 0x20;
867 sr11 = 0x08;
868 sr1f = 0xc0;
869 cr63 = 0x40;
870 p2_0 = 0xc0;
871 p1_13 = 0xc0;
872 backlight = FALSE;
873 break;
874 default:
875 return 1;
876 }
877
878 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
879
880 if( (!ivideo->sisfb_thismonitor.datavalid) ||
881 ((ivideo->sisfb_thismonitor.datavalid) &&
882 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
883
884 if(ivideo->sisvga_engine == SIS_315_VGA) {
885 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
886 }
887
888 if(!(sisfb_bridgeisslave(ivideo))) {
889 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
890 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
891 }
892 }
893
894 }
895
896 if(ivideo->currentvbflags & CRT2_LCD) {
897
898 if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
899 if(backlight) {
900 SiS_SiS30xBLOn(&ivideo->SiS_Pr, &ivideo->sishw_ext);
901 } else {
902 SiS_SiS30xBLOff(&ivideo->SiS_Pr, &ivideo->sishw_ext);
903 }
904 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
905 if(ivideo->vbflags & VB_CHRONTEL) {
906 if(backlight) {
907 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr,&ivideo->sishw_ext);
908 } else {
909 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
910 }
911 }
912 }
913
914 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
915 (ivideo->vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
916 ((ivideo->sisvga_engine == SIS_315_VGA) &&
917 ((ivideo->vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
918 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
919 }
920
921 if(ivideo->sisvga_engine == SIS_300_VGA) {
922 if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
923 (!(ivideo->vbflags & VB_30xBDH))) {
924 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
925 }
926 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
927 if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
928 (!(ivideo->vbflags & VB_30xBDH))) {
929 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
930 }
931 }
932
933 } else if(ivideo->currentvbflags & CRT2_VGA) {
934
935 if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) {
936 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
937 }
938
939 }
940
941 return(0);
942}
943
944/* ----------- FBDev related routines for all series ----------- */
945
946static int
947sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
948{
949 return (var->bits_per_pixel == 8) ? 256 : 16;
950}
951
952static void
953sisfb_set_vparms(struct sis_video_info *ivideo)
954{
955 switch(ivideo->video_bpp) {
956 case 8:
957 ivideo->DstColor = 0x0000;
958 ivideo->SiS310_AccelDepth = 0x00000000;
959 ivideo->video_cmap_len = 256;
960 break;
961 case 16:
962 ivideo->DstColor = 0x8000;
963 ivideo->SiS310_AccelDepth = 0x00010000;
964 ivideo->video_cmap_len = 16;
965 break;
966 case 32:
967 ivideo->DstColor = 0xC000;
968 ivideo->SiS310_AccelDepth = 0x00020000;
969 ivideo->video_cmap_len = 16;
970 break;
971 default:
972 ivideo->video_cmap_len = 16;
973 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
974 ivideo->accel = 0;
975 break;
976 }
977}
978
979static int
980sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
981{
982 int maxyres = ivideo->heapstart / (var->xres_virtual * (var->bits_per_pixel >> 3));
983
984 if(maxyres > 32767) maxyres = 32767;
985
986 return maxyres;
987}
988
989static void
990sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
991{
992 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
993 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
994 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
995 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
996 ivideo->scrnpitchCRT1 <<= 1;
997 }
998 }
999
1000}
1001
1002static void
1003sisfb_set_pitch(struct sis_video_info *ivideo)
1004{
1005 BOOLEAN isslavemode = FALSE;
1006 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1007 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1008
1009 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
1010
1011 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1012 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1013 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1014 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1015 }
1016
1017 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1018 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1019 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1020 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1021 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1022 }
1023}
1024
1025static void
1026sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1027{
1028 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1029
1030 switch(var->bits_per_pixel) {
1031 case 8:
1032 var->red.offset = var->green.offset = var->blue.offset = 0;
1033 var->red.length = var->green.length = var->blue.length = 6;
1034 break;
1035 case 16:
1036 var->red.offset = 11;
1037 var->red.length = 5;
1038 var->green.offset = 5;
1039 var->green.length = 6;
1040 var->blue.offset = 0;
1041 var->blue.length = 5;
1042 var->transp.offset = 0;
1043 var->transp.length = 0;
1044 break;
1045 case 32:
1046 var->red.offset = 16;
1047 var->red.length = 8;
1048 var->green.offset = 8;
1049 var->green.length = 8;
1050 var->blue.offset = 0;
1051 var->blue.length = 8;
1052 var->transp.offset = 24;
1053 var->transp.length = 8;
1054 break;
1055 }
1056}
1057
1058static int
1059sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1060{
1061 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1062 unsigned int htotal = 0, vtotal = 0;
1063 unsigned int drate = 0, hrate = 0;
1064 int found_mode = 0;
1065 int old_mode;
1066 u32 pixclock;
1067
1068 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1069
1070 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1071
1072 pixclock = var->pixclock;
1073
1074 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1075 vtotal += var->yres;
1076 vtotal <<= 1;
1077 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1078 vtotal += var->yres;
1079 vtotal <<= 2;
1080 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1081 vtotal += var->yres;
1082 vtotal <<= 1;
1083 } else vtotal += var->yres;
1084
1085 if(!(htotal) || !(vtotal)) {
1086 DPRINTK("sisfb: Invalid 'var' information\n");
1087 return -EINVAL;
1088 }
1089
1090 if(pixclock && htotal && vtotal) {
1091 drate = 1000000000 / pixclock;
1092 hrate = (drate * 1000) / htotal;
1093 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1094 } else {
1095 ivideo->refresh_rate = 60;
1096 }
1097
1098 old_mode = ivideo->sisfb_mode_idx;
1099 ivideo->sisfb_mode_idx = 0;
1100
1101 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1102 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1103 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1104 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1105 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1106 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1107 found_mode = 1;
1108 break;
1109 }
1110 ivideo->sisfb_mode_idx++;
1111 }
1112
1113 if(found_mode) {
1114 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1115 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1116 } else {
1117 ivideo->sisfb_mode_idx = -1;
1118 }
1119
1120 if(ivideo->sisfb_mode_idx < 0) {
1121 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1122 var->yres, var->bits_per_pixel);
1123 ivideo->sisfb_mode_idx = old_mode;
1124 return -EINVAL;
1125 }
1126
1127 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1128 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1129 ivideo->refresh_rate = 60;
1130 }
1131
1132#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1133 if(ivideo->sisfb_thismonitor.datavalid) {
1134 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
1135 ivideo->rate_idx, ivideo->refresh_rate)) {
1136 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1137 }
1138 }
1139#endif
1140
1141#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1142 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1143#else
1144 if(isactive) {
1145#endif
1146 sisfb_pre_setmode(ivideo);
1147
1148 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
1149 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1150 return -EINVAL;
1151 }
1152
1153 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1154
1155 sisfb_post_setmode(ivideo);
1156
1157 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1158 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1159 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1160
1161 sisfb_calc_pitch(ivideo, var);
1162 sisfb_set_pitch(ivideo);
1163
1164 ivideo->accel = 0;
1165#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1166#ifdef STUPID_ACCELF_TEXT_SHIT
1167 if(var->accel_flags & FB_ACCELF_TEXT) {
1168 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1169 } else {
1170 info->flags |= FBINFO_HWACCEL_DISABLED;
1171 }
1172#endif
1173 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1174#else
1175 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1176#endif
1177
1178 sisfb_set_vparms(ivideo);
1179
1180 ivideo->current_width = ivideo->video_width;
1181 ivideo->current_height = ivideo->video_height;
1182 ivideo->current_bpp = ivideo->video_bpp;
1183 ivideo->current_htotal = htotal;
1184 ivideo->current_vtotal = vtotal;
1185 ivideo->current_linelength = ivideo->video_linelength;
1186 ivideo->current_pixclock = var->pixclock;
1187 ivideo->current_refresh_rate = ivideo->refresh_rate;
1188#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1189 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1190#endif
1191 }
1192
1193 return 0;
1194}
1195
1196static int
1197sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1198{
1199 unsigned int base;
1200
1201 if(var->xoffset > (var->xres_virtual - var->xres)) {
1202 return -EINVAL;
1203 }
1204 if(var->yoffset > (var->yres_virtual - var->yres)) {
1205 return -EINVAL;
1206 }
1207
1208 base = (var->yoffset * var->xres_virtual) + var->xoffset;
1209
1210 /* calculate base bpp dep. */
1211 switch(var->bits_per_pixel) {
1212 case 32:
1213 break;
1214 case 16:
1215 base >>= 1;
1216 break;
1217 case 8:
1218 default:
1219 base >>= 2;
1220 break;
1221 }
1222
1223 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1224
1225 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1226 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1227 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1228 if(ivideo->sisvga_engine == SIS_315_VGA) {
1229 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1230 }
1231 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1232 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1233 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1234 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1235 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1236 if(ivideo->sisvga_engine == SIS_315_VGA) {
1237 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1238 }
1239 }
1240 return 0;
1241}
1242
1243/* ------------ FBDev related routines for 2.4 series ----------- */
1244
1245#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1246
1247static void
1248sisfb_crtc_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1249{
1250 u16 VRE, VBE, VRS, VBS, VDE, VT;
1251 u16 HRE, HBE, HRS, HBS, HDE, HT;
1252 u8 sr_data, cr_data, cr_data2, cr_data3, mr_data;
1253 int A, B, C, D, E, F, temp;
1254 unsigned int hrate, drate, maxyres;
1255
1256 inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
1257
1258 if(sr_data & SIS_INTERLACED_MODE)
1259 var->vmode = FB_VMODE_INTERLACED;
1260 else
1261 var->vmode = FB_VMODE_NONINTERLACED;
1262
1263 switch((sr_data & 0x1C) >> 2) {
1264 case SIS_8BPP_COLOR_MODE:
1265 var->bits_per_pixel = 8;
1266 break;
1267 case SIS_16BPP_COLOR_MODE:
1268 var->bits_per_pixel = 16;
1269 break;
1270 case SIS_32BPP_COLOR_MODE:
1271 var->bits_per_pixel = 32;
1272 break;
1273 }
1274
1275 sisfb_bpp_to_var(ivideo, var);
1276
1277 inSISIDXREG(SISSR, 0x0A, sr_data);
1278 inSISIDXREG(SISCR, 0x06, cr_data);
1279 inSISIDXREG(SISCR, 0x07, cr_data2);
1280
1281 VT = (cr_data & 0xFF) |
1282 ((u16) (cr_data2 & 0x01) << 8) |
1283 ((u16) (cr_data2 & 0x20) << 4) |
1284 ((u16) (sr_data & 0x01) << 10);
1285 A = VT + 2;
1286
1287 inSISIDXREG(SISCR, 0x12, cr_data);
1288
1289 VDE = (cr_data & 0xff) |
1290 ((u16) (cr_data2 & 0x02) << 7) |
1291 ((u16) (cr_data2 & 0x40) << 3) |
1292 ((u16) (sr_data & 0x02) << 9);
1293 E = VDE + 1;
1294
1295 inSISIDXREG(SISCR, 0x10, cr_data);
1296
1297 VRS = (cr_data & 0xff) |
1298 ((u16) (cr_data2 & 0x04) << 6) |
1299 ((u16) (cr_data2 & 0x80) << 2) |
1300 ((u16) (sr_data & 0x08) << 7);
1301 F = VRS + 1 - E;
1302
1303 inSISIDXREG(SISCR, 0x15, cr_data);
1304 inSISIDXREG(SISCR, 0x09, cr_data3);
1305
1306 if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE;
1307
1308 VBS = (cr_data & 0xff) |
1309 ((u16) (cr_data2 & 0x08) << 5) |
1310 ((u16) (cr_data3 & 0x20) << 4) |
1311 ((u16) (sr_data & 0x04) << 8);
1312
1313 inSISIDXREG(SISCR, 0x16, cr_data);
1314
1315 VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
1316 temp = VBE - ((E - 1) & 511);
1317 B = (temp > 0) ? temp : (temp + 512);
1318
1319 inSISIDXREG(SISCR, 0x11, cr_data);
1320
1321 VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
1322 temp = VRE - ((E + F - 1) & 31);
1323 C = (temp > 0) ? temp : (temp + 32);
1324
1325 D = B - F - C;
1326
1327 var->yres = E;
1328 var->upper_margin = D;
1329 var->lower_margin = F;
1330 var->vsync_len = C;
1331
1332 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1333 var->yres <<= 1;
1334 var->upper_margin <<= 1;
1335 var->lower_margin <<= 1;
1336 var->vsync_len <<= 1;
1337 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1338 var->yres >>= 1;
1339 var->upper_margin >>= 1;
1340 var->lower_margin >>= 1;
1341 var->vsync_len >>= 1;
1342 }
1343
1344 inSISIDXREG(SISSR, 0x0b, sr_data);
1345 inSISIDXREG(SISCR, 0x00, cr_data);
1346
1347 HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
1348 A = HT + 5;
1349
1350 inSISIDXREG(SISCR, 0x01, cr_data);
1351
1352 HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
1353 E = HDE + 1;
1354
1355 inSISIDXREG(SISCR, 0x04, cr_data);
1356
1357 HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
1358 F = HRS - E - 3;
1359
1360 inSISIDXREG(SISCR, 0x02, cr_data);
1361
1362 HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
1363
1364 inSISIDXREG(SISSR, 0x0c, sr_data);
1365 inSISIDXREG(SISCR, 0x03, cr_data);
1366 inSISIDXREG(SISCR, 0x05, cr_data2);
1367
1368 HBE = (cr_data & 0x1f) |
1369 ((u16) (cr_data2 & 0x80) >> 2) |
1370 ((u16) (sr_data & 0x03) << 6);
1371 HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
1372
1373 temp = HBE - ((E - 1) & 255);
1374 B = (temp > 0) ? temp : (temp + 256);
1375
1376 temp = HRE - ((E + F + 3) & 63);
1377 C = (temp > 0) ? temp : (temp + 64);
1378
1379 D = B - F - C;
1380
1381 var->xres = E * 8;
1382 if(var->xres_virtual < var->xres) {
1383 var->xres_virtual = var->xres;
1384 }
1385
1386 if((var->xres == 320) &&
1387 (var->yres == 200 || var->yres == 240)) {
1388 /* Terrible hack, but the correct CRTC data for
1389 * these modes only produces a black screen...
1390 */
1391 var->left_margin = (400 - 376);
1392 var->right_margin = (328 - 320);
1393 var->hsync_len = (376 - 328);
1394 } else {
1395 var->left_margin = D * 8;
1396 var->right_margin = F * 8;
1397 var->hsync_len = C * 8;
1398 }
1399 var->activate = FB_ACTIVATE_NOW;
1400
1401 var->sync = 0;
1402
1403 mr_data = inSISREG(SISMISCR);
1404 if(mr_data & 0x80)
1405 var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
1406 else
1407 var->sync |= FB_SYNC_VERT_HIGH_ACT;
1408
1409 if(mr_data & 0x40)
1410 var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
1411 else
1412 var->sync |= FB_SYNC_HOR_HIGH_ACT;
1413
1414 VT += 2;
1415 VT <<= 1;
1416 HT = (HT + 5) * 8;
1417
1418 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1419 VT <<= 1;
1420 }
1421 hrate = ivideo->refresh_rate * VT / 2;
1422 drate = (hrate * HT) / 1000;
1423 var->pixclock = (u32) (1000000000 / drate);
1424
1425 if(ivideo->sisfb_ypan) {
1426 maxyres = sisfb_calc_maxyres(ivideo, var);
1427 if(ivideo->sisfb_max) {
1428 var->yres_virtual = maxyres;
1429 } else {
1430 if(var->yres_virtual > maxyres) {
1431 var->yres_virtual = maxyres;
1432 }
1433 }
1434 if(var->yres_virtual <= var->yres) {
1435 var->yres_virtual = var->yres;
1436 }
1437 } else {
1438 var->yres_virtual = var->yres;
1439 }
1440
1441}
1442
1443static int
1444sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
1445 unsigned *transp, struct fb_info *info)
1446{
1447 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1448
1449 if(regno >= ivideo->video_cmap_len) return 1;
1450
1451 *red = ivideo->sis_palette[regno].red;
1452 *green = ivideo->sis_palette[regno].green;
1453 *blue = ivideo->sis_palette[regno].blue;
1454 *transp = 0;
1455
1456 return 0;
1457}
1458
1459static int
1460sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1461 unsigned transp, struct fb_info *info)
1462{
1463 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1464
1465 if(regno >= ivideo->video_cmap_len) return 1;
1466
1467 ivideo->sis_palette[regno].red = red;
1468 ivideo->sis_palette[regno].green = green;
1469 ivideo->sis_palette[regno].blue = blue;
1470
1471 switch(ivideo->video_bpp) {
1472#ifdef FBCON_HAS_CFB8
1473 case 8:
1474 outSISREG(SISDACA, regno);
1475 outSISREG(SISDACD, (red >> 10));
1476 outSISREG(SISDACD, (green >> 10));
1477 outSISREG(SISDACD, (blue >> 10));
1478 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1479 outSISREG(SISDAC2A, regno);
1480 outSISREG(SISDAC2D, (red >> 8));
1481 outSISREG(SISDAC2D, (green >> 8));
1482 outSISREG(SISDAC2D, (blue >> 8));
1483 }
1484 break;
1485#endif
1486#ifdef FBCON_HAS_CFB16
1487 case 16:
1488 ivideo->sis_fbcon_cmap.cfb16[regno] =
1489 ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1490 break;
1491#endif
1492#ifdef FBCON_HAS_CFB32
1493 case 32:
1494 red >>= 8;
1495 green >>= 8;
1496 blue >>= 8;
1497 ivideo->sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
1498 break;
1499#endif
1500 }
1501
1502 return 0;
1503}
1504
1505static void
1506sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info)
1507{
1508 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1509 struct display *display;
1510 struct display_switch *sw;
1511 struct fb_fix_screeninfo fix;
1512 long flags;
1513
1514 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1515
1516 sisfb_get_fix(&fix, con, info);
1517
1518 display->var = *var;
1519 display->screen_base = (char *)ivideo->video_vbase;
1520 display->visual = fix.visual;
1521 display->type = fix.type;
1522 display->type_aux = fix.type_aux;
1523 display->ypanstep = fix.ypanstep;
1524 display->ywrapstep = fix.ywrapstep;
1525 display->line_length = fix.line_length;
1526 display->can_soft_blank = 1;
1527 display->inverse = ivideo->sisfb_inverse;
1528 display->next_line = fix.line_length;
1529
1530 save_flags(flags);
1531
1532 switch(ivideo->video_bpp) {
1533#ifdef FBCON_HAS_CFB8
1534 case 8: sw = ivideo->accel ? &fbcon_sis8 : &fbcon_cfb8;
1535 break;
1536#endif
1537#ifdef FBCON_HAS_CFB16
1538 case 16:sw = ivideo->accel ? &fbcon_sis16 : &fbcon_cfb16;
1539 display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb16;
1540 break;
1541#endif
1542#ifdef FBCON_HAS_CFB32
1543 case 32:sw = ivideo->accel ? &fbcon_sis32 : &fbcon_cfb32;
1544 display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb32;
1545 break;
1546#endif
1547 default:sw = &fbcon_dummy;
1548 break;
1549 }
1550 memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw));
1551 display->dispsw = &ivideo->sisfb_sw;
1552
1553 restore_flags(flags);
1554
1555 if(ivideo->sisfb_ypan) {
1556 /* display->scrollmode = 0; */
1557 } else {
1558 display->scrollmode = SCROLL_YREDRAW;
1559 ivideo->sisfb_sw.bmove = fbcon_redraw_bmove;
1560 }
1561}
1562
1563static void
1564sisfb_do_install_cmap(int con, struct fb_info *info)
1565{
1566 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1567
1568 if(con != ivideo->currcon) return;
1569
1570 if(fb_display[con].cmap.len) {
1571 fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
1572 } else {
1573 int size = sisfb_get_cmap_len(&fb_display[con].var);
1574 fb_set_cmap(fb_default_cmap(size), 1, sisfb_setcolreg, info);
1575 }
1576}
1577
1578static int
1579sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1580{
1581 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1582
1583 if(con == -1) {
1584 memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo));
1585 } else {
1586 *var = fb_display[con].var;
1587 }
1588
1589 if(ivideo->sisfb_fstn) {
1590 if(var->xres == 320 && var->yres == 480) var->yres = 240;
1591 }
1592
1593 return 0;
1594}
1595
1596static int
1597sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1598{
1599 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1600 int err;
1601
1602 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1603
1604 if(sisfb_do_set_var(var, con == ivideo->currcon, info)) {
1605 sisfb_crtc_to_var(ivideo, var);
1606 return -EINVAL;
1607 }
1608
1609 sisfb_crtc_to_var(ivideo, var);
1610
1611 sisfb_set_disp(con, var, info);
1612
1613 if(info->changevar) {
1614 (*info->changevar)(con);
1615 }
1616
1617 if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) {
1618 return err;
1619 }
1620
1621 sisfb_do_install_cmap(con, info);
1622
1623#if 0 /* Why was this called here? */
1624 unsigned int cols, rows;
1625 cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
1626 rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
1627 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1628#endif
1629 return 0;
1630}
1631
1632static int
1633sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1634{
1635 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1636 struct display *display;
1637
1638 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1639
1640 if(con == ivideo->currcon) {
1641
1642 return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
1643
1644 } else if(display->cmap.len) {
1645
1646 fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2);
1647
1648 } else {
1649
1650 int size = sisfb_get_cmap_len(&display->var);
1651 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
1652
1653 }
1654
1655 return 0;
1656}
1657
1658static int
1659sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1660{
1661 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1662 struct display *display;
1663 int err, size;
1664
1665 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1666
1667 size = sisfb_get_cmap_len(&display->var);
1668 if(display->cmap.len != size) {
1669 err = fb_alloc_cmap(&display->cmap, size, 0);
1670 if(err) return err;
1671 }
1672
1673 if(con == ivideo->currcon) {
1674 return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
1675 } else {
1676 fb_copy_cmap(cmap, &display->cmap, kspc ? 0 : 1);
1677 }
1678
1679 return 0;
1680}
1681
1682static int
1683sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info)
1684{
1685 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1686 int err;
1687
1688 if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
1689
1690 if((var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual) ||
1691 (var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)) {
1692 return -EINVAL;
1693 }
1694
1695 if(con == ivideo->currcon) {
1696 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
1697 }
1698
1699 fb_display[con].var.xoffset = var->xoffset;
1700 fb_display[con].var.yoffset = var->yoffset;
1701
1702 return 0;
1703}
1704
1705static int
1706sisfb_update_var(int con, struct fb_info *info)
1707{
1708 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1709
1710 return(sisfb_pan_var(ivideo, &fb_display[con].var));
1711}
1712
1713static int
1714sisfb_switch(int con, struct fb_info *info)
1715{
1716 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1717 int cols, rows;
1718
1719 if(fb_display[ivideo->currcon].cmap.len) {
1720 fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info);
1721 }
1722
1723 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1724
1725 if(!memcmp(&fb_display[con].var, &fb_display[ivideo->currcon].var,
1726 sizeof(struct fb_var_screeninfo))) {
1727 ivideo->currcon = con;
1728 return 1;
1729 }
1730
1731 ivideo->currcon = con;
1732
1733 sisfb_do_set_var(&fb_display[con].var, 1, info);
1734
1735 sisfb_set_disp(con, &fb_display[con].var, info);
1736
1737 sisfb_do_install_cmap(con, info);
1738
1739 cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
1740 rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
1741 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1742
1743 sisfb_update_var(con, info);
1744
1745 return 1;
1746}
1747
1748static void
1749sisfb_blank(int blank, struct fb_info *info)
1750{
1751 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1752
1753 sisfb_myblank(ivideo, blank);
1754}
1755#endif
1756
1757/* ------------ FBDev related routines for 2.6 series ----------- */
1758
1759#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1760
1761static int
1762sisfb_open(struct fb_info *info, int user)
1763{
1764 return 0;
1765}
1766
1767static int
1768sisfb_release(struct fb_info *info, int user)
1769{
1770 return 0;
1771}
1772
1773static int
1774sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1775 unsigned transp, struct fb_info *info)
1776{
1777 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1778
1779 if(regno >= sisfb_get_cmap_len(&info->var)) return 1;
1780
1781 switch(info->var.bits_per_pixel) {
1782 case 8:
1783 outSISREG(SISDACA, regno);
1784 outSISREG(SISDACD, (red >> 10));
1785 outSISREG(SISDACD, (green >> 10));
1786 outSISREG(SISDACD, (blue >> 10));
1787 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1788 outSISREG(SISDAC2A, regno);
1789 outSISREG(SISDAC2D, (red >> 8));
1790 outSISREG(SISDAC2D, (green >> 8));
1791 outSISREG(SISDAC2D, (blue >> 8));
1792 }
1793 break;
1794 case 16:
1795 ((u32 *)(info->pseudo_palette))[regno] =
1796 ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1797 break;
1798 case 32:
1799 red >>= 8;
1800 green >>= 8;
1801 blue >>= 8;
1802 ((u32 *)(info->pseudo_palette))[regno] =
1803 (red << 16) | (green << 8) | (blue);
1804 break;
1805 }
1806 return 0;
1807}
1808
1809static int
1810sisfb_set_par(struct fb_info *info)
1811{
1812 int err;
1813
1814 if((err = sisfb_do_set_var(&info->var, 1, info))) {
1815 return err;
1816 }
1817#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1818 sisfb_get_fix(&info->fix, info->currcon, info);
1819#else
1820 sisfb_get_fix(&info->fix, -1, info);
1821#endif
1822 return 0;
1823}
1824
1825static int
1826sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1827{
1828 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1829 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1830 unsigned int drate = 0, hrate = 0, maxyres;
1831 int found_mode = 0;
1832 int refresh_rate, search_idx;
1833 BOOLEAN recalc_clock = FALSE;
1834 u32 pixclock;
1835
1836 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1837
1838 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1839
1840 pixclock = var->pixclock;
1841
1842 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1843 vtotal += var->yres;
1844 vtotal <<= 1;
1845 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1846 vtotal += var->yres;
1847 vtotal <<= 2;
1848 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1849 vtotal += var->yres;
1850 vtotal <<= 1;
1851 } else vtotal += var->yres;
1852
1853 if(!(htotal) || !(vtotal)) {
1854 SISFAIL("sisfb: no valid timing data");
1855 }
1856
1857 search_idx = 0;
1858 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1859 (sisbios_mode[search_idx].xres <= var->xres) ) {
1860 if( (sisbios_mode[search_idx].xres == var->xres) &&
1861 (sisbios_mode[search_idx].yres == var->yres) &&
1862 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1863 if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) {
1864 found_mode = 1;
1865 break;
1866 }
1867 }
1868 search_idx++;
1869 }
1870
1871 if(!found_mode) {
1872 search_idx = 0;
1873 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1874 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1875 (var->yres <= sisbios_mode[search_idx].yres) &&
1876 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1877 if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) {
1878 found_mode = 1;
1879 break;
1880 }
1881 }
1882 search_idx++;
1883 }
1884 if(found_mode) {
1885 printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1886 var->xres, var->yres, var->bits_per_pixel,
1887 sisbios_mode[search_idx].xres,
1888 sisbios_mode[search_idx].yres,
1889 var->bits_per_pixel);
1890 var->xres = sisbios_mode[search_idx].xres;
1891 var->yres = sisbios_mode[search_idx].yres;
1892
1893
1894 } else {
1895 printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n",
1896 var->xres, var->yres, var->bits_per_pixel);
1897 return -EINVAL;
1898 }
1899 }
1900
1901 if( ((ivideo->vbflags & VB_LVDS) || /* Slave modes on LVDS and 301B-DH */
1902 ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1903 (var->bits_per_pixel == 8) ) {
1904 refresh_rate = 60;
1905 recalc_clock = TRUE;
1906 } else if( (ivideo->current_htotal == htotal) && /* x=x & y=y & c=c -> assume depth change */
1907 (ivideo->current_vtotal == vtotal) &&
1908 (ivideo->current_pixclock == pixclock) ) {
1909 drate = 1000000000 / pixclock;
1910 hrate = (drate * 1000) / htotal;
1911 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1912 } else if( ( (ivideo->current_htotal != htotal) || /* x!=x | y!=y & c=c -> invalid pixclock */
1913 (ivideo->current_vtotal != vtotal) ) &&
1914 (ivideo->current_pixclock == var->pixclock) ) {
1915 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1916 refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1917 } else if(ivideo->sisfb_parm_rate != -1) {
1918 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1919 refresh_rate = ivideo->sisfb_parm_rate;
1920 } else {
1921 refresh_rate = 60;
1922 }
1923 recalc_clock = TRUE;
1924 } else if((pixclock) && (htotal) && (vtotal)) {
1925 drate = 1000000000 / pixclock;
1926 hrate = (drate * 1000) / htotal;
1927 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1928 } else if(ivideo->current_refresh_rate) {
1929 refresh_rate = ivideo->current_refresh_rate;
1930 recalc_clock = TRUE;
1931 } else {
1932 refresh_rate = 60;
1933 recalc_clock = TRUE;
1934 }
1935
1936 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1937
1938 /* Eventually recalculate timing and clock */
1939 if(recalc_clock) {
1940 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1941 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1942 &ivideo->sishw_ext,
1943 sisbios_mode[search_idx].mode_no[ivideo->mni],
1944 myrateindex));
1945 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
1946 sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex, var);
1947 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1948 var->pixclock <<= 1;
1949 }
1950 }
1951
1952 if(ivideo->sisfb_thismonitor.datavalid) {
1953 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1954 myrateindex, refresh_rate)) {
1955 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1956 }
1957 }
1958
1959 /* Adapt RGB settings */
1960 sisfb_bpp_to_var(ivideo, var);
1961
1962 /* Sanity check for offsets */
1963 if(var->xoffset < 0) var->xoffset = 0;
1964 if(var->yoffset < 0) var->yoffset = 0;
1965
1966 if(var->xres > var->xres_virtual) {
1967 var->xres_virtual = var->xres;
1968 }
1969
1970 if(ivideo->sisfb_ypan) {
1971 maxyres = sisfb_calc_maxyres(ivideo, var);
1972 if(ivideo->sisfb_max) {
1973 var->yres_virtual = maxyres;
1974 } else {
1975 if(var->yres_virtual > maxyres) {
1976 var->yres_virtual = maxyres;
1977 }
1978 }
1979 if(var->yres_virtual <= var->yres) {
1980 var->yres_virtual = var->yres;
1981 }
1982 } else {
1983 if(var->yres != var->yres_virtual) {
1984 var->yres_virtual = var->yres;
1985 }
1986 var->xoffset = 0;
1987 var->yoffset = 0;
1988 }
1989
1990 /* Truncate offsets to maximum if too high */
1991 if(var->xoffset > var->xres_virtual - var->xres) {
1992 var->xoffset = var->xres_virtual - var->xres - 1;
1993 }
1994
1995 if(var->yoffset > var->yres_virtual - var->yres) {
1996 var->yoffset = var->yres_virtual - var->yres - 1;
1997 }
1998
1999 /* Set everything else to 0 */
2000 var->red.msb_right =
2001 var->green.msb_right =
2002 var->blue.msb_right =
2003 var->transp.offset =
2004 var->transp.length =
2005 var->transp.msb_right = 0;
2006
2007 return 0;
2008}
2009
2010static int
2011sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
2012{
2013 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2014 int err;
2015
2016 if(var->xoffset > (var->xres_virtual - var->xres)) {
2017 return -EINVAL;
2018 }
2019 if(var->yoffset > (var->yres_virtual - var->yres)) {
2020 return -EINVAL;
2021 }
2022
2023 if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
2024
2025 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
2026 var->yoffset + info->var.yres > info->var.yres_virtual) {
2027 return -EINVAL;
2028 }
2029
2030 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
2031
2032 info->var.xoffset = var->xoffset;
2033 info->var.yoffset = var->yoffset;
2034
2035 return 0;
2036}
2037
2038static int
2039sisfb_blank(int blank, struct fb_info *info)
2040{
2041 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2042
2043 return(sisfb_myblank(ivideo, blank));
2044}
2045
2046#endif
2047
2048/* ----------- FBDev related routines for all series ---------- */
2049
2050static int
2051sisfb_ioctl(struct inode *inode, struct file *file,
2052 unsigned int cmd, unsigned long arg,
2053#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2054 int con,
2055#endif
2056 struct fb_info *info)
2057{
2058 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2059 struct sis_memreq sismemreq;
2060 struct fb_vblank sisvbblank;
2061 sisfb_info x;
2062 u32 gpu32 = 0;
2063#ifndef __user
2064#define __user
2065#endif
2066 u32 __user *argp = (u32 __user *)arg;
2067
2068 switch (cmd) {
2069 case FBIO_ALLOC:
2070 if(!capable(CAP_SYS_RAWIO)) {
2071 return -EPERM;
2072 }
2073 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq))) {
2074 return -EFAULT;
2075 }
2076 sis_malloc(&sismemreq);
2077 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
2078 sis_free((u32)sismemreq.offset);
2079 return -EFAULT;
2080 }
2081 break;
2082
2083 case FBIO_FREE:
2084 if(!capable(CAP_SYS_RAWIO)) {
2085 return -EPERM;
2086 }
2087 if(get_user(gpu32, argp)) {
2088 return -EFAULT;
2089 }
2090 sis_free(gpu32);
2091 break;
2092
2093 case FBIOGET_VBLANK:
2094 sisvbblank.count = 0;
2095 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
2096 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank))) {
2097 return -EFAULT;
2098 }
2099 break;
2100
2101 case SISFB_GET_INFO_SIZE:
2102 return put_user(sizeof(sisfb_info), argp);
2103
2104 case SISFB_GET_INFO_OLD:
2105 if(ivideo->warncount++ < 50) {
2106 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2107 }
2108 case SISFB_GET_INFO: /* For communication with X driver */
2109 x.sisfb_id = SISFB_ID;
2110 x.sisfb_version = VER_MAJOR;
2111 x.sisfb_revision = VER_MINOR;
2112 x.sisfb_patchlevel = VER_LEVEL;
2113 x.chip_id = ivideo->chip_id;
2114 x.memory = ivideo->video_size / 1024;
2115 x.heapstart = ivideo->heapstart / 1024;
2116 if(ivideo->modechanged) {
2117 x.fbvidmode = ivideo->mode_no;
2118 } else {
2119 x.fbvidmode = ivideo->modeprechange;
2120 }
2121 x.sisfb_caps = ivideo->caps;
2122 x.sisfb_tqlen = 512; /* yet fixed */
2123 x.sisfb_pcibus = ivideo->pcibus;
2124 x.sisfb_pcislot = ivideo->pcislot;
2125 x.sisfb_pcifunc = ivideo->pcifunc;
2126 x.sisfb_lcdpdc = ivideo->detectedpdc;
2127 x.sisfb_lcdpdca = ivideo->detectedpdca;
2128 x.sisfb_lcda = ivideo->detectedlcda;
2129 x.sisfb_vbflags = ivideo->vbflags;
2130 x.sisfb_currentvbflags = ivideo->currentvbflags;
2131 x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
2132 x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
2133 x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
2134 x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
2135 x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
2136 x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
2137 x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
2138 x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
2139 x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
2140 x.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
2141
2142 if(copy_to_user((void __user *)arg, &x, sizeof(x))) {
2143 return -EFAULT;
2144 }
2145 break;
2146
2147 case SISFB_GET_VBRSTATUS_OLD:
2148 if(ivideo->warncount++ < 50) {
2149 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2150 }
2151 case SISFB_GET_VBRSTATUS:
2152 if(sisfb_CheckVBRetrace(ivideo)) {
2153 return put_user((u32)1, argp);
2154 } else {
2155 return put_user((u32)0, argp);
2156 }
2157
2158 case SISFB_GET_AUTOMAXIMIZE_OLD:
2159 if(ivideo->warncount++ < 50) {
2160 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2161 }
2162 case SISFB_GET_AUTOMAXIMIZE:
2163 if(ivideo->sisfb_max) return put_user((u32)1, argp);
2164 else return put_user((u32)0, argp);
2165
2166 case SISFB_SET_AUTOMAXIMIZE_OLD:
2167 if(ivideo->warncount++ < 50) {
2168 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2169 }
2170 case SISFB_SET_AUTOMAXIMIZE:
2171 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2172 return -EFAULT;
2173 }
2174 ivideo->sisfb_max = (gpu32) ? 1 : 0;
2175 break;
2176
2177 case SISFB_SET_TVPOSOFFSET:
2178 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2179 return -EFAULT;
2180 }
2181 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
2182 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
2183 break;
2184
2185 case SISFB_GET_TVPOSOFFSET:
2186 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
2187 argp);
2188
2189 case SISFB_SET_LOCK:
2190 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2191 return -EFAULT;
2192 }
2193 ivideo->sisfblocked = (gpu32) ? 1 : 0;
2194 break;
2195
2196 default:
2197 return -ENOIOCTLCMD;
2198 }
2199 return 0;
2200}
2201
2202#ifdef CONFIG_COMPAT
2203static long sisfb_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg, struct fb_info *info)
2204{
2205 int ret;
2206 lock_kernel();
2207 ret = sisfb_ioctl(NULL, f, cmd, arg, info);
2208 unlock_kernel();
2209 return ret;
2210}
2211#endif
2212
2213static int
2214sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
2215{
2216 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2217
2218 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2219
2220 strcpy(fix->id, ivideo->myid);
2221
2222 fix->smem_start = ivideo->video_base;
2223 fix->smem_len = ivideo->sisfb_mem;
2224 fix->type = FB_TYPE_PACKED_PIXELS;
2225 fix->type_aux = 0;
2226 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
2227 fix->xpanstep = 1;
2228 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
2229 fix->ywrapstep = 0;
2230 fix->line_length = ivideo->video_linelength;
2231 fix->mmio_start = ivideo->mmio_base;
2232 fix->mmio_len = ivideo->mmio_size;
2233 if(ivideo->sisvga_engine == SIS_300_VGA) {
2234 fix->accel = FB_ACCEL_SIS_GLAMOUR;
2235 } else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) {
2236 fix->accel = FB_ACCEL_SIS_XABRE;
2237 } else {
2238 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
2239 }
2240
2241 return 0;
2242}
2243
2244/* ---------------- fb_ops structures ----------------- */
2245
2246#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2247static struct fb_ops sisfb_ops = {
2248 .owner = THIS_MODULE,
2249 .fb_get_fix = sisfb_get_fix,
2250 .fb_get_var = sisfb_get_var,
2251 .fb_set_var = sisfb_set_var,
2252 .fb_get_cmap = sisfb_get_cmap,
2253 .fb_set_cmap = sisfb_set_cmap,
2254 .fb_pan_display = sisfb_pan_display,
2255 .fb_ioctl = sisfb_ioctl
2256};
2257#endif
2258
2259#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
2260static struct fb_ops sisfb_ops = {
2261 .owner = THIS_MODULE,
2262 .fb_open = sisfb_open,
2263 .fb_release = sisfb_release,
2264 .fb_check_var = sisfb_check_var,
2265 .fb_set_par = sisfb_set_par,
2266 .fb_setcolreg = sisfb_setcolreg,
2267 .fb_pan_display = sisfb_pan_display,
2268 .fb_blank = sisfb_blank,
2269 .fb_fillrect = fbcon_sis_fillrect,
2270 .fb_copyarea = fbcon_sis_copyarea,
2271 .fb_imageblit = cfb_imageblit,
2272 .fb_cursor = soft_cursor,
2273 .fb_sync = fbcon_sis_sync,
2274 .fb_ioctl = sisfb_ioctl,
2275#ifdef CONFIG_COMPAT
2276 .fb_compat_ioctl = sisfb_compat_ioctl,
2277#endif
2278};
2279#endif
2280
2281/* ---------------- Chip generation dependent routines ---------------- */
2282
2283static struct pci_dev * sisfb_get_northbridge(int basechipid)
2284{
2285 struct pci_dev *pdev = NULL;
2286 int nbridgenum, nbridgeidx, i;
2287 const unsigned short nbridgeids[] = {
2288 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2289 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2290 PCI_DEVICE_ID_SI_730,
2291 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2292 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2293 PCI_DEVICE_ID_SI_651,
2294 PCI_DEVICE_ID_SI_740,
2295 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760 VGA */
2296 PCI_DEVICE_ID_SI_741,
2297 PCI_DEVICE_ID_SI_660,
2298 PCI_DEVICE_ID_SI_760
2299 };
2300
2301 switch(basechipid) {
2302#ifdef CONFIG_FB_SIS_300
2303 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2304 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2305#endif
2306#ifdef CONFIG_FB_SIS_315
2307 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2308 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
2309 case SIS_660: nbridgeidx = 7; nbridgenum = 4; break;
2310#endif
2311 default: return NULL;
2312 }
2313 for(i = 0; i < nbridgenum; i++) {
2314 if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break;
2315 }
2316 return pdev;
2317}
2318
2319static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
2320{
2321#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2322 u8 reg;
2323#endif
2324
2325 ivideo->video_size = 0;
2326
2327 switch(ivideo->chip) {
2328#ifdef CONFIG_FB_SIS_300
2329 case SIS_300:
2330 inSISIDXREG(SISSR, 0x14, reg);
2331 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2332 break;
2333 case SIS_540:
2334 case SIS_630:
2335 case SIS_730:
2336 if(!ivideo->nbridge) return -1;
2337 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
2338 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2339 break;
2340#endif
2341#ifdef CONFIG_FB_SIS_315
2342 case SIS_315H:
2343 case SIS_315PRO:
2344 case SIS_315:
2345 inSISIDXREG(SISSR, 0x14, reg);
2346 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2347 switch((reg >> 2) & 0x03) {
2348 case 0x01:
2349 case 0x03:
2350 ivideo->video_size <<= 1;
2351 break;
2352 case 0x02:
2353 ivideo->video_size += (ivideo->video_size/2);
2354 }
2355 break;
2356 case SIS_330:
2357 inSISIDXREG(SISSR, 0x14, reg);
2358 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2359 if(reg & 0x0c) ivideo->video_size <<= 1;
2360 break;
2361 case SIS_550:
2362 case SIS_650:
2363 case SIS_740:
2364 inSISIDXREG(SISSR, 0x14, reg);
2365 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2366 break;
2367 case SIS_661:
2368 case SIS_741:
2369 inSISIDXREG(SISCR, 0x79, reg);
2370 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2371 break;
2372 case SIS_660:
2373 case SIS_760:
2374 inSISIDXREG(SISCR, 0x79, reg);
2375 reg = (reg & 0xf0) >> 4;
2376 if(reg) ivideo->video_size = (1 << reg) << 20;
2377 inSISIDXREG(SISCR, 0x78, reg);
2378 reg &= 0x30;
2379 if(reg) {
2380 if(reg == 0x10) ivideo->video_size += (32 << 20);
2381 else ivideo->video_size += (64 << 20);
2382 }
2383 break;
2384#endif
2385 default:
2386 return -1;
2387 }
2388 return 0;
2389}
2390
2391/* -------------- video bridge device detection --------------- */
2392
2393static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2394{
2395 u8 cr32, temp;
2396
2397#ifdef CONFIG_FB_SIS_300
2398 if(ivideo->sisvga_engine == SIS_300_VGA) {
2399 inSISIDXREG(SISSR, 0x17, temp);
2400 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2401 /* PAL/NTSC is stored on SR16 on such machines */
2402 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2403 inSISIDXREG(SISSR, 0x16, temp);
2404 if(temp & 0x20)
2405 ivideo->vbflags |= TV_PAL;
2406 else
2407 ivideo->vbflags |= TV_NTSC;
2408 }
2409 }
2410 }
2411#endif
2412
2413 inSISIDXREG(SISCR, 0x32, cr32);
2414
2415 if(cr32 & SIS_CRT1) {
2416 ivideo->sisfb_crt1off = 0;
2417 } else {
2418 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2419 }
2420
2421 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2422
2423 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2424 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2425 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2426
2427 /* Check given parms for hardware compatibility.
2428 * (Cannot do this in the search_xx routines since we don't
2429 * know what hardware we are running on then)
2430 */
2431
2432 if(ivideo->chip != SIS_550) {
2433 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2434 }
2435
2436 if(ivideo->sisfb_tvplug != -1) {
2437 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2438 (!(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) ) {
2439 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2440 ivideo->sisfb_tvplug = -1;
2441 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2442 }
2443 }
2444 }
2445 if(ivideo->sisfb_tvplug != -1) {
2446 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2447 (!(ivideo->vbflags & (VB_301|VB_301B|VB_302B))) ) {
2448 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2449 ivideo->sisfb_tvplug = -1;
2450 printk(KERN_ERR "sisfb: HiVision not supported\n");
2451 }
2452 }
2453 }
2454 if(ivideo->sisfb_tvstd != -1) {
2455 if( (!(ivideo->vbflags & VB_SISBRIDGE)) &&
2456 (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags & VB_CHRONTEL))) ) {
2457 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2458 ivideo->sisfb_tvstd = -1;
2459 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2460 }
2461 }
2462 }
2463
2464 /* Detect/set TV plug & type */
2465 if(ivideo->sisfb_tvplug != -1) {
2466 ivideo->vbflags |= ivideo->sisfb_tvplug;
2467 } else {
2468 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2469 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2470 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2471 else {
2472 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2473 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2474 }
2475 }
2476
2477 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2478 if(ivideo->sisfb_tvstd != -1) {
2479 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2480 ivideo->vbflags |= ivideo->sisfb_tvstd;
2481 }
2482 if(ivideo->vbflags & TV_SCART) {
2483 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2484 ivideo->vbflags |= TV_PAL;
2485 }
2486 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2487 if(ivideo->sisvga_engine == SIS_300_VGA) {
2488 inSISIDXREG(SISSR, 0x38, temp);
2489 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2490 else ivideo->vbflags |= TV_NTSC;
2491 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2492 inSISIDXREG(SISSR, 0x38, temp);
2493 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2494 else ivideo->vbflags |= TV_NTSC;
2495 } else {
2496 inSISIDXREG(SISCR, 0x79, temp);
2497 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2498 else ivideo->vbflags |= TV_NTSC;
2499 }
2500 }
2501 }
2502
2503 /* Copy forceCRT1 option to CRT1off if option is given */
2504 if(ivideo->sisfb_forcecrt1 != -1) {
2505 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2506 }
2507}
2508
2509static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo)
2510{
2511 char stdstr[] = "sisfb: Detected";
2512 char bridgestr[] = "video bridge";
2513 u8 vb_chipid;
2514 u8 reg;
2515
2516 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2517 switch(vb_chipid) {
2518 case 0x01:
2519 inSISIDXREG(SISPART4, 0x01, reg);
2520 if(reg < 0xb0) {
2521 ivideo->vbflags |= VB_301;
2522 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2523 } else if(reg < 0xc0) {
2524 ivideo->vbflags |= VB_301B;
2525 inSISIDXREG(SISPART4,0x23,reg);
2526 if(!(reg & 0x02)) {
2527 ivideo->vbflags |= VB_30xBDH;
2528 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2529 } else {
2530 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2531 }
2532 } else if(reg < 0xd0) {
2533 ivideo->vbflags |= VB_301C;
2534 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2535 } else if(reg < 0xe0) {
2536 ivideo->vbflags |= VB_301LV;
2537 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2538 } else if(reg <= 0xe1) {
2539 inSISIDXREG(SISPART4,0x39,reg);
2540 if(reg == 0xff) {
2541 ivideo->vbflags |= VB_302LV;
2542 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2543 } else {
2544 ivideo->vbflags |= VB_301C;
2545 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2546#if 0
2547 ivideo->vbflags |= VB_302ELV;
2548 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2549#endif
2550 }
2551 }
2552 break;
2553 case 0x02:
2554 ivideo->vbflags |= VB_302B;
2555 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2556 break;
2557 }
2558
2559 if((!(ivideo->vbflags & VB_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2560 inSISIDXREG(SISCR, 0x37, reg);
2561 reg &= SIS_EXTERNAL_CHIP_MASK;
2562 reg >>= 1;
2563 if(ivideo->sisvga_engine == SIS_300_VGA) {
2564#ifdef CONFIG_FB_SIS_300
2565 switch(reg) {
2566 case SIS_EXTERNAL_CHIP_LVDS:
2567 ivideo->vbflags |= VB_LVDS;
2568 break;
2569 case SIS_EXTERNAL_CHIP_TRUMPION:
2570 ivideo->vbflags |= VB_TRUMPION;
2571 break;
2572 case SIS_EXTERNAL_CHIP_CHRONTEL:
2573 ivideo->vbflags |= VB_CHRONTEL;
2574 break;
2575 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2576 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2577 break;
2578 }
2579 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 1;
2580#endif
2581 } else if(ivideo->chip < SIS_661) {
2582#ifdef CONFIG_FB_SIS_315
2583 switch (reg) {
2584 case SIS310_EXTERNAL_CHIP_LVDS:
2585 ivideo->vbflags |= VB_LVDS;
2586 break;
2587 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2588 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2589 break;
2590 }
2591 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2592#endif
2593 } else if(ivideo->chip >= SIS_661) {
2594#ifdef CONFIG_FB_SIS_315
2595 inSISIDXREG(SISCR, 0x38, reg);
2596 reg >>= 5;
2597 switch(reg) {
2598 case 0x02:
2599 ivideo->vbflags |= VB_LVDS;
2600 break;
2601 case 0x03:
2602 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2603 break;
2604 case 0x04:
2605 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);
2606 break;
2607 }
2608 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2609#endif
2610 }
2611 if(ivideo->vbflags & VB_LVDS) {
2612 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2613 }
2614 if(ivideo->vbflags & VB_TRUMPION) {
2615 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2616 }
2617 if(ivideo->vbflags & VB_CHRONTEL) {
2618 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2619 }
2620 if(ivideo->vbflags & VB_CONEXANT) {
2621 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2622 }
2623 }
2624
2625 if(ivideo->vbflags & VB_SISBRIDGE) {
2626 SiS_Sense30x(ivideo);
2627 } else if(ivideo->vbflags & VB_CHRONTEL) {
2628 SiS_SenseCh(ivideo);
2629 }
2630}
2631
2632/* ------------------ Sensing routines ------------------ */
2633
2634static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo)
2635{
2636 unsigned short old;
2637 int count = 48;
2638
2639 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2640 do {
2641 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2642 } while(count--);
2643 return (count == -1) ? FALSE : TRUE;
2644}
2645
2646static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
2647{
2648 BOOLEAN mustwait = FALSE;
2649 u8 sr1F, cr17;
2650#ifdef CONFIG_FB_SIS_315
2651 u8 cr63=0;
2652#endif
2653 u16 temp = 0xffff;
2654 int i;
2655
2656 inSISIDXREG(SISSR,0x1F,sr1F);
2657 orSISIDXREG(SISSR,0x1F,0x04);
2658 andSISIDXREG(SISSR,0x1F,0x3F);
2659 if(sr1F & 0xc0) mustwait = TRUE;
2660
2661#ifdef CONFIG_FB_SIS_315
2662 if(ivideo->sisvga_engine == SIS_315_VGA) {
2663 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2664 cr63 &= 0x40;
2665 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2666 }
2667#endif
2668
2669 inSISIDXREG(SISCR,0x17,cr17);
2670 cr17 &= 0x80;
2671 if(!cr17) {
2672 orSISIDXREG(SISCR,0x17,0x80);
2673 mustwait = TRUE;
2674 outSISIDXREG(SISSR, 0x00, 0x01);
2675 outSISIDXREG(SISSR, 0x00, 0x03);
2676 }
2677
2678 if(mustwait) {
2679 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2680 }
2681
2682#ifdef CONFIG_FB_SIS_315
2683 if(ivideo->chip >= SIS_330) {
2684 andSISIDXREG(SISCR,0x32,~0x20);
2685 if(ivideo->chip >= SIS_340) {
2686 outSISIDXREG(SISCR, 0x57, 0x4a);
2687 } else {
2688 outSISIDXREG(SISCR, 0x57, 0x5f);
2689 }
2690 orSISIDXREG(SISCR, 0x53, 0x02);
2691 while((inSISREG(SISINPSTAT)) & 0x01) break;
2692 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2693 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2694 andSISIDXREG(SISCR, 0x53, 0xfd);
2695 andSISIDXREG(SISCR, 0x57, 0x00);
2696 }
2697#endif
2698
2699 if(temp == 0xffff) {
2700 i = 3;
2701 do {
2702 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, 0, 0, NULL);
2703 } while(((temp == 0) || (temp == 0xffff)) && i--);
2704
2705 if((temp == 0) || (temp == 0xffff)) {
2706 if(sisfb_test_DDC1(ivideo)) temp = 1;
2707 }
2708 }
2709
2710 if((temp) && (temp != 0xffff)) {
2711 orSISIDXREG(SISCR,0x32,0x20);
2712 }
2713
2714#ifdef CONFIG_FB_SIS_315
2715 if(ivideo->sisvga_engine == SIS_315_VGA) {
2716 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2717 }
2718#endif
2719
2720 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2721
2722 outSISIDXREG(SISSR,0x1F,sr1F);
2723}
2724
2725/* Determine and detect attached devices on SiS30x */
2726static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2727{
2728 int temp, mytest, result, i, j;
2729
2730 for(j = 0; j < 10; j++) {
2731 result = 0;
2732 for(i = 0; i < 3; i++) {
2733 mytest = test;
2734 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2735 temp = (type >> 8) | (mytest & 0x00ff);
2736 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2737 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2738 mytest >>= 8;
2739 mytest &= 0x7f;
2740 inSISIDXREG(SISPART4,0x03,temp);
2741 temp ^= 0x0e;
2742 temp &= mytest;
2743 if(temp == mytest) result++;
2744#if 1
2745 outSISIDXREG(SISPART4,0x11,0x00);
2746 andSISIDXREG(SISPART4,0x10,0xe0);
2747 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2748#endif
2749 }
2750 if((result == 0) || (result >= 2)) break;
2751 }
2752 return(result);
2753}
2754
2755static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
2756{
2757 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2758 u16 svhs=0, svhs_c=0;
2759 u16 cvbs=0, cvbs_c=0;
2760 u16 vga2=0, vga2_c=0;
2761 int myflag, result;
2762 char stdstr[] = "sisfb: Detected";
2763 char tvstr[] = "TV connected to";
2764
2765 if(ivideo->vbflags & VB_301) {
2766 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2767 inSISIDXREG(SISPART4,0x01,myflag);
2768 if(myflag & 0x04) {
2769 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2770 }
2771 } else if(ivideo->vbflags & (VB_301B | VB_302B)) {
2772 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2773 } else if(ivideo->vbflags & (VB_301LV | VB_302LV)) {
2774 svhs = 0x0200; cvbs = 0x0100;
2775 } else if(ivideo->vbflags & (VB_301C | VB_302ELV)) {
2776 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2777 } else return;
2778
2779 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2780 if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
2781 svhs_c = 0x0408; cvbs_c = 0x0808;
2782 }
2783 biosflag = 2;
2784
2785 if(ivideo->chip == SIS_300) {
2786 inSISIDXREG(SISSR,0x3b,myflag);
2787 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2788 }
2789
2790 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2791 orSISIDXREG(SISSR,0x1e,0x20);
2792
2793 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2794 if(ivideo->vbflags & VB_301C) {
2795 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2796 } else {
2797 orSISIDXREG(SISPART4,0x0d,0x04);
2798 }
2799 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2800
2801 inSISIDXREG(SISPART2,0x00,backupP2_00);
2802 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2803
2804 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2805 if(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV)) {
2806 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2807 }
2808
2809 if(!(ivideo->vbflags & VB_301C)) {
2810 SISDoSense(ivideo, 0, 0);
2811 }
2812
2813 andSISIDXREG(SISCR, 0x32, ~0x14);
2814
2815 if(vga2_c || vga2) {
2816 if(SISDoSense(ivideo, vga2, vga2_c)) {
2817 if(biosflag & 0x01) {
2818 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2819 orSISIDXREG(SISCR, 0x32, 0x04);
2820 } else {
2821 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2822 orSISIDXREG(SISCR, 0x32, 0x10);
2823 }
2824 }
2825 }
2826
2827 andSISIDXREG(SISCR, 0x32, 0x3f);
2828
2829 if(ivideo->vbflags & VB_301C) {
2830 orSISIDXREG(SISPART4,0x0d,0x04);
2831 }
2832
2833 if((ivideo->sisvga_engine == SIS_315_VGA) &&
2834 (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV))) {
2835 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2836 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2837 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2838 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2839 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2840 orSISIDXREG(SISCR,0x32,0x80);
2841 }
2842 }
2843 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2844 }
2845
2846 andSISIDXREG(SISCR, 0x32, ~0x03);
2847
2848 if(!(ivideo->vbflags & TV_YPBPR)) {
2849 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2850 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2851 orSISIDXREG(SISCR, 0x32, 0x02);
2852 }
2853 if((biosflag & 0x02) || (!result)) {
2854 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2855 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2856 orSISIDXREG(SISCR, 0x32, 0x01);
2857 }
2858 }
2859 }
2860
2861 SISDoSense(ivideo, 0, 0);
2862
2863 outSISIDXREG(SISPART2,0x00,backupP2_00);
2864 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2865 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2866
2867 if(ivideo->vbflags & VB_301C) {
2868 inSISIDXREG(SISPART2,0x00,biosflag);
2869 if(biosflag & 0x20) {
2870 for(myflag = 2; myflag > 0; myflag--) {
2871 biosflag ^= 0x20;
2872 outSISIDXREG(SISPART2,0x00,biosflag);
2873 }
2874 }
2875 }
2876
2877 outSISIDXREG(SISPART2,0x00,backupP2_00);
2878}
2879
2880/* Determine and detect attached TV's on Chrontel */
2881static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
2882{
2883#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2884 u8 temp1, temp2;
2885 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2886#endif
2887#ifdef CONFIG_FB_SIS_300
2888 unsigned char test[3];
2889 int i;
2890#endif
2891
2892 if(ivideo->chip < SIS_315H) {
2893
2894#ifdef CONFIG_FB_SIS_300
2895 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2896 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2897 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2898 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2899 /* See Chrontel TB31 for explanation */
2900 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2901 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2902 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b0e);
2903 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2904 }
2905 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2906 if(temp2 != temp1) temp1 = temp2;
2907
2908 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2909 /* Read power status */
2910 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2911 if((temp1 & 0x03) != 0x03) {
2912 /* Power all outputs */
2913 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0B0E);
2914 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2915 }
2916 /* Sense connected TV devices */
2917 for(i = 0; i < 3; i++) {
2918 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0110);
2919 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2920 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0010);
2921 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2922 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2923 if(!(temp1 & 0x08)) test[i] = 0x02;
2924 else if(!(temp1 & 0x02)) test[i] = 0x01;
2925 else test[i] = 0;
2926 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2927 }
2928
2929 if(test[0] == test[1]) temp1 = test[0];
2930 else if(test[0] == test[2]) temp1 = test[0];
2931 else if(test[1] == test[2]) temp1 = test[1];
2932 else {
2933 printk(KERN_INFO
2934 "sisfb: TV detection unreliable - test results varied\n");
2935 temp1 = test[2];
2936 }
2937 if(temp1 == 0x02) {
2938 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2939 ivideo->vbflags |= TV_SVIDEO;
2940 orSISIDXREG(SISCR, 0x32, 0x02);
2941 andSISIDXREG(SISCR, 0x32, ~0x05);
2942 } else if (temp1 == 0x01) {
2943 printk(KERN_INFO "%s CVBS output\n", stdstr);
2944 ivideo->vbflags |= TV_AVIDEO;
2945 orSISIDXREG(SISCR, 0x32, 0x01);
2946 andSISIDXREG(SISCR, 0x32, ~0x06);
2947 } else {
2948 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2949 andSISIDXREG(SISCR, 0x32, ~0x07);
2950 }
2951 } else if(temp1 == 0) {
2952 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2953 andSISIDXREG(SISCR, 0x32, ~0x07);
2954 }
2955 /* Set general purpose IO for Chrontel communication */
2956 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2957#endif
2958
2959 } else {
2960
2961#ifdef CONFIG_FB_SIS_315
2962 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2963 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2964 SiS_SetCH701x(&ivideo->SiS_Pr, 0x2049);
2965 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2966 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2967 temp2 |= 0x01;
2968 SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2969 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2970 temp2 ^= 0x01;
2971 SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2972 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2973 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2974 SiS_SetCH701x(&ivideo->SiS_Pr, (temp1 << 8) | 0x49);
2975 temp1 = 0;
2976 if(temp2 & 0x02) temp1 |= 0x01;
2977 if(temp2 & 0x10) temp1 |= 0x01;
2978 if(temp2 & 0x04) temp1 |= 0x02;
2979 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2980 switch(temp1) {
2981 case 0x01:
2982 printk(KERN_INFO "%s CVBS output\n", stdstr);
2983 ivideo->vbflags |= TV_AVIDEO;
2984 orSISIDXREG(SISCR, 0x32, 0x01);
2985 andSISIDXREG(SISCR, 0x32, ~0x06);
2986 break;
2987 case 0x02:
2988 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2989 ivideo->vbflags |= TV_SVIDEO;
2990 orSISIDXREG(SISCR, 0x32, 0x02);
2991 andSISIDXREG(SISCR, 0x32, ~0x05);
2992 break;
2993 case 0x04:
2994 printk(KERN_INFO "%s SCART output\n", stdstr);
2995 orSISIDXREG(SISCR, 0x32, 0x04);
2996 andSISIDXREG(SISCR, 0x32, ~0x03);
2997 break;
2998 default:
2999 andSISIDXREG(SISCR, 0x32, ~0x07);
3000 }
3001#endif
3002 }
3003}
3004
3005/* ------------------------ Heap routines -------------------------- */
3006
3007static u32 __devinit
3008sisfb_getheapstart(struct sis_video_info *ivideo)
3009{
3010 u32 ret = ivideo->sisfb_parm_mem * 1024;
3011 u32 max = ivideo->video_size - ivideo->hwcursor_size;
3012 u32 def;
3013
3014 /* Calculate heap start = end of memory for console
3015 *
3016 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3017 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3018 *
3019 * Basically given by "mem" parameter
3020 *
3021 * maximum = videosize - cmd_queue - hwcursor
3022 * (results in a heap of size 0)
3023 * default = SiS 300: depends on videosize
3024 * SiS 315/330: 32k below max
3025 */
3026
3027 if(ivideo->sisvga_engine == SIS_300_VGA) {
3028 max -= TURBO_QUEUE_AREA_SIZE;
3029 if(ivideo->video_size > 0x1000000) {
3030 def = 0xc00000;
3031 } else if(ivideo->video_size > 0x800000) {
3032 def = 0x800000;
3033 } else {
3034 def = 0x400000;
3035 }
3036 } else {
3037 max -= COMMAND_QUEUE_AREA_SIZE;
3038 def = max - 0x8000;
3039 }
3040
3041 if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) {
3042 ret = def;
3043 }
3044
3045 return ret;
3046}
3047
3048static int __devinit
3049sisfb_heap_init(struct sis_video_info *ivideo)
3050{
3051 SIS_OH *poh;
3052
3053 ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo);
3054
3055 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3056 ivideo->sisfb_heap_end = ivideo->video_vbase + ivideo->video_size;
3057
3058 /* Initialize command queue (We use MMIO only) */
3059
3060#ifdef CONFIG_FB_SIS_315
3061 if(ivideo->sisvga_engine == SIS_315_VGA) {
3062 u32 tempq = 0;
3063 u8 temp = 0;
3064
3065 ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
3066
3067 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
3068 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3069
3070 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3071 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3072
3073 temp = SIS_CMD_QUEUE_SIZE_512k;
3074 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3075 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3076
3077 tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE);
3078 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3079
3080 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3081 }
3082#endif
3083
3084#ifdef CONFIG_FB_SIS_300
3085 if(ivideo->sisvga_engine == SIS_300_VGA) {
3086 unsigned long tqueue_pos;
3087 u8 tq_state;
3088
3089 ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
3090
3091 tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
3092
3093 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3094 tq_state |= 0xf0;
3095 tq_state &= 0xfc;
3096 tq_state |= (u8)(tqueue_pos >> 8);
3097 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3098
3099 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
3100
3101 ivideo->caps |= TURBO_QUEUE_CAP;
3102 }
3103#endif
3104
3105 /* Reserve memory for the HWCursor */
3106 ivideo->sisfb_heap_end -= ivideo->hwcursor_size;
3107 ivideo->hwcursor_vbase = ivideo->sisfb_heap_end;
3108 ivideo->caps |= HW_CURSOR_CAP;
3109
3110 ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start;
3111
3112 if(ivideo->cardnumber == 0) {
3113
3114 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3115 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3116
3117 sisfb_heap.vinfo = ivideo;
3118
3119 sisfb_heap.poha_chain = NULL;
3120 sisfb_heap.poh_freelist = NULL;
3121
3122 poh = sisfb_poh_new_node();
3123 if(poh == NULL) return 1;
3124
3125 poh->poh_next = &sisfb_heap.oh_free;
3126 poh->poh_prev = &sisfb_heap.oh_free;
3127 poh->size = ivideo->sisfb_heap_size;
3128 poh->offset = ivideo->heapstart;
3129
3130 sisfb_heap.oh_free.poh_next = poh;
3131 sisfb_heap.oh_free.poh_prev = poh;
3132 sisfb_heap.oh_free.size = 0;
3133 sisfb_heap.max_freesize = poh->size;
3134
3135 sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
3136 sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
3137 sisfb_heap.oh_used.size = SENTINEL;
3138
3139 } else {
3140
3141 printk(KERN_INFO "Skipped heap initialization for secondary cards\n");
3142
3143 }
3144
3145 return 0;
3146}
3147
3148static SIS_OH *
3149sisfb_poh_new_node(void)
3150{
3151 int i;
3152 unsigned long cOhs;
3153 SIS_OHALLOC *poha;
3154 SIS_OH *poh;
3155
3156 if(sisfb_heap.poh_freelist == NULL) {
3157 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3158 if(!poha) return NULL;
3159
3160 poha->poha_next = sisfb_heap.poha_chain;
3161 sisfb_heap.poha_chain = poha;
3162
3163 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
3164
3165 poh = &poha->aoh[0];
3166 for(i = cOhs - 1; i != 0; i--) {
3167 poh->poh_next = poh + 1;
3168 poh = poh + 1;
3169 }
3170
3171 poh->poh_next = NULL;
3172 sisfb_heap.poh_freelist = &poha->aoh[0];
3173 }
3174
3175 poh = sisfb_heap.poh_freelist;
3176 sisfb_heap.poh_freelist = poh->poh_next;
3177
3178 return (poh);
3179}
3180
3181static SIS_OH *
3182sisfb_poh_allocate(u32 size)
3183{
3184 SIS_OH *pohThis;
3185 SIS_OH *pohRoot;
3186 int bAllocated = 0;
3187
3188 if(size > sisfb_heap.max_freesize) {
3189 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3190 (unsigned int) size / 1024);
3191 return (NULL);
3192 }
3193
3194 pohThis = sisfb_heap.oh_free.poh_next;
3195
3196 while(pohThis != &sisfb_heap.oh_free) {
3197 if (size <= pohThis->size) {
3198 bAllocated = 1;
3199 break;
3200 }
3201 pohThis = pohThis->poh_next;
3202 }
3203
3204 if(!bAllocated) {
3205 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3206 (unsigned int) size / 1024);
3207 return (NULL);
3208 }
3209
3210 if(size == pohThis->size) {
3211 pohRoot = pohThis;
3212 sisfb_delete_node(pohThis);
3213 } else {
3214 pohRoot = sisfb_poh_new_node();
3215
3216 if(pohRoot == NULL) {
3217 return (NULL);
3218 }
3219
3220 pohRoot->offset = pohThis->offset;
3221 pohRoot->size = size;
3222
3223 pohThis->offset += size;
3224 pohThis->size -= size;
3225 }
3226
3227 sisfb_heap.max_freesize -= size;
3228
3229 pohThis = &sisfb_heap.oh_used;
3230 sisfb_insert_node(pohThis, pohRoot);
3231
3232 return (pohRoot);
3233}
3234
3235static void
3236sisfb_delete_node(SIS_OH *poh)
3237{
3238 SIS_OH *poh_prev;
3239 SIS_OH *poh_next;
3240
3241 poh_prev = poh->poh_prev;
3242 poh_next = poh->poh_next;
3243
3244 poh_prev->poh_next = poh_next;
3245 poh_next->poh_prev = poh_prev;
3246}
3247
3248static void
3249sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
3250{
3251 SIS_OH *pohTemp;
3252
3253 pohTemp = pohList->poh_next;
3254
3255 pohList->poh_next = poh;
3256 pohTemp->poh_prev = poh;
3257
3258 poh->poh_prev = pohList;
3259 poh->poh_next = pohTemp;
3260}
3261
3262static SIS_OH *
3263sisfb_poh_free(u32 base)
3264{
3265 SIS_OH *pohThis;
3266 SIS_OH *poh_freed;
3267 SIS_OH *poh_prev;
3268 SIS_OH *poh_next;
3269 u32 ulUpper;
3270 u32 ulLower;
3271 int foundNode = 0;
3272
3273 poh_freed = sisfb_heap.oh_used.poh_next;
3274
3275 while(poh_freed != &sisfb_heap.oh_used) {
3276 if(poh_freed->offset == base) {
3277 foundNode = 1;
3278 break;
3279 }
3280
3281 poh_freed = poh_freed->poh_next;
3282 }
3283
3284 if(!foundNode) return(NULL);
3285
3286 sisfb_heap.max_freesize += poh_freed->size;
3287
3288 poh_prev = poh_next = NULL;
3289 ulUpper = poh_freed->offset + poh_freed->size;
3290 ulLower = poh_freed->offset;
3291
3292 pohThis = sisfb_heap.oh_free.poh_next;
3293
3294 while(pohThis != &sisfb_heap.oh_free) {
3295 if(pohThis->offset == ulUpper) {
3296 poh_next = pohThis;
3297 } else if((pohThis->offset + pohThis->size) == ulLower) {
3298 poh_prev = pohThis;
3299 }
3300 pohThis = pohThis->poh_next;
3301 }
3302
3303 sisfb_delete_node(poh_freed);
3304
3305 if(poh_prev && poh_next) {
3306 poh_prev->size += (poh_freed->size + poh_next->size);
3307 sisfb_delete_node(poh_next);
3308 sisfb_free_node(poh_freed);
3309 sisfb_free_node(poh_next);
3310 return(poh_prev);
3311 }
3312
3313 if(poh_prev) {
3314 poh_prev->size += poh_freed->size;
3315 sisfb_free_node(poh_freed);
3316 return(poh_prev);
3317 }
3318
3319 if(poh_next) {
3320 poh_next->size += poh_freed->size;
3321 poh_next->offset = poh_freed->offset;
3322 sisfb_free_node(poh_freed);
3323 return(poh_next);
3324 }
3325
3326 sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
3327
3328 return(poh_freed);
3329}
3330
3331static void
3332sisfb_free_node(SIS_OH *poh)
3333{
3334 if(poh == NULL) return;
3335
3336 poh->poh_next = sisfb_heap.poh_freelist;
3337 sisfb_heap.poh_freelist = poh;
3338}
3339
3340void
3341sis_malloc(struct sis_memreq *req)
3342{
3343 struct sis_video_info *ivideo = sisfb_heap.vinfo;
3344 SIS_OH *poh = NULL;
3345
3346 if((ivideo) && (!ivideo->havenoheap)) {
3347 poh = sisfb_poh_allocate((u32)req->size);
3348 }
3349
3350 if(poh == NULL) {
3351 req->offset = req->size = 0;
3352 DPRINTK("sisfb: Video RAM allocation failed\n");
3353 } else {
3354 req->offset = poh->offset;
3355 req->size = poh->size;
3356 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3357 (poh->offset + ivideo->video_vbase));
3358 }
3359}
3360
3361/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3362
3363void
3364sis_free(u32 base)
3365{
3366 struct sis_video_info *ivideo = sisfb_heap.vinfo;
3367 SIS_OH *poh;
3368
3369 if((!ivideo) || (ivideo->havenoheap)) return;
3370
3371 poh = sisfb_poh_free((u32)base);
3372
3373 if(poh == NULL) {
3374 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3375 (unsigned int) base);
3376 }
3377}
3378
3379/* --------------------- SetMode routines ------------------------- */
3380
3381static void
3382sisfb_pre_setmode(struct sis_video_info *ivideo)
3383{
3384 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3385 int tvregnum = 0;
3386
3387 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3388
3389 inSISIDXREG(SISCR, 0x31, cr31);
3390 cr31 &= ~0x60;
3391 cr31 |= 0x04;
3392
3393 cr33 = ivideo->rate_idx & 0x0F;
3394
3395#ifdef CONFIG_FB_SIS_315
3396 if(ivideo->sisvga_engine == SIS_315_VGA) {
3397 if(ivideo->chip >= SIS_661) {
3398 inSISIDXREG(SISCR, 0x38, cr38);
3399 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3400 } else {
3401 tvregnum = 0x38;
3402 inSISIDXREG(SISCR, tvregnum, cr38);
3403 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3404 }
3405 }
3406#endif
3407#ifdef CONFIG_FB_SIS_300
3408 if(ivideo->sisvga_engine == SIS_300_VGA) {
3409 tvregnum = 0x35;
3410 inSISIDXREG(SISCR, tvregnum, cr38);
3411 }
3412#endif
3413
3414 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3415 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3416
3417 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3418
3419 case CRT2_TV:
3420 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3421 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) {
3422#ifdef CONFIG_FB_SIS_315
3423 if(ivideo->chip >= SIS_661) {
3424 cr38 |= 0x04;
3425 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3426 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3427 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3428 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3429 cr35 &= ~0x01;
3430 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3431 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3432 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3433 cr38 |= 0x08;
3434 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3435 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3436 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3437 cr31 &= ~0x01;
3438 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3439 }
3440#endif
3441 } else if((ivideo->vbflags & TV_HIVISION) && (ivideo->vbflags & (VB_301|VB_301B|VB_302B))) {
3442 if(ivideo->chip >= SIS_661) {
3443 cr38 |= 0x04;
3444 cr35 |= 0x60;
3445 } else {
3446 cr30 |= 0x80;
3447 }
3448 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3449 cr31 |= 0x01;
3450 cr35 |= 0x01;
3451 ivideo->currentvbflags |= TV_HIVISION;
3452 } else if(ivideo->vbflags & TV_SCART) {
3453 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3454 cr31 |= 0x01;
3455 cr35 |= 0x01;
3456 ivideo->currentvbflags |= TV_SCART;
3457 } else {
3458 if(ivideo->vbflags & TV_SVIDEO) {
3459 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3460 ivideo->currentvbflags |= TV_SVIDEO;
3461 }
3462 if(ivideo->vbflags & TV_AVIDEO) {
3463 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3464 ivideo->currentvbflags |= TV_AVIDEO;
3465 }
3466 }
3467 cr31 |= SIS_DRIVER_MODE;
3468
3469 if(ivideo->vbflags & (TV_AVIDEO|TV_SVIDEO)) {
3470 if(ivideo->vbflags & TV_PAL) {
3471 cr31 |= 0x01; cr35 |= 0x01;
3472 ivideo->currentvbflags |= TV_PAL;
3473 if(ivideo->vbflags & TV_PALM) {
3474 cr38 |= 0x40; cr35 |= 0x04;
3475 ivideo->currentvbflags |= TV_PALM;
3476 } else if(ivideo->vbflags & TV_PALN) {
3477 cr38 |= 0x80; cr35 |= 0x08;
3478 ivideo->currentvbflags |= TV_PALN;
3479 }
3480 } else {
3481 cr31 &= ~0x01; cr35 &= ~0x01;
3482 ivideo->currentvbflags |= TV_NTSC;
3483 if(ivideo->vbflags & TV_NTSCJ) {
3484 cr38 |= 0x40; cr35 |= 0x02;
3485 ivideo->currentvbflags |= TV_NTSCJ;
3486 }
3487 }
3488 }
3489 break;
3490
3491 case CRT2_LCD:
3492 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3493 cr31 |= SIS_DRIVER_MODE;
3494 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3495 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3496 break;
3497
3498 case CRT2_VGA:
3499 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3500 cr31 |= SIS_DRIVER_MODE;
3501 if(ivideo->sisfb_nocrt2rate) {
3502 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3503 } else {
3504 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3505 }
3506 break;
3507
3508 default: /* disable CRT2 */
3509 cr30 = 0x00;
3510 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3511 }
3512
3513 outSISIDXREG(SISCR, 0x30, cr30);
3514 outSISIDXREG(SISCR, 0x33, cr33);
3515
3516 if(ivideo->chip >= SIS_661) {
3517#ifdef CONFIG_FB_SIS_315
3518 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3519 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3520 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3521 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3522#endif
3523 } else if(ivideo->chip != SIS_300) {
3524 outSISIDXREG(SISCR, tvregnum, cr38);
3525 }
3526 outSISIDXREG(SISCR, 0x31, cr31);
3527
3528 if(ivideo->accel) sisfb_syncaccel(ivideo);
3529
3530 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3531}
3532
3533/* Fix SR11 for 661 and later */
3534#ifdef CONFIG_FB_SIS_315
3535static void
3536sisfb_fixup_SR11(struct sis_video_info *ivideo)
3537{
3538 u8 tmpreg;
3539
3540 if(ivideo->chip >= SIS_661) {
3541 inSISIDXREG(SISSR,0x11,tmpreg);
3542 if(tmpreg & 0x20) {
3543 inSISIDXREG(SISSR,0x3e,tmpreg);
3544 tmpreg = (tmpreg + 1) & 0xff;
3545 outSISIDXREG(SISSR,0x3e,tmpreg);
3546 inSISIDXREG(SISSR,0x11,tmpreg);
3547 }
3548 if(tmpreg & 0xf0) {
3549 andSISIDXREG(SISSR,0x11,0x0f);
3550 }
3551 }
3552}
3553#endif
3554
3555static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3556{
3557 if(val > 32) val = 32;
3558 if(val < -32) val = -32;
3559 ivideo->tvxpos = val;
3560
3561 if(ivideo->sisfblocked) return;
3562 if(!ivideo->modechanged) return;
3563
3564 if(ivideo->currentvbflags & CRT2_TV) {
3565
3566 if(ivideo->vbflags & VB_CHRONTEL) {
3567
3568 int x = ivideo->tvx;
3569
3570 switch(ivideo->chronteltype) {
3571 case 1:
3572 x += val;
3573 if(x < 0) x = 0;
3574 outSISIDXREG(SISSR,0x05,0x86);
3575 SiS_SetCH700x(&ivideo->SiS_Pr, (((x & 0xff) << 8) | 0x0a));
3576 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD);
3577 break;
3578 case 2:
3579 /* Not supported by hardware */
3580 break;
3581 }
3582
3583 } else if(ivideo->vbflags & VB_SISBRIDGE) {
3584
3585 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3586 unsigned short temp;
3587
3588 p2_1f = ivideo->p2_1f;
3589 p2_20 = ivideo->p2_20;
3590 p2_2b = ivideo->p2_2b;
3591 p2_42 = ivideo->p2_42;
3592 p2_43 = ivideo->p2_43;
3593
3594 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3595 temp += (val * 2);
3596 p2_1f = temp & 0xff;
3597 p2_20 = (temp & 0xf00) >> 4;
3598 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3599 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3600 temp += (val * 2);
3601 p2_43 = temp & 0xff;
3602 p2_42 = (temp & 0xf00) >> 4;
3603 outSISIDXREG(SISPART2,0x1f,p2_1f);
3604 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3605 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3606 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3607 outSISIDXREG(SISPART2,0x43,p2_43);
3608 }
3609 }
3610}
3611
3612static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3613{
3614 if(val > 32) val = 32;
3615 if(val < -32) val = -32;
3616 ivideo->tvypos = val;
3617
3618 if(ivideo->sisfblocked) return;
3619 if(!ivideo->modechanged) return;
3620
3621 if(ivideo->currentvbflags & CRT2_TV) {
3622
3623 if(ivideo->vbflags & VB_CHRONTEL) {
3624
3625 int y = ivideo->tvy;
3626
3627 switch(ivideo->chronteltype) {
3628 case 1:
3629 y -= val;
3630 if(y < 0) y = 0;
3631 outSISIDXREG(SISSR,0x05,0x86);
3632 SiS_SetCH700x(&ivideo->SiS_Pr, (((y & 0xff) << 8) | 0x0b));
3633 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, ((y & 0x0100) | 0x08),0xFE);
3634 break;
3635 case 2:
3636 /* Not supported by hardware */
3637 break;
3638 }
3639
3640 } else if(ivideo->vbflags & VB_SISBRIDGE) {
3641
3642 char p2_01, p2_02;
3643 val /= 2;
3644 p2_01 = ivideo->p2_01;
3645 p2_02 = ivideo->p2_02;
3646
3647 p2_01 += val;
3648 p2_02 += val;
3649 while((p2_01 <= 0) || (p2_02 <= 0)) {
3650 p2_01 += 2;
3651 p2_02 += 2;
3652 }
3653 outSISIDXREG(SISPART2,0x01,p2_01);
3654 outSISIDXREG(SISPART2,0x02,p2_02);
3655 }
3656 }
3657}
3658
3659static void
3660sisfb_post_setmode(struct sis_video_info *ivideo)
3661{
3662 BOOLEAN crt1isoff = FALSE;
3663 BOOLEAN doit = TRUE;
3664#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3665 u8 reg;
3666#endif
3667#ifdef CONFIG_FB_SIS_315
3668 u8 reg1;
3669#endif
3670
3671 outSISIDXREG(SISSR,0x05,0x86);
3672
3673#ifdef CONFIG_FB_SIS_315
3674 sisfb_fixup_SR11(ivideo);
3675#endif
3676
3677 /* Now we actually HAVE changed the display mode */
3678 ivideo->modechanged = 1;
3679
3680 /* We can't switch off CRT1 if bridge is in slave mode */
3681 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
3682 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3683 } else ivideo->sisfb_crt1off = 0;
3684
3685#ifdef CONFIG_FB_SIS_300
3686 if(ivideo->sisvga_engine == SIS_300_VGA) {
3687 if((ivideo->sisfb_crt1off) && (doit)) {
3688 crt1isoff = TRUE;
3689 reg = 0x00;
3690 } else {
3691 crt1isoff = FALSE;
3692 reg = 0x80;
3693 }
3694 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3695 }
3696#endif
3697#ifdef CONFIG_FB_SIS_315
3698 if(ivideo->sisvga_engine == SIS_315_VGA) {
3699 if((ivideo->sisfb_crt1off) && (doit)) {
3700 crt1isoff = TRUE;
3701 reg = 0x40;
3702 reg1 = 0xc0;
3703 } else {
3704 crt1isoff = FALSE;
3705 reg = 0x00;
3706 reg1 = 0x00;
3707
3708 }
3709 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3710 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3711 }
3712#endif
3713
3714 if(crt1isoff) {
3715 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3716 ivideo->currentvbflags |= VB_SINGLE_MODE;
3717 } else {
3718 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3719 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3720 ivideo->currentvbflags |= VB_MIRROR_MODE;
3721 } else {
3722 ivideo->currentvbflags |= VB_SINGLE_MODE;
3723 }
3724 }
3725
3726 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3727
3728 if(ivideo->currentvbflags & CRT2_TV) {
3729 if(ivideo->vbflags & VB_SISBRIDGE) {
3730 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3731 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3732 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3733 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3734 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3735 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3736 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3737 } else if(ivideo->vbflags & VB_CHRONTEL) {
3738 if(ivideo->chronteltype == 1) {
3739 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3740 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3741 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3742 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3743 }
3744 }
3745 }
3746
3747 if(ivideo->tvxpos) {
3748 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3749 }
3750 if(ivideo->tvypos) {
3751 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3752 }
3753
3754 if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) { /* Set filter for SiS301 */
3755
3756 unsigned char filter_tb = 0;
3757
3758 switch (ivideo->video_width) {
3759 case 320:
3760 filter_tb = (ivideo->vbflags & TV_NTSC) ? 4 : 12;
3761 break;
3762 case 640:
3763 filter_tb = (ivideo->vbflags & TV_NTSC) ? 5 : 13;
3764 break;
3765 case 720:
3766 filter_tb = (ivideo->vbflags & TV_NTSC) ? 6 : 14;
3767 break;
3768 case 400:
3769 case 800:
3770 filter_tb = (ivideo->vbflags & TV_NTSC) ? 7 : 15;
3771 break;
3772 default:
3773 ivideo->sisfb_filter = -1;
3774 break;
3775 }
3776
3777 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
3778
3779 if(ivideo->vbflags & TV_NTSC) {
3780
3781 andSISIDXREG(SISPART2, 0x3a, 0x1f);
3782
3783 if (ivideo->vbflags & TV_SVIDEO) {
3784
3785 andSISIDXREG(SISPART2, 0x30, 0xdf);
3786
3787 } else if (ivideo->vbflags & TV_AVIDEO) {
3788
3789 orSISIDXREG(SISPART2, 0x30, 0x20);
3790
3791 switch (ivideo->video_width) {
3792 case 640:
3793 outSISIDXREG(SISPART2, 0x35, 0xEB);
3794 outSISIDXREG(SISPART2, 0x36, 0x04);
3795 outSISIDXREG(SISPART2, 0x37, 0x25);
3796 outSISIDXREG(SISPART2, 0x38, 0x18);
3797 break;
3798 case 720:
3799 outSISIDXREG(SISPART2, 0x35, 0xEE);
3800 outSISIDXREG(SISPART2, 0x36, 0x0C);
3801 outSISIDXREG(SISPART2, 0x37, 0x22);
3802 outSISIDXREG(SISPART2, 0x38, 0x08);
3803 break;
3804 case 400:
3805 case 800:
3806 outSISIDXREG(SISPART2, 0x35, 0xEB);
3807 outSISIDXREG(SISPART2, 0x36, 0x15);
3808 outSISIDXREG(SISPART2, 0x37, 0x25);
3809 outSISIDXREG(SISPART2, 0x38, 0xF6);
3810 break;
3811 }
3812 }
3813
3814 } else if(ivideo->vbflags & TV_PAL) {
3815
3816 andSISIDXREG(SISPART2, 0x3A, 0x1F);
3817
3818 if (ivideo->vbflags & TV_SVIDEO) {
3819
3820 andSISIDXREG(SISPART2, 0x30, 0xDF);
3821
3822 } else if (ivideo->vbflags & TV_AVIDEO) {
3823
3824 orSISIDXREG(SISPART2, 0x30, 0x20);
3825
3826 switch (ivideo->video_width) {
3827 case 640:
3828 outSISIDXREG(SISPART2, 0x35, 0xF1);
3829 outSISIDXREG(SISPART2, 0x36, 0xF7);
3830 outSISIDXREG(SISPART2, 0x37, 0x1F);
3831 outSISIDXREG(SISPART2, 0x38, 0x32);
3832 break;
3833 case 720:
3834 outSISIDXREG(SISPART2, 0x35, 0xF3);
3835 outSISIDXREG(SISPART2, 0x36, 0x00);
3836 outSISIDXREG(SISPART2, 0x37, 0x1D);
3837 outSISIDXREG(SISPART2, 0x38, 0x20);
3838 break;
3839 case 400:
3840 case 800:
3841 outSISIDXREG(SISPART2, 0x35, 0xFC);
3842 outSISIDXREG(SISPART2, 0x36, 0xFB);
3843 outSISIDXREG(SISPART2, 0x37, 0x14);
3844 outSISIDXREG(SISPART2, 0x38, 0x2A);
3845 break;
3846 }
3847 }
3848 }
3849
3850 if((ivideo->sisfb_filter >= 0) && (ivideo->sisfb_filter <= 7)) {
3851 outSISIDXREG(SISPART2,0x35,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][0]));
3852 outSISIDXREG(SISPART2,0x36,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][1]));
3853 outSISIDXREG(SISPART2,0x37,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][2]));
3854 outSISIDXREG(SISPART2,0x38,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][3]));
3855 }
3856
3857 }
3858}
3859
3860#ifndef MODULE
3861SISINITSTATIC int __init sisfb_setup(char *options)
3862{
3863 char *this_opt;
3864
3865 sisfb_setdefaultparms();
3866
3867 printk(KERN_DEBUG "sisfb: Options %s\n", options);
3868
3869 if(!options || !(*options)) {
3870 return 0;
3871 }
3872
3873 while((this_opt = strsep(&options, ",")) != NULL) {
3874
3875 if(!(*this_opt)) continue;
3876
3877 if(!strnicmp(this_opt, "off", 3)) {
3878 sisfb_off = 1;
3879 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3880 /* Need to check crt2 type first for fstn/dstn */
3881 sisfb_search_crt2type(this_opt + 14);
3882 } else if(!strnicmp(this_opt, "tvmode:",7)) {
3883 sisfb_search_tvstd(this_opt + 7);
3884 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3885 sisfb_search_tvstd(this_opt + 7);
3886 } else if(!strnicmp(this_opt, "mode:", 5)) {
3887 sisfb_search_mode(this_opt + 5, FALSE);
3888 } else if(!strnicmp(this_opt, "vesa:", 5)) {
3889 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
3890#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
3891 } else if(!strnicmp(this_opt, "inverse", 7)) {
3892 sisfb_inverse = 1;
3893 /* fb_invert_cmaps(); */
3894 } else if(!strnicmp(this_opt, "font:", 5)) {
3895 if(strlen(this_opt + 5) < 40) {
3896 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
3897 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
3898 }
3899#endif
3900 } else if(!strnicmp(this_opt, "rate:", 5)) {
3901 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
3902 } else if(!strnicmp(this_opt, "filter:", 7)) {
3903 sisfb_filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
3904 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3905 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
3906 } else if(!strnicmp(this_opt, "mem:",4)) {
3907 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
3908 } else if(!strnicmp(this_opt, "pdc:", 4)) {
3909 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
3910 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
3911 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
3912 } else if(!strnicmp(this_opt, "noaccel", 7)) {
3913 sisfb_accel = 0;
3914 } else if(!strnicmp(this_opt, "accel", 5)) {
3915 sisfb_accel = -1;
3916 } else if(!strnicmp(this_opt, "noypan", 6)) {
3917 sisfb_ypan = 0;
3918 } else if(!strnicmp(this_opt, "ypan", 4)) {
3919 sisfb_ypan = -1;
3920 } else if(!strnicmp(this_opt, "nomax", 5)) {
3921 sisfb_max = 0;
3922 } else if(!strnicmp(this_opt, "max", 3)) {
3923 sisfb_max = -1;
3924 } else if(!strnicmp(this_opt, "userom:", 7)) {
3925 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
3926 } else if(!strnicmp(this_opt, "useoem:", 7)) {
3927 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
3928 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
3929 sisfb_nocrt2rate = 1;
3930 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
3931 unsigned long temp = 2;
3932 temp = simple_strtoul(this_opt + 9, NULL, 0);
3933 if((temp == 0) || (temp == 1)) {
3934 sisfb_scalelcd = temp ^ 1;
3935 }
3936 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
3937 int temp = 0;
3938 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3939 if((temp >= -32) && (temp <= 32)) {
3940 sisfb_tvxposoffset = temp;
3941 }
3942 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
3943 int temp = 0;
3944 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3945 if((temp >= -32) && (temp <= 32)) {
3946 sisfb_tvyposoffset = temp;
3947 }
3948 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
3949 sisfb_search_specialtiming(this_opt + 14);
3950 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
3951 int temp = 4;
3952 temp = simple_strtoul(this_opt + 7, NULL, 0);
3953 if((temp >= 0) && (temp <= 3)) {
3954 sisfb_lvdshl = temp;
3955 }
3956 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
3957 sisfb_search_mode(this_opt, TRUE);
3958#if !defined(__i386__) && !defined(__x86_64__)
3959 } else if(!strnicmp(this_opt, "resetcard", 9)) {
3960 sisfb_resetcard = 1;
3961 } else if(!strnicmp(this_opt, "videoram:", 9)) {
3962 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
3963#endif
3964 } else {
3965 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
3966 }
3967
3968 }
3969
3970
3971
3972 return 0;
3973}
3974#endif
3975
3976static UCHAR * __devinit sis_find_rom(struct pci_dev *pdev)
3977{
3978 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3979 USHORT pciid;
3980 int romptr;
3981 UCHAR *myrombase;
3982 u32 temp;
3983 SIS_IOTYPE1 *rom_base, *rom;
3984
3985 if(!(myrombase = vmalloc(65536))) return NULL;
3986
3987#if defined(__i386__) || defined(__x86_64__)
3988
3989 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
3990
3991 rom_base = ioremap(temp, 0x10000);
3992 if(!rom_base) continue;
3993
3994 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) {
3995 iounmap(rom_base);
3996 continue;
3997 }
3998
3999 romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4000 if(romptr > (0x10000 - 8)) {
4001 iounmap(rom_base);
4002 continue;
4003 }
4004
4005 rom = rom_base + romptr;
4006
4007 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4008 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) {
4009 iounmap(rom_base);
4010 continue;
4011 }
4012
4013 pciid = readb(rom + 4) | (readb(rom + 5) << 8);
4014 if(pciid != 0x1039) {
4015 iounmap(rom_base);
4016 continue;
4017 }
4018
4019 pciid = readb(rom + 6) | (readb(rom + 7) << 8);
4020 if(pciid == ivideo->chip_id) {
4021 memcpy_fromio(myrombase, rom_base, 65536);
4022 iounmap(rom_base);
4023 return myrombase;
4024 }
4025
4026 iounmap(rom_base);
4027 }
4028
4029#else
4030
4031 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4032 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4033 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4034
4035 rom_base = ioremap(ivideo->video_base, 65536);
4036 if(rom_base) {
4037 if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) {
4038 romptr = (u16)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4039 if(romptr <= (0x10000 - 8)) {
4040 rom = rom_base + romptr;
4041 if((readb(rom) == 'P') && (readb(rom + 1) == 'C') &&
4042 (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) {
4043 pciid = readb(rom + 4) | (readb(rom + 5) << 8);
4044 if(pciid == 0x1039) {
4045 pciid = readb(rom + 6) | (readb(rom + 7) << 8);
4046 if(pciid == ivideo->chip_id) {
4047 memcpy_fromio(myrombase, rom_base, 65536);
4048 iounmap(rom_base);
4049 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4050 return myrombase;
4051 }
4052 }
4053 }
4054 }
4055 }
4056 iounmap(rom_base);
4057 }
4058 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4059
4060#endif
4061
4062 vfree(myrombase);
4063 return NULL;
4064}
4065
4066#ifdef CONFIG_FB_SIS_300
4067static int __devinit
4068sisfb_chkbuswidth300(struct pci_dev *pdev, SIS_IOTYPE1 *FBAddress)
4069{
4070 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4071 int i, j;
4072 USHORT temp;
4073 UCHAR reg;
4074
4075 andSISIDXREG(SISSR,0x15,0xFB);
4076 orSISIDXREG(SISSR,0x15,0x04);
4077 outSISIDXREG(SISSR,0x13,0x00);
4078 outSISIDXREG(SISSR,0x14,0xBF);
4079
4080 for(i=0; i<2; i++) {
4081 temp = 0x1234;
4082 for(j=0; j<4; j++) {
4083 writew(temp, FBAddress);
4084 if(readw(FBAddress) == temp) break;
4085 orSISIDXREG(SISSR,0x3c,0x01);
4086 inSISIDXREG(SISSR,0x05,reg);
4087 inSISIDXREG(SISSR,0x05,reg);
4088 andSISIDXREG(SISSR,0x3c,0xfe);
4089 inSISIDXREG(SISSR,0x05,reg);
4090 inSISIDXREG(SISSR,0x05,reg);
4091 temp++;
4092 }
4093 }
4094
4095 writel(0x01234567L, FBAddress);
4096 writel(0x456789ABL, (FBAddress+4));
4097 writel(0x89ABCDEFL, (FBAddress+8));
4098 writel(0xCDEF0123L, (FBAddress+12));
4099 inSISIDXREG(SISSR,0x3b,reg);
4100 if(reg & 0x01) {
4101 if(readl((FBAddress+12)) == 0xCDEF0123L) return(4); /* Channel A 128bit */
4102 }
4103 if(readl((FBAddress+4)) == 0x456789ABL) return(2); /* Channel B 64bit */
4104 return(1); /* 32bit */
4105}
4106
4107static void __devinit
4108sisfb_setramsize300(struct pci_dev *pdev)
4109{
4110 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4111 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4112 SIS_IOTYPE1 *Addr;
4113 USHORT sr13, sr14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0;
4114 int PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
4115 int RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
4116 int PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k;
4117 const USHORT SiS_DRAMType[17][5] = {
4118 {0x0C,0x0A,0x02,0x40,0x39},
4119 {0x0D,0x0A,0x01,0x40,0x48},
4120 {0x0C,0x09,0x02,0x20,0x35},
4121 {0x0D,0x09,0x01,0x20,0x44},
4122 {0x0C,0x08,0x02,0x10,0x31},
4123 {0x0D,0x08,0x01,0x10,0x40},
4124 {0x0C,0x0A,0x01,0x20,0x34},
4125 {0x0C,0x09,0x01,0x08,0x32},
4126 {0x0B,0x08,0x02,0x08,0x21},
4127 {0x0C,0x08,0x01,0x08,0x30},
4128 {0x0A,0x08,0x02,0x04,0x11},
4129 {0x0B,0x0A,0x01,0x10,0x28},
4130 {0x09,0x08,0x02,0x02,0x01},
4131 {0x0B,0x09,0x01,0x08,0x24},
4132 {0x0B,0x08,0x01,0x04,0x20},
4133 {0x0A,0x08,0x01,0x02,0x10},
4134 {0x09,0x08,0x01,0x01,0x00}
4135 };
4136
4137 buswidth = sisfb_chkbuswidth300(pdev, FBAddr);
4138
4139 MB2Bank = 16;
4140 Done = 0;
4141 for(i = 6; i >= 0; i--) {
4142 if(Done) break;
4143 PseudoRankCapacity = 1 << i;
4144 for(j = 4; j >= 1; j--) {
4145 if(Done) break;
4146 PseudoTotalCapacity = PseudoRankCapacity * j;
4147 PseudoAdrPinCount = 15 - j;
4148 if(PseudoTotalCapacity <= 64) {
4149 for(k = 0; k <= 16; k++) {
4150 if(Done) break;
4151 RankCapacity = buswidth * SiS_DRAMType[k][3];
4152 AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
4153 if(RankCapacity == PseudoRankCapacity)
4154 if(AdrPinCount <= PseudoAdrPinCount) {
4155 if(j == 3) { /* Rank No */
4156 BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
4157 BankNumMid = RankCapacity * MB2Bank * 1 - 1;
4158 } else {
4159 BankNumHigh = RankCapacity * MB2Bank * j - 1;
4160 BankNumMid = RankCapacity * MB2Bank * j / 2 - 1;
4161 }
4162 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4163 PhysicalAdrHigh = BankNumHigh;
4164 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4165 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4166 /* Write data */
4167 andSISIDXREG(SISSR,0x15,0xFB); /* Test */
4168 orSISIDXREG(SISSR,0x15,0x04); /* Test */
4169 TotalCapacity = SiS_DRAMType[k][3] * buswidth;
4170 sr13 = SiS_DRAMType[k][4];
4171 if(buswidth == 4) sr14 = (TotalCapacity - 1) | 0x80;
4172 if(buswidth == 2) sr14 = (TotalCapacity - 1) | 0x40;
4173 if(buswidth == 1) sr14 = (TotalCapacity - 1) | 0x00;
4174 outSISIDXREG(SISSR,0x13,sr13);
4175 outSISIDXREG(SISSR,0x14,sr14);
4176 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4177 /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */
4178 writew(((USHORT)PhysicalAdrHigh), Addr);
4179 Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh;
4180 /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */
4181 writew(((USHORT)BankNumMid), Addr);
4182 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage;
4183 /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */
4184 writew(((USHORT)PhysicalAdrHalfPage), Addr);
4185 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage;
4186 /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */
4187 writew(((USHORT)PhysicalAdrOtherPage), Addr);
4188 /* Read data */
4189 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4190 data = readw(Addr); /* *((USHORT *)(Addr)); */
4191 if(data == PhysicalAdrHigh) Done = 1;
4192 } /* if */
4193 } /* for k */
4194 } /* if */
4195 } /* for j */
4196 } /* for i */
4197}
4198
4199static void __devinit sisfb_post_sis300(struct pci_dev *pdev)
4200{
4201 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4202 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4203 u16 index, rindex, memtype = 0;
4204
4205 outSISIDXREG(SISSR,0x05,0x86);
4206
4207 if(ivideo->sishw_ext.UseROM) {
4208 if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80) {
4209 memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4210 } else {
4211 inSISIDXREG(SISSR,0x3a,memtype);
4212 }
4213 memtype &= 0x07;
4214 }
4215
4216 if(ivideo->revision_id <= 0x13) {
4217 v1 = 0x44; v2 = 0x42; v3 = 0x80;
4218 v4 = 0x44; v5 = 0x42; v6 = 0x80;
4219 } else {
4220 v1 = 0x68; v2 = 0x43; v3 = 0x80; /* Assume 125Mhz MCLK */
4221 v4 = 0x68; v5 = 0x43; v6 = 0x80; /* Assume 125Mhz ECLK */
4222 if(ivideo->sishw_ext.UseROM) {
4223 index = memtype * 5;
4224 rindex = index + 0x54;
4225 v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4226 v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4227 v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4228 rindex = index + 0x7c;
4229 v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4230 v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4231 v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4232 }
4233 }
4234 outSISIDXREG(SISSR,0x28,v1);
4235 outSISIDXREG(SISSR,0x29,v2);
4236 outSISIDXREG(SISSR,0x2a,v3);
4237 outSISIDXREG(SISSR,0x2e,v4);
4238 outSISIDXREG(SISSR,0x2f,v5);
4239 outSISIDXREG(SISSR,0x30,v6);
4240 v1 = 0x10;
4241 if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0xa4];
4242 outSISIDXREG(SISSR,0x07,v1); /* DAC speed */
4243 outSISIDXREG(SISSR,0x11,0x0f); /* DDC, power save */
4244 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4245 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4246 if(ivideo->sishw_ext.UseROM) {
4247 memtype += 0xa5;
4248 v1 = ivideo->sishw_ext.pjVirtualRomBase[memtype];
4249 v2 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 8];
4250 v3 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 16];
4251 v4 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 24];
4252 v5 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 32];
4253 v6 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 40];
4254 v7 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 48];
4255 v8 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 56];
4256 }
4257 if(ivideo->revision_id >= 0x80) v3 &= 0xfd;
4258 outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4259 outSISIDXREG(SISSR,0x16,v2);
4260 outSISIDXREG(SISSR,0x17,v3);
4261 outSISIDXREG(SISSR,0x18,v4);
4262 outSISIDXREG(SISSR,0x19,v5);
4263 outSISIDXREG(SISSR,0x1a,v6);
4264 outSISIDXREG(SISSR,0x1b,v7);
4265 outSISIDXREG(SISSR,0x1c,v8); /* ---- */
4266 andSISIDXREG(SISSR,0x15,0xfb);
4267 orSISIDXREG(SISSR,0x15,0x04);
4268 if(ivideo->sishw_ext.UseROM) {
4269 if(ivideo->sishw_ext.pjVirtualRomBase[0x53] & 0x02) {
4270 orSISIDXREG(SISSR,0x19,0x20);
4271 }
4272 }
4273 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4274 if(ivideo->revision_id >= 0x80) v1 |= 0x01;
4275 outSISIDXREG(SISSR,0x1f,v1);
4276 outSISIDXREG(SISSR,0x20,0xa0); /* linear & relocated io */
4277 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4278 if(ivideo->sishw_ext.UseROM) {
4279 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe8];
4280 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe9];
4281 v3 = ivideo->sishw_ext.pjVirtualRomBase[0xea];
4282 }
4283 outSISIDXREG(SISSR,0x23,v1);
4284 outSISIDXREG(SISSR,0x24,v2);
4285 outSISIDXREG(SISSR,0x25,v3);
4286 outSISIDXREG(SISSR,0x21,0x84);
4287 outSISIDXREG(SISSR,0x22,0x00);
4288 outSISIDXREG(SISCR,0x37,0x00);
4289 orSISIDXREG(SISPART1,0x24,0x01); /* unlock crt2 */
4290 outSISIDXREG(SISPART1,0x00,0x00);
4291 v1 = 0x40; v2 = 0x11;
4292 if(ivideo->sishw_ext.UseROM) {
4293 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xec];
4294 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xeb];
4295 }
4296 outSISIDXREG(SISPART1,0x02,v1);
4297 if(ivideo->revision_id >= 0x80) v2 &= ~0x01;
4298 inSISIDXREG(SISPART4,0x00,reg);
4299 if((reg == 1) || (reg == 2)) {
4300 outSISIDXREG(SISCR,0x37,0x02);
4301 outSISIDXREG(SISPART2,0x00,0x1c);
4302 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4303 if(ivideo->sishw_ext.UseROM) {
4304 v4 = ivideo->sishw_ext.pjVirtualRomBase[0xf5];
4305 v5 = ivideo->sishw_ext.pjVirtualRomBase[0xf6];
4306 v6 = ivideo->sishw_ext.pjVirtualRomBase[0xf7];
4307 }
4308 outSISIDXREG(SISPART4,0x0d,v4);
4309 outSISIDXREG(SISPART4,0x0e,v5);
4310 outSISIDXREG(SISPART4,0x10,v6);
4311 outSISIDXREG(SISPART4,0x0f,0x3f);
4312 inSISIDXREG(SISPART4,0x01,reg);
4313 if(reg >= 0xb0) {
4314 inSISIDXREG(SISPART4,0x23,reg);
4315 reg &= 0x20;
4316 reg <<= 1;
4317 outSISIDXREG(SISPART4,0x23,reg);
4318 }
4319 } else {
4320 v2 &= ~0x10;
4321 }
4322 outSISIDXREG(SISSR,0x32,v2);
4323 andSISIDXREG(SISPART1,0x24,0xfe); /* Lock CRT2 */
4324 inSISIDXREG(SISSR,0x16,reg);
4325 reg &= 0xc3;
4326 outSISIDXREG(SISCR,0x35,reg);
4327 outSISIDXREG(SISCR,0x83,0x00);
4328#if !defined(__i386__) && !defined(__x86_64__)
4329 if(sisfb_videoram) {
4330 outSISIDXREG(SISSR,0x13,0x28); /* ? */
4331 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4332 outSISIDXREG(SISSR,0x14,reg);
4333 } else {
4334#endif
4335 /* Need to map max FB size for finding out about RAM size */
4336 ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000);
4337 if(ivideo->video_vbase) {
4338 sisfb_setramsize300(pdev);
4339 iounmap(ivideo->video_vbase);
4340 } else {
4341 printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4342 outSISIDXREG(SISSR,0x13,0x28); /* ? */
4343 outSISIDXREG(SISSR,0x14,0x47); /* 8MB, 64bit default */
4344 }
4345#if !defined(__i386__) && !defined(__x86_64__)
4346 }
4347#endif
4348 if(ivideo->sishw_ext.UseROM) {
4349 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe6];
4350 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe7];
4351 } else {
4352 inSISIDXREG(SISSR,0x3a,reg);
4353 if((reg & 0x30) == 0x30) {
4354 v1 = 0x04; /* PCI */
4355 v2 = 0x92;
4356 } else {
4357 v1 = 0x14; /* AGP */
4358 v2 = 0xb2;
4359 }
4360 }
4361 outSISIDXREG(SISSR,0x21,v1);
4362 outSISIDXREG(SISSR,0x22,v2);
4363}
4364#endif
4365
4366#ifdef CONFIG_FB_SIS_315
4367static void __devinit sisfb_post_sis315330(struct pci_dev *pdev)
4368{
4369#ifdef YET_TO_BE_DONE
4370 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4371 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4372 u16 index, rindex, memtype = 0;
4373 u32 reg1_32, reg2_32, reg3_32;
4374 int i;
4375
4376 /* Unlock */
4377 /* outSISIDXREG(0x3c4,0x05,0x86); */
4378 outSISIDXREG(SISSR,0x05,0x86);
4379
4380 /* Enable relocated i/o ports */
4381 /* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */
4382 setSISIDXREG(SISSR,0x20,~0x10,0x20);
4383
4384 /* Clear regs */
4385 for(i = 0; i < 0x22; i++) {
4386 outSISIDXREG(SISSR,(0x06 + i),0x00);
4387 }
4388 v1 = 0x0d;
4389 if( is 330) v1 = 0x0b;
4390 for(i = 0; i < v1; i++) {
4391 outSISIDXREG(SISSR,(0x31 + i),0x00);
4392 }
4393 for(i = 0; i < 0x10; i++) {
4394 outSISIDXREG(SISCR,(0x30 + i),0x00);
4395 }
4396
4397 /* Reset clocks */
4398 reg = inSISREG(SISMISCR);
4399 outSISIDXREG(SISSR,0x28,0x81);
4400 outSISIDXREG(SISSR,0x2A,0x00);
4401 outSISIDXREG(SISSR,0x29,0xE1);
4402 outSISREG(SISMISCW,(reg | 0x0c));
4403 outSISIDXREG(SISSR,0x2B,0x81);
4404 outSISIDXREG(SISSR,0x2D,0x00);
4405 outSISIDXREG(SISSR,0x2C,0xE1);
4406 outSISIDXREG(SISSR,0x2E,0x81);
4407 outSISIDXREG(SISSR,0x30,0x00);
4408 outSISIDXREG(SISSR,0x2F,0xE1);
4409 SiS_DDC2Delay(....);
4410 outSISREG(SISMISCW,reg);
4411
4412 /* Get memory type */
4413 if(ivideo->sishw_ext.UseROM) {
4414 if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80)) {
4415 memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4416 } else {
4417 inSISIDXREG(SISSR,0x3a,memtype);
4418 }
4419 memtype &= 0x03;
4420 if( is 330 ) {
4421 if(memtype <= 1) memtype = 0;
4422 else {
4423 inSISIDXREG(SISCR,0x5F,reg);
4424 reg &= 0x30;
4425 switch(reg) {
4426 case 0x00: memtype = 1; break;
4427 case 0x10: memtype = 3; break;
4428 case 0x20: memtype = 3; break;
4429 default: memtype = 2;
4430 }
4431 }
4432 }
4433 }
4434
4435 /* Set clocks */
4436 v1 = 0x3b; v2 = 0x22; v3 = 0x01; /* Assume 143Mhz MCLK */
4437 v4 = 0x5c; v5 = 0x23; v6 = 0x01; /* Assume 166Mhz ECLK */
4438 if(ivideo->sishw_ext.UseROM) {
4439 index = memtype * 5;
4440 rindex = index + 0x54;
4441 v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4442 v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4443 v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4444 rindex = index + 0x68;
4445 v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4446 v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4447 v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4448 }
4449 outSISIDXREG(SISSR,0x28,v1);
4450 outSISIDXREG(SISSR,0x29,v2);
4451 outSISIDXREG(SISSR,0x2a,v3);
4452 if( is 330 ) {
4453 inSISIDXREG(SISSR,0x3a,reg);
4454 reg &= 0x03;
4455 if(reg >= 2) {
4456 ...
4457 }
4458 }
4459 outSISIDXREG(SISSR,0x2e,v4);
4460 outSISIDXREG(SISSR,0x2f,v5);
4461 outSISIDXREG(SISSR,0x30,v6);
4462
4463 /* End of comp with 330 */
4464
4465 v1 = 0x18;
4466 if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0x7c];
4467 outSISIDXREG(SISSR,0x07,v1);
4468 outSISIDXREG(SISSR,0x11,0x0f);
4469
4470 v1 = 0x00; v2 = 0x0f; v3 = 0xba; v4 = 0xa9;
4471 v5 = 0xa0; v6 = 0x00; v7 = 0x30;
4472 if(ivideo->sishw_ext.UseROM) {
4473 index = memtype + 0x7d;
4474 v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4475 v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4476 v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4477 v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4478 v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4479 v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
4480 v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
4481 }
4482 outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0x7d step 4) */
4483 outSISIDXREG(SISSR,0x16,v2);
4484 outSISIDXREG(SISSR,0x17,v3);
4485 outSISIDXREG(SISSR,0x18,v4);
4486 outSISIDXREG(SISSR,0x19,v5);
4487 outSISIDXREG(SISSR,0x1a,v6);
4488 outSISIDXREG(SISSR,0x1b,v7);
4489 outSISIDXREG(SISSR,0x1c,v8); /* ---- */
4490
4491 v1 = 0x77; v2 = 0x77; v3 = 0x00; v4 = 0x5b; v5 = 0x00;
4492 if(ivideo->sishw_ext.UseROM) {
4493 index = memtype + 0xa2;
4494 v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4495 v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4496 v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4497 v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4498 v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4499 }
4500 outSISIDXREG(SISCR,0x40,v1);
4501 outSISIDXREG(SISCR,0x41,v2);
4502 outSISIDXREG(SISCR,0x42,v3);
4503 outSISIDXREG(SISCR,0x43,v4);
4504 outSISIDXREG(SISCR,0x44,v5);
4505
4506 if( is 330 ) {
4507
4508 v1 = 0x;
4509 if(ivideo->sishw_ext.UseROM) {
4510 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4511 }
4512 outSISIDXREG(SISCR,0x59,v1);
4513
4514 v1 = 0x; v2 = 0x; v3 = 0x; v4 = 0x;
4515 v5 = 0x; v6 = 0x; v7 = 0x; v8 = 0x;
4516 if(ivideo->sishw_ext.UseROM) {
4517 index = memtype + 0xbe;
4518 v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4519 v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4520 v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4521 v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4522 v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4523 v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
4524 v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
4525 v8 = ivideo->sishw_ext.pjVirtualRomBase[index + 28];
4526 }
4527 outSISIDXREG(SISCR,0x68,v1);
4528 outSISIDXREG(SISCR,0x69,v2);
4529 outSISIDXREG(SISCR,0x6a,v3);
4530 outSISIDXREG(SISCR,0x6b,v4);
4531 outSISIDXREG(SISCR,0x6c,v5);
4532 outSISIDXREG(SISCR,0x6d,v6);
4533 outSISIDXREG(SISCR,0x6e,v7);
4534 outSISIDXREG(SISCR,0x6f,v8);
4535
4536 v1 = 0x20;
4537 inSISIDXREG(SISSR,0x3b,reg);
4538
4539 if(!(reg & 0x04)) {
4540 inSISIDXREG(SISCR,0x5F,reg);
4541 reg &= 0x30;
4542 if(reg) v1 = 0x23;
4543 }
4544 outSISIDXREG(SISCR,0x48,v1);
4545 outSISIDXREG(SISCR,0x4c,0x20);
4546
4547 xx= xxx();
4548 if(xx >= 1) {
4549 v1 = 0x;
4550 if(ivideo->sishw_ext.UseROM) {
4551 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4552 }
4553 outSISIDXREG(SISCR,0x59,v1);
4554 }
4555
4556
4557
4558 } else {
4559
4560 outSISIDXREG(SISCR,0x48,0x23);
4561
4562 andSISIDXREG(SISSR,0x16,0x0f);
4563 if(memtype <= 1) {
4564 orSISIDXREG(SISSR,0x16,0x80);
4565 } else {
4566 v1 = 0x0f;
4567 if(ivideo->sishw_ext.UseROM) {
4568 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x81 + memtype];
4569 }
4570 if(!(v1 & 0x10)) v2 = 0xc0;
4571 else v2 = 0xd0;
4572 orSISIDXREG(SISSR,0x16,v2);
4573 andSISIDXREG(SISSR,0x16,0x0f);
4574 if(!(v1 & 0x10)) v2 = 0x80;
4575 else v2 = 0xA0;
4576 orSISIDXREG(SISSR,0x16,v2);
4577 }
4578
4579 if(memtype >= 2) {
4580 const u8 sr3cseq1[] = { 0xc0,0xe0,0xf0,0xe0,0xf0,0xa0,0xb0,0xa0,0xb0,0x90,0xd0 };
4581 const u8 sr3cseq2[] = { 0xc0,0xa0,0xb0,0xa0,0xb0,0xe0,0xf0,0xa0,0xb0,0x90,0xd0 };
4582 for(i = 0; i < 11; i++) {
4583 outSISIDXREG(SISSR,0x3c,sr3cseq1[i]);
4584 }
4585 outSISIDXREG(SISSR,0x3d,0x00);
4586 outSISIDXREG(SISSR,0x3d,0x04);
4587 SiS_DDC2Delay(0x200);
4588 v1 = inSISIDXREG(SISCR,0xEC);
4589 v2 = inSISIDXREG(SISCR,0xED);
4590 reg1_32 = (v2 << 8) | v1;
4591 outSISIDXREG(SISSR,0x3D,0x00);
4592 for(i = 0; i < 11; i++) {
4593 outSISIDXREG(SISSR,0x3c,sr3cseq2[i]);
4594 }
4595 outSISIDXREG(SISSR,0x3d,0x00);
4596 outSISIDXREG(SISSR,0x3d,0x04);
4597 SiS_DDC2Delay(0x200);
4598 v1 = inSISIDXREG(SISCR,0xEC);
4599 v2 = inSISIDXREG(SISCR,0xED);
4600 reg2_32 = (v2 << 8) | v1;
4601 outSISIDXREG(SISSR,0x3D,0x00);
4602 reg3_32 = reg2_32 << 1;
4603 reg2_32 >>= 1;
4604 reg3_32 += reg2_32;
4605 v1 = 0x40;
4606 if(reg3_32 > reg1_32) v1 = 0x10;
4607 outSISIDXREG(SISCR,0x59,v1);
4608 }
4609
4610 }
4611
4612 v1 = 0x00;
4613 if(ivideo->sishw_ext.UseROM) {
4614 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x99];
4615 }
4616 outSISIDXREG(SISSR,0x1f,v1);
4617
4618 outSISIDXREG(SISSR,0x20,0x20);
4619
4620 v1 = 0xf6; v2 = 0x0d; v3 = 0x33;
4621 if(ivideo->sishw_ext.UseROM) {
4622 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9c];
4623 v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9d];
4624 v3 = ivideo->sishw_ext.pjVirtualRomBase[0x9e];
4625 }
4626 outSISIDXREG(SISSR,0x23,v1);
4627 outSISIDXREG(SISSR,0x24,v2);
4628 outSISIDXREG(SISSR,0x25,v3);
4629
4630 outSISIDXREG(SISSR,0x21,0x84);
4631 outSISIDXREG(SISSR,0x22,0x00);
4632 outSISIDXREG(SISSR,0x27,0x1f);
4633
4634 v1 = 0x00; v2 = 0x00;
4635 if(ivideo->sishw_ext.UseROM) {
4636 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9F];
4637 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xA1];
4638 }
4639 outSISIDXREG(SISSR,0x31,v1);
4640 outSISIDXREG(SISSR,0x33,v2);
4641
4642 v1 = 0x11;
4643 if(ivideo->sishw_ext.UseROM) {
4644 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xA0];
4645 }
4646 v2 = inSISIDXREG(SISPART4,0x00);
4647 if((v2 != 1) && (v2 != 2)) v1 &= 0xef;
4648 outSISIDXREG(SISSR,0x32,v1);
4649
4650 /* AGP */
4651 pci_read_config_long(pdev, 0x50, &reg1_32);
4652 reg1_32 >>= 20;
4653 reg1_32 &= 0x0f;
4654 if(reg1_32 == 1) {
4655 v1 = 0xAA; v2 = 0x33;
4656 if(ivideo->sishw_ext.UseROM) {
4657 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF7];
4658 v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9E];
4659 }
4660 } else {
4661 v1 = 0x88; v2 = 0x03;
4662 if(ivideo->sishw_ext.UseROM) {
4663 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF8];
4664 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xF6];
4665 }
4666 }
4667 outSISIDXREG(SISCR,0x49,v1);
4668 outSISIDXREG(SISSR,0x25,v2);
4669
4670 v1 = inSISIDXREG(SISPART4,0x00);
4671 if((v1 == 1) || (v1 == 2)) {
4672 orSISIDXREG(SISPART1,0x2F,0x01); /* Unlock CRT2 */
4673 outSISIDXREG(SISPART1,0x00,0x00);
4674 v1 = 0x00;
4675 if(ivideo->sishw_ext.UseROM) {
4676 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb6];
4677 }
4678 outSISIDXREG(SISPART1,0x02,v1);
4679 outSISIDXREG(SISPART1,0x2E,0x08);
4680 outSISIDXREG(SISPART2,0x00,0x1c);
4681 v1 = 0x40; v2 = 0x00; v3 = 0x80;
4682 if(ivideo->sishw_ext.UseROM) {
4683 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb7];
4684 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xb8];
4685 v3 = ivideo->sishw_ext.pjVirtualRomBase[0xbb];
4686 }
4687 outSISIDXREG(SISPART4,0x0d,v1);
4688 outSISIDXREG(SISPART4,0x0e,v2);
4689 outSISIDXREG(SISPART4,0x10,v3);
4690 outSISIDXREG(SISPART4,0x0F,0x3F);
4691
4692 inSISIDXREG(SISPART4,0x01,reg);
4693 if(reg >= 0xb0) {
4694 inSISIDXREG(SISPART4,0x23,reg);
4695 reg &= 0x20;
4696 reg <<= 1;
4697 outSISIDXREG(SISPART4,0x23,reg);
4698 }
4699 }
4700 outSISIDXREG(SISCR,0x37,0x02); /* Why? */
4701
4702 outSISIDXREG(SISCR,0x83,0x00);
4703 outSISIDXREG(SISCR,0x90,0x00);
4704 andSISIDXREG(SISSR,0x5B,0xDF);
4705 outSISIDXREG(SISVID,0x00,0x86);
4706 outSISIDXREG(SISVID,0x32,0x00);
4707 outSISIDXREG(SISVID,0x30,0x00);
4708 outSISIDXREG(SISVID,0x32,0x01);
4709 outSISIDXREG(SISVID,0x30,0x00);
4710 orSISIDXREG(SISCR,0x63,0x80);
4711 /* End of Init1 */
4712
4713 /* Set Mode 0x2e */
4714
4715 /* Ramsize */
4716 orSISIDXREG(SISSR,0x16,0x0f);
4717 orSISIDXREG(SISSR,0x18,0xA9);
4718 orSISIDXREG(SISSR,0x19,0xA0);
4719 orSISIDXREG(SISSR,0x1B,0x30);
4720 andSISIDXREG(SISSR,0x17,0xF8);
4721 orSISIDXREG(SISSR,0x19,0x03);
4722 andSIDIDXREG(SISSR,0x13,0x00);
4723
4724 /* Need to map max FB size for finding out about RAM size */
4725 ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000);
4726 if(ivideo->video_vbase) {
4727 /* Find out about bus width */
4728 if(memtype <= 1) {
4729 outSISIDXREG(SISSR,0x14,0x02);
4730 andSISIDXREG(SISSR,0x16,0x0F);
4731 orSISIDXREG(SISSR,0x16,0x80);
4732
4733 ...
4734
4735 } else {
4736
4737 ...
4738
4739 }
4740
4741 /* Find out about size */
4742
4743
4744 iounmap(ivideo->video_vbase);
4745 } else {
4746 printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4747 outSISIDXREG(SISSR,0x14,0x??); /* 8MB, 64bit default */
4748 }
4749
4750 /* AGP (Missing: Checks for VIA and AMD hosts) */
4751 v1 = 0xA5; v2 = 0xFB;
4752 if(ivideo->sishw_ext.UseROM) {
4753 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9A];
4754 v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9B];
4755 }
4756 outSISIDXREG(SISSR,0x21,v1);
4757 outSISIDXREG(SISSR,0x22,v2);
4758
4759#endif
4760 return;
4761}
4762#endif
4763
4764
4765int __devinit sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
4766{
4767 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
4768 struct sis_video_info *ivideo = NULL;
4769 struct fb_info *sis_fb_info = NULL;
4770 u16 reg16;
4771 u8 reg;
4772 int sisvga_enabled = 0, i;
4773
4774 if(sisfb_off) return -ENXIO;
4775
4776#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
4777 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
4778 if(!sis_fb_info) return -ENOMEM;
4779#else
4780 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
4781 if(!sis_fb_info) return -ENOMEM;
4782 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
4783 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
4784#endif
4785
4786 ivideo = (struct sis_video_info *)sis_fb_info->par;
4787 ivideo->memyselfandi = sis_fb_info;
4788
4789 if(card_list == NULL) {
4790 ivideo->cardnumber = 0;
4791 } else {
4792 struct sis_video_info *countvideo = card_list;
4793 ivideo->cardnumber = 1;
4794 while((countvideo = countvideo->next) != NULL) ivideo->cardnumber++;
4795 }
4796
4797 strncpy(ivideo->myid, chipinfo->chip_name, 30);
4798
4799 ivideo->warncount = 0;
4800 ivideo->chip_id = pdev->device;
4801 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
4802 ivideo->sishw_ext.jChipRevision = ivideo->revision_id;
4803 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
4804 sisvga_enabled = reg16 & 0x01;
4805 ivideo->pcibus = pdev->bus->number;
4806 ivideo->pcislot = PCI_SLOT(pdev->devfn);
4807 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
4808 ivideo->subsysvendor = pdev->subsystem_vendor;
4809 ivideo->subsysdevice = pdev->subsystem_device;
4810
4811#ifndef MODULE
4812 if(sisfb_mode_idx == -1) {
4813 sisfb_get_vga_mode_from_kernel();
4814 }
4815#endif
4816
4817 ivideo->chip = chipinfo->chip;
4818 ivideo->sisvga_engine = chipinfo->vgaengine;
4819 ivideo->hwcursor_size = chipinfo->hwcursor_size;
4820 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
4821 ivideo->mni = chipinfo->mni;
4822
4823 ivideo->detectedpdc = 0xff;
4824 ivideo->detectedpdca = 0xff;
4825 ivideo->detectedlcda = 0xff;
4826
4827 ivideo->sisfb_thismonitor.datavalid = FALSE;
4828
4829 ivideo->sisfb_parm_mem = sisfb_parm_mem;
4830 ivideo->sisfb_accel = sisfb_accel;
4831 ivideo->sisfb_ypan = sisfb_ypan;
4832 ivideo->sisfb_max = sisfb_max;
4833 ivideo->sisfb_userom = sisfb_userom;
4834 ivideo->sisfb_useoem = sisfb_useoem;
4835 ivideo->sisfb_mode_idx = sisfb_mode_idx;
4836 ivideo->sisfb_parm_rate = sisfb_parm_rate;
4837 ivideo->sisfb_crt1off = sisfb_crt1off;
4838 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
4839 ivideo->sisfb_crt2type = sisfb_crt2type;
4840 ivideo->sisfb_crt2flags = sisfb_crt2flags;
4841 /* pdc(a), scalelcd, special timing, lvdshl handled below */
4842 ivideo->sisfb_dstn = sisfb_dstn;
4843 ivideo->sisfb_fstn = sisfb_fstn;
4844 ivideo->sisfb_tvplug = sisfb_tvplug;
4845 ivideo->sisfb_tvstd = sisfb_tvstd;
4846 ivideo->tvxpos = sisfb_tvxposoffset;
4847 ivideo->tvypos = sisfb_tvyposoffset;
4848 ivideo->sisfb_filter = sisfb_filter;
4849 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
4850#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4851 ivideo->sisfb_inverse = sisfb_inverse;
4852#endif
4853
4854 ivideo->refresh_rate = 0;
4855 if(ivideo->sisfb_parm_rate != -1) {
4856 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
4857 }
4858
4859 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
4860 ivideo->SiS_Pr.CenterScreen = -1;
4861 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
4862 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
4863
4864 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
4865 ivideo->SiS_Pr.SiS_CHOverScan = -1;
4866 ivideo->SiS_Pr.SiS_ChSW = FALSE;
4867 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
4868 ivideo->SiS_Pr.HaveEMI = FALSE;
4869 ivideo->SiS_Pr.HaveEMILCD = FALSE;
4870 ivideo->SiS_Pr.OverruleEMI = FALSE;
4871 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
4872 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
4873 ivideo->SiS_Pr.PDC = -1;
4874 ivideo->SiS_Pr.PDCA = -1;
4875#ifdef CONFIG_FB_SIS_315
4876 if(ivideo->chip >= SIS_330) {
4877 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
4878 if(ivideo->chip >= SIS_661) {
4879 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
4880 }
4881 }
4882#endif
4883
4884 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
4885
4886 pci_set_drvdata(pdev, ivideo);
4887
4888 /* Patch special cases */
4889 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
4890 switch(ivideo->nbridge->device) {
4891#ifdef CONFIG_FB_SIS_300
4892 case PCI_DEVICE_ID_SI_730:
4893 ivideo->chip = SIS_730;
4894 strcpy(ivideo->myid, "SiS 730");
4895 break;
4896#endif
4897#ifdef CONFIG_FB_SIS_315
4898 case PCI_DEVICE_ID_SI_651:
4899 /* ivideo->chip is ok */
4900 strcpy(ivideo->myid, "SiS 651");
4901 break;
4902 case PCI_DEVICE_ID_SI_740:
4903 ivideo->chip = SIS_740;
4904 strcpy(ivideo->myid, "SiS 740");
4905 break;
4906 case PCI_DEVICE_ID_SI_661:
4907 ivideo->chip = SIS_661;
4908 strcpy(ivideo->myid, "SiS 661");
4909 break;
4910 case PCI_DEVICE_ID_SI_741:
4911 ivideo->chip = SIS_741;
4912 strcpy(ivideo->myid, "SiS 741");
4913 break;
4914 case PCI_DEVICE_ID_SI_760:
4915 ivideo->chip = SIS_760;
4916 strcpy(ivideo->myid, "SiS 760");
4917 break;
4918#endif
4919 }
4920 }
4921
4922#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4923 strcpy(sis_fb_info->modename, ivideo->myid);
4924#endif
4925
4926 ivideo->sishw_ext.jChipType = ivideo->chip;
4927
4928#ifdef CONFIG_FB_SIS_315
4929 if((ivideo->sishw_ext.jChipType == SIS_315PRO) ||
4930 (ivideo->sishw_ext.jChipType == SIS_315)) {
4931 ivideo->sishw_ext.jChipType = SIS_315H;
4932 }
4933#endif
4934
4935 ivideo->video_base = pci_resource_start(pdev, 0);
4936 ivideo->mmio_base = pci_resource_start(pdev, 1);
4937 ivideo->mmio_size = pci_resource_len(pdev, 1);
4938 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
4939 ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
4940
4941 if(!sisvga_enabled) {
4942 if(pci_enable_device(pdev)) {
4943 pci_set_drvdata(pdev, NULL);
4944 kfree(sis_fb_info);
4945 return -EIO;
4946 }
4947 }
4948
4949 SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress);
4950
4951#ifdef CONFIG_FB_SIS_300
4952 /* Find PCI systems for Chrontel/GPIO communication setup */
4953 if(ivideo->chip == SIS_630) {
4954 i=0;
4955 do {
4956 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
4957 mychswtable[i].subsysCard == ivideo->subsysdevice) {
4958 ivideo->SiS_Pr.SiS_ChSW = TRUE;
4959 printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
4960 mychswtable[i].vendorName, mychswtable[i].cardName);
4961 break;
4962 }
4963 i++;
4964 } while(mychswtable[i].subsysVendor != 0);
4965 }
4966#endif
4967
4968 outSISIDXREG(SISSR, 0x05, 0x86);
4969
4970 if( (!sisvga_enabled)
4971#if !defined(__i386__) && !defined(__x86_64__)
4972 || (sisfb_resetcard)
4973#endif
4974 ) {
4975 for(i = 0x30; i <= 0x3f; i++) {
4976 outSISIDXREG(SISCR,i,0x00);
4977 }
4978 }
4979
4980 /* Find out about current video mode */
4981 ivideo->modeprechange = 0x03;
4982 inSISIDXREG(SISCR,0x34,reg);
4983 if(reg & 0x7f) {
4984 ivideo->modeprechange = reg & 0x7f;
4985 } else if(sisvga_enabled) {
4986#if defined(__i386__) || defined(__x86_64__)
4987 unsigned char SIS_IOTYPE2 *tt = ioremap(0, 0x1000);
4988 if(tt) {
4989 ivideo->modeprechange = readb(tt + 0x449);
4990 iounmap(tt);
4991 }
4992#endif
4993 }
4994
4995#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4996#ifdef MODULE
4997 if((reg & 0x80) && (reg != 0xff)) {
4998 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) {
4999 printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
5000 pci_set_drvdata(pdev, NULL);
5001 kfree(sis_fb_info);
5002 return -EBUSY;
5003 }
5004 }
5005#endif
5006#endif
5007
5008 ivideo->sishw_ext.bIntegratedMMEnabled = TRUE;
5009#ifdef CONFIG_FB_SIS_300
5010 if(ivideo->sisvga_engine == SIS_300_VGA) {
5011 if(ivideo->chip != SIS_300) {
5012 inSISIDXREG(SISSR, 0x1a, reg);
5013 if(!(reg & 0x10)) {
5014 ivideo->sishw_ext.bIntegratedMMEnabled = FALSE;
5015 }
5016 }
5017 }
5018#endif
5019
5020 ivideo->bios_abase = NULL;
5021 if(ivideo->sisfb_userom) {
5022 ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
5023 ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase;
5024 if(ivideo->sishw_ext.pjVirtualRomBase) {
5025 printk(KERN_INFO "sisfb: Video ROM found and copied\n");
5026 ivideo->sishw_ext.UseROM = TRUE;
5027 } else {
5028 ivideo->sishw_ext.UseROM = FALSE;
5029 printk(KERN_INFO "sisfb: Video ROM not found\n");
5030 }
5031 } else {
5032 ivideo->sishw_ext.pjVirtualRomBase = NULL;
5033 ivideo->sishw_ext.UseROM = FALSE;
5034 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
5035 }
5036
5037 /* Find systems for special custom timing */
5038 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
5039 int j;
5040 unsigned char *biosver = NULL;
5041 unsigned char *biosdate = NULL;
5042 BOOLEAN footprint;
5043 u32 chksum = 0;
5044
5045 if(ivideo->sishw_ext.UseROM) {
5046 biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
5047 biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
5048 for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
5049 }
5050
5051 i=0;
5052 do {
5053 if( (mycustomttable[i].chipID == ivideo->chip) &&
5054 ((!strlen(mycustomttable[i].biosversion)) ||
5055 (ivideo->sishw_ext.UseROM &&
5056 (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
5057 ((!strlen(mycustomttable[i].biosdate)) ||
5058 (ivideo->sishw_ext.UseROM &&
5059 (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
5060 ((!mycustomttable[i].bioschksum) ||
5061 (ivideo->sishw_ext.UseROM &&
5062 (mycustomttable[i].bioschksum == chksum))) &&
5063 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
5064 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
5065 footprint = TRUE;
5066 for(j = 0; j < 5; j++) {
5067 if(mycustomttable[i].biosFootprintAddr[j]) {
5068 if(ivideo->sishw_ext.UseROM) {
5069 if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
5070 mycustomttable[i].biosFootprintData[j]) {
5071 footprint = FALSE;
5072 }
5073 } else footprint = FALSE;
5074 }
5075 }
5076 if(footprint) {
5077 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
5078 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
5079 mycustomttable[i].vendorName,
5080 mycustomttable[i].cardName);
5081 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
5082 mycustomttable[i].optionName);
5083 break;
5084 }
5085 }
5086 i++;
5087 } while(mycustomttable[i].chipID);
5088 }
5089
5090#ifdef CONFIG_FB_SIS_300
5091 if(ivideo->sisvga_engine == SIS_300_VGA) {
5092 if( (!sisvga_enabled)
5093#if !defined(__i386__) && !defined(__x86_64__)
5094 || (sisfb_resetcard)
5095#endif
5096 ) {
5097 if(ivideo->chip == SIS_300) {
5098 sisfb_post_sis300(pdev);
5099 }
5100 }
5101 }
5102#endif
5103
5104#ifdef CONFIG_FB_SIS_315
5105 if(ivideo->sisvga_engine == SIS_315_VGA) {
5106 if( (!sisvga_enabled)
5107#if !defined(__i386__) && !defined(__x86_64__)
5108 || (sisfb_resetcard)
5109#endif
5110 ) {
5111 if((ivideo->chip == SIS_315H) ||
5112 (ivideo->chip == SIS_315) ||
5113 (ivideo->chip == SIS_315PRO) ||
5114 (ivideo->chip == SIS_330)) {
5115 sisfb_post_sis315330(pdev);
5116 }
5117 }
5118 }
5119#endif
5120
5121 if(sisfb_get_dram_size(ivideo)) {
5122 printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
5123 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5124 pci_set_drvdata(pdev, NULL);
5125 kfree(sis_fb_info);
5126 return -ENODEV;
5127 }
5128
5129 if((ivideo->sisfb_mode_idx < 0) ||
5130 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5131 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
5132 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
5133 /* Enable 2D accelerator engine */
5134 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
5135 }
5136
5137 if(sisfb_pdc != 0xff) {
5138 if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
5139 else sisfb_pdc &= 0x1f;
5140 ivideo->SiS_Pr.PDC = sisfb_pdc;
5141 }
5142#ifdef CONFIG_FB_SIS_315
5143 if(ivideo->sisvga_engine == SIS_315_VGA) {
5144 if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
5145 }
5146#endif
5147
5148 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
5149 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
5150 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
5151 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5152 pci_set_drvdata(pdev, NULL);
5153 kfree(sis_fb_info);
5154 return -ENODEV;
5155 }
5156
5157 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
5158 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
5159 release_mem_region(ivideo->video_base, ivideo->video_size);
5160 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5161 pci_set_drvdata(pdev, NULL);
5162 kfree(sis_fb_info);
5163 return -ENODEV;
5164 }
5165
5166 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
5167 ivideo->sishw_ext.pjVideoMemoryAddress = ivideo->video_vbase;
5168 if(!ivideo->video_vbase) {
5169 printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
5170 release_mem_region(ivideo->video_base, ivideo->video_size);
5171 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5172 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5173 pci_set_drvdata(pdev, NULL);
5174 kfree(sis_fb_info);
5175 return -ENODEV;
5176 }
5177
5178 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
5179 if(!ivideo->mmio_vbase) {
5180 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
5181 iounmap(ivideo->video_vbase);
5182 release_mem_region(ivideo->video_base, ivideo->video_size);
5183 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5184 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5185 pci_set_drvdata(pdev, NULL);
5186 kfree(sis_fb_info);
5187 return -ENODEV;
5188 }
5189
5190 printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n",
5191 ivideo->video_base, (ULONG)ivideo->video_vbase, ivideo->video_size / 1024);
5192
5193 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
5194 ivideo->mmio_base, (ULONG)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
5195
5196 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
5197 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
5198 }
5199
5200 /* Used for clearing the screen only, therefore respect our mem limit */
5201 ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
5202
5203 ivideo->mtrr = 0;
5204
5205 ivideo->vbflags = 0;
5206 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
5207 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
5208 ivideo->defmodeidx = DEFAULT_MODE;
5209
5210 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
5211
5212 if((ivideo->sisfb_mode_idx < 0) ||
5213 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5214
5215 sisfb_sense_crt1(ivideo);
5216
5217 sisfb_get_VB_type(ivideo);
5218
5219 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5220 sisfb_detect_VB_connect(ivideo);
5221 }
5222
5223 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
5224
5225 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5226 if(ivideo->sisfb_crt2type != -1) {
5227 if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
5228 ivideo->currentvbflags |= CRT2_LCD;
5229 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
5230 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
5231 }
5232 } else {
5233 /* Chrontel 700x TV detection often unreliable, therefore use a
5234 * different default order on such machines
5235 */
5236 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
5237 if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5238 else if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
5239 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5240 } else {
5241 if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
5242 else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5243 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5244 }
5245 }
5246 }
5247
5248 if(ivideo->vbflags & CRT2_LCD) {
5249 inSISIDXREG(SISCR, 0x36, reg);
5250 reg &= 0x0f;
5251 if(ivideo->sisvga_engine == SIS_300_VGA) {
5252 ivideo->CRT2LCDType = sis300paneltype[reg];
5253 } else if(ivideo->chip >= SIS_661) {
5254 ivideo->CRT2LCDType = sis661paneltype[reg];
5255 } else {
5256 ivideo->CRT2LCDType = sis310paneltype[reg];
5257 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
5258 if((ivideo->CRT2LCDType != LCD_640x480_2) &&
5259 (ivideo->CRT2LCDType != LCD_640x480_3)) {
5260 ivideo->CRT2LCDType = LCD_320x480;
5261 }
5262 }
5263 }
5264 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
5265 /* For broken BIOSes: Assume 1024x768, RGB18 */
5266 ivideo->CRT2LCDType = LCD_1024x768;
5267 setSISIDXREG(SISCR,0x36,0xf0,0x02);
5268 setSISIDXREG(SISCR,0x37,0xee,0x01);
5269 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
5270 }
5271 for(i = 0; i < SIS_LCD_NUMBER; i++) {
5272 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
5273 ivideo->lcdxres = sis_lcd_data[i].xres;
5274 ivideo->lcdyres = sis_lcd_data[i].yres;
5275 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
5276 break;
5277 }
5278 }
5279 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
5280 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
5281 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
5282 ivideo->lcdxres = 848; ivideo->lcdyres = 480; ivideo->lcddefmodeidx = 47;
5283 }
5284 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
5285 ivideo->lcdxres, ivideo->lcdyres);
5286 }
5287
5288#ifdef CONFIG_FB_SIS_300
5289 /* Save the current PanelDelayCompensation if the LCD is currently used */
5290 if(ivideo->sisvga_engine == SIS_300_VGA) {
5291 if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
5292 int tmp;
5293 inSISIDXREG(SISCR,0x30,tmp);
5294 if(tmp & 0x20) {
5295 /* Currently on LCD? If yes, read current pdc */
5296 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
5297 ivideo->detectedpdc &= 0x3c;
5298 if(ivideo->SiS_Pr.PDC == -1) {
5299 /* Let option override detection */
5300 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5301 }
5302 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
5303 ivideo->detectedpdc);
5304 }
5305 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5306 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
5307 ivideo->SiS_Pr.PDC);
5308 }
5309 }
5310 }
5311#endif
5312
5313#ifdef CONFIG_FB_SIS_315
5314 if(ivideo->sisvga_engine == SIS_315_VGA) {
5315
5316 /* Try to find about LCDA */
5317 if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
5318 int tmp;
5319 inSISIDXREG(SISPART1,0x13,tmp);
5320 if(tmp & 0x04) {
5321 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
5322 ivideo->detectedlcda = 0x03;
5323 }
5324 }
5325
5326 /* Save PDC */
5327 if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
5328 int tmp;
5329 inSISIDXREG(SISCR,0x30,tmp);
5330 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5331 /* Currently on LCD? If yes, read current pdc */
5332 u8 pdc;
5333 inSISIDXREG(SISPART1,0x2D,pdc);
5334 ivideo->detectedpdc = (pdc & 0x0f) << 1;
5335 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
5336 inSISIDXREG(SISPART1,0x35,pdc);
5337 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
5338 inSISIDXREG(SISPART1,0x20,pdc);
5339 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
5340 if(ivideo->newrom) {
5341 /* New ROM invalidates other PDC resp. */
5342 if(ivideo->detectedlcda != 0xff) {
5343 ivideo->detectedpdc = 0xff;
5344 } else {
5345 ivideo->detectedpdca = 0xff;
5346 }
5347 }
5348 if(ivideo->SiS_Pr.PDC == -1) {
5349 if(ivideo->detectedpdc != 0xff) {
5350 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5351 }
5352 }
5353 if(ivideo->SiS_Pr.PDCA == -1) {
5354 if(ivideo->detectedpdca != 0xff) {
5355 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
5356 }
5357 }
5358 if(ivideo->detectedpdc != 0xff) {
5359 printk(KERN_INFO
5360 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
5361 ivideo->detectedpdc);
5362 }
5363 if(ivideo->detectedpdca != 0xff) {
5364 printk(KERN_INFO
5365 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
5366 ivideo->detectedpdca);
5367 }
5368 }
5369
5370 /* Save EMI */
5371 if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
5372 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
5373 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
5374 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
5375 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
5376 ivideo->SiS_Pr.HaveEMI = TRUE;
5377 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5378 ivideo->SiS_Pr.HaveEMILCD = TRUE;
5379 }
5380 }
5381 }
5382
5383 /* Let user override detected PDCs (all bridges) */
5384 if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
5385 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5386 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
5387 ivideo->SiS_Pr.PDC);
5388 }
5389 if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
5390 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
5391 ivideo->SiS_Pr.PDCA);
5392 }
5393 }
5394
5395 }
5396#endif
5397
5398 if(!ivideo->sisfb_crt1off) {
5399 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
5400 } else {
5401 if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
5402 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
5403 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
5404 }
5405 }
5406
5407 if(ivideo->sisfb_mode_idx >= 0) {
5408 int bu = ivideo->sisfb_mode_idx;
5409 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
5410 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
5411 if(bu != ivideo->sisfb_mode_idx) {
5412 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
5413 sisbios_mode[bu].xres,
5414 sisbios_mode[bu].yres,
5415 sisbios_mode[bu].bpp);
5416 }
5417 }
5418
5419 if(ivideo->sisfb_mode_idx < 0) {
5420 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
5421 case CRT2_LCD:
5422 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
5423 break;
5424 case CRT2_TV:
5425 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
5426 break;
5427 default:
5428 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
5429 break;
5430 }
5431 }
5432
5433 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
5434
5435 if(ivideo->refresh_rate != 0) {
5436 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
5437 }
5438
5439 if(ivideo->rate_idx == 0) {
5440 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
5441 ivideo->refresh_rate = 60;
5442 }
5443
5444 if(ivideo->sisfb_thismonitor.datavalid) {
5445 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
5446 ivideo->rate_idx, ivideo->refresh_rate)) {
5447 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
5448 }
5449 }
5450
5451 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
5452 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
5453 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
5454
5455 sisfb_set_vparms(ivideo);
5456
5457#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5458
5459 /* ---------------- For 2.4: Now switch the mode ------------------ */
5460
5461 printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
5462 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5463 ivideo->refresh_rate);
5464
5465 sisfb_pre_setmode(ivideo);
5466
5467 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
5468 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
5469 ivideo->mode_no);
5470 iounmap(ivideo->video_vbase);
5471 iounmap(ivideo->mmio_vbase);
5472 release_mem_region(ivideo->video_base, ivideo->video_size);
5473 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5474 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5475 pci_set_drvdata(pdev, NULL);
5476 kfree(sis_fb_info);
5477 return -EINVAL;
5478 }
5479
5480 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
5481
5482 sisfb_post_setmode(ivideo);
5483
5484 /* Maximize regardless of sisfb_max at startup */
5485 ivideo->default_var.yres_virtual = 32767;
5486
5487 /* Force reset of x virtual in crtc_to_var */
5488 ivideo->default_var.xres_virtual = 0;
5489
5490 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
5491
5492 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5493 sisfb_set_pitch(ivideo);
5494
5495 ivideo->accel = 0;
5496 if(ivideo->sisfb_accel) {
5497 ivideo->accel = -1;
5498 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5499 }
5500 sisfb_initaccel(ivideo);
5501
5502 sis_fb_info->node = -1;
5503 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5504 sis_fb_info->fbops = &sisfb_ops;
5505 sis_fb_info->disp = &ivideo->sis_disp;
5506 sis_fb_info->blank = &sisfb_blank;
5507 sis_fb_info->switch_con = &sisfb_switch;
5508 sis_fb_info->updatevar = &sisfb_update_var;
5509 sis_fb_info->changevar = NULL;
5510 strcpy(sis_fb_info->fontname, sisfb_fontname);
5511
5512 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
5513
5514#else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
5515
5516 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
5517 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5518 ivideo->refresh_rate);
5519
5520 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
5521 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
5522 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
5523
5524 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
5525
5526 ivideo->default_var.pixclock = (u32) (1000000000 /
5527 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5528 ivideo->mode_no, ivideo->rate_idx));
5529
5530 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5531 ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
5532 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
5533 ivideo->default_var.pixclock <<= 1;
5534 }
5535 }
5536
5537 if(ivideo->sisfb_ypan) {
5538 /* Maximize regardless of sisfb_max at startup */
5539 ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var);
5540 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
5541 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
5542 }
5543 }
5544
5545 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5546
5547 ivideo->accel = 0;
5548 if(ivideo->sisfb_accel) {
5549 ivideo->accel = -1;
5550#ifdef STUPID_ACCELF_TEXT_SHIT
5551 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5552#endif
5553 }
5554 sisfb_initaccel(ivideo);
5555
5556#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
5557 sis_fb_info->flags = FBINFO_DEFAULT |
5558 FBINFO_HWACCEL_YPAN |
5559 FBINFO_HWACCEL_XPAN |
5560 FBINFO_HWACCEL_COPYAREA |
5561 FBINFO_HWACCEL_FILLRECT |
5562 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
5563#else
5564 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5565#endif
5566 sis_fb_info->var = ivideo->default_var;
5567 sis_fb_info->fix = ivideo->sisfb_fix;
5568 sis_fb_info->screen_base = ivideo->video_vbase;
5569 sis_fb_info->fbops = &sisfb_ops;
5570
5571 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
5572 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
5573
5574 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
5575#endif /* 2.6 */
5576
5577 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
5578
5579#ifdef CONFIG_MTRR
5580 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
5581 MTRR_TYPE_WRCOMB, 1);
5582 if(!ivideo->mtrr) {
5583 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
5584 }
5585#endif
5586
5587#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5588 vc_resize_con(1, 1, 0);
5589#endif
5590
5591 if(register_framebuffer(sis_fb_info) < 0) {
5592 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
5593 iounmap(ivideo->video_vbase);
5594 iounmap(ivideo->mmio_vbase);
5595 release_mem_region(ivideo->video_base, ivideo->video_size);
5596 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5597 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5598 pci_set_drvdata(pdev, NULL);
5599 kfree(sis_fb_info);
5600 return -EINVAL;
5601 }
5602
5603 ivideo->registered = 1;
5604
5605 /* Enlist us */
5606 ivideo->next = card_list;
5607 card_list = ivideo;
5608
5609 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
5610 ivideo->sisfb_accel ? "enabled" : "disabled",
5611 ivideo->sisfb_ypan ?
5612 (ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
5613
5614
5615 printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n",
5616#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5617 GET_FB_IDX(sis_fb_info->node),
5618#else
5619 sis_fb_info->node,
5620#endif
5621 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
5622
5623 printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
5624
5625 } /* if mode = "none" */
5626
5627 return 0;
5628}
5629
5630/*****************************************************/
5631/* PCI DEVICE HANDLING */
5632/*****************************************************/
5633
5634static void __devexit sisfb_remove(struct pci_dev *pdev)
5635{
5636 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5637 struct fb_info *sis_fb_info = ivideo->memyselfandi;
5638 int registered = ivideo->registered;
5639
5640 /* Unmap */
5641 iounmap(ivideo->video_vbase);
5642 iounmap(ivideo->mmio_vbase);
5643 vfree(ivideo->bios_abase);
5644
5645 /* Release mem regions */
5646 release_mem_region(ivideo->video_base, ivideo->video_size);
5647 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5648
5649#ifdef CONFIG_MTRR
5650 /* Release MTRR region */
5651 if(ivideo->mtrr) {
5652 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
5653 }
5654#endif
5655
5656 /* Unregister the framebuffer */
5657 if(ivideo->registered) {
5658 unregister_framebuffer(sis_fb_info);
5659#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5660 framebuffer_release(sis_fb_info);
5661#else
5662 kfree(sis_fb_info);
5663#endif
5664 }
5665
5666 pci_set_drvdata(pdev, NULL);
5667
5668 /* TODO: Restore the initial mode
5669 * This sounds easy but is as good as impossible
5670 * on many machines with SiS chip and video bridge
5671 * since text modes are always set up differently
5672 * from machine to machine. Depends on the type
5673 * of integration between chipset and bridge.
5674 */
5675 if(registered) {
5676 printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
5677 }
5678};
5679
5680static struct pci_driver sisfb_driver = {
5681 .name = "sisfb",
5682 .id_table = sisfb_pci_table,
5683 .probe = sisfb_probe,
5684 .remove = __devexit_p(sisfb_remove)
5685};
5686
5687SISINITSTATIC int __init sisfb_init(void)
5688{
5689#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5690#ifndef MODULE
5691 char *options = NULL;
5692
5693 if(fb_get_options("sisfb", &options))
5694 return -ENODEV;
5695 sisfb_setup(options);
5696#endif
5697#endif
5698 return(pci_register_driver(&sisfb_driver));
5699}
5700
5701#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5702#ifndef MODULE
5703module_init(sisfb_init);
5704#endif
5705#endif
5706
5707/*****************************************************/
5708/* MODULE */
5709/*****************************************************/
5710
5711#ifdef MODULE
5712
5713static char *mode = NULL;
5714static int vesa = -1;
5715static unsigned int rate = 0;
5716static unsigned int crt1off = 1;
5717static unsigned int mem = 0;
5718static char *forcecrt2type = NULL;
5719static int forcecrt1 = -1;
5720static int pdc = -1;
5721static int pdc1 = -1;
5722static int noaccel = -1;
5723static int noypan = -1;
5724static int nomax = -1;
5725#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5726static int inverse = 0;
5727#endif
5728static int userom = -1;
5729static int useoem = -1;
5730static char *tvstandard = NULL;
5731static int nocrt2rate = 0;
5732static int scalelcd = -1;
5733static char *specialtiming = NULL;
5734static int lvdshl = -1;
5735static int tvxposoffset = 0, tvyposoffset = 0;
5736static int filter = -1;
5737#if !defined(__i386__) && !defined(__x86_64__)
5738static int resetcard = 0;
5739static int videoram = 0;
5740#endif
5741
5742MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
5743MODULE_LICENSE("GPL");
5744MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
5745
5746#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5747MODULE_PARM(mem, "i");
5748MODULE_PARM(noaccel, "i");
5749MODULE_PARM(noypan, "i");
5750MODULE_PARM(nomax, "i");
5751MODULE_PARM(userom, "i");
5752MODULE_PARM(useoem, "i");
5753MODULE_PARM(mode, "s");
5754MODULE_PARM(vesa, "i");
5755MODULE_PARM(rate, "i");
5756MODULE_PARM(forcecrt1, "i");
5757MODULE_PARM(forcecrt2type, "s");
5758MODULE_PARM(scalelcd, "i");
5759MODULE_PARM(pdc, "i");
5760MODULE_PARM(pdc1, "i");
5761MODULE_PARM(specialtiming, "s");
5762MODULE_PARM(lvdshl, "i");
5763MODULE_PARM(tvstandard, "s");
5764MODULE_PARM(tvxposoffset, "i");
5765MODULE_PARM(tvyposoffset, "i");
5766MODULE_PARM(filter, "i");
5767MODULE_PARM(nocrt2rate, "i");
5768MODULE_PARM(inverse, "i");
5769#if !defined(__i386__) && !defined(__x86_64__)
5770MODULE_PARM(resetcard, "i");
5771MODULE_PARM(videoram, "i");
5772#endif
5773#endif
5774
5775#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5776module_param(mem, int, 0);
5777module_param(noaccel, int, 0);
5778module_param(noypan, int, 0);
5779module_param(nomax, int, 0);
5780module_param(userom, int, 0);
5781module_param(useoem, int, 0);
5782module_param(mode, charp, 0);
5783module_param(vesa, int, 0);
5784module_param(rate, int, 0);
5785module_param(forcecrt1, int, 0);
5786module_param(forcecrt2type, charp, 0);
5787module_param(scalelcd, int, 0);
5788module_param(pdc, int, 0);
5789module_param(pdc1, int, 0);
5790module_param(specialtiming, charp, 0);
5791module_param(lvdshl, int, 0);
5792module_param(tvstandard, charp, 0);
5793module_param(tvxposoffset, int, 0);
5794module_param(tvyposoffset, int, 0);
5795module_param(filter, int, 0);
5796module_param(nocrt2rate, int, 0);
5797#if !defined(__i386__) && !defined(__x86_64__)
5798module_param(resetcard, int, 0);
5799module_param(videoram, int, 0);
5800#endif
5801#endif
5802
5803MODULE_PARM_DESC(mem,
5804 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
5805 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
5806 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
5807 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
5808 "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
5809 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
5810 "for XFree86 4.x/X.org 6.7 and later.\n");
5811
5812MODULE_PARM_DESC(noaccel,
5813 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
5814 "(default: 0)\n");
5815
5816MODULE_PARM_DESC(noypan,
5817 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
5818 "will be performed by redrawing the screen. (default: 0)\n");
5819
5820MODULE_PARM_DESC(nomax,
5821 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
5822 "memory for the virtual screen in order to optimize scrolling performance. If\n"
5823 "this is set to anything other than 0, sisfb will not do this and thereby \n"
5824 "enable the user to positively specify a virtual Y size of the screen using\n"
5825 "fbset. (default: 0)\n");
5826
5827#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5828MODULE_PARM_DESC(mode,
5829 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
5830 "1024x768x16. Other formats supported include XxY-Depth and\n"
5831 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5832 "number, it will be interpreted as a VESA mode number. (default: none if\n"
5833 "sisfb is a module; this leaves the console untouched and the driver will\n"
5834 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
5835 "is in the kernel)\n");
5836MODULE_PARM_DESC(vesa,
5837 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
5838 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
5839 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
5840 "0x0103 if sisfb is in the kernel)\n");
5841#endif
5842
5843#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5844MODULE_PARM_DESC(mode,
5845 "\nSelects the desired default display mode in the format XxYxDepth,\n"
5846 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
5847 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5848 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
5849
5850MODULE_PARM_DESC(vesa,
5851 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
5852 "0x117 (default: 0x0103)\n");
5853#endif
5854
5855MODULE_PARM_DESC(rate,
5856 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
5857 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
5858 "will be ignored (default: 60)\n");
5859
5860MODULE_PARM_DESC(forcecrt1,
5861 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
5862 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
5863 "0=CRT1 OFF) (default: [autodetected])\n");
5864
5865MODULE_PARM_DESC(forcecrt2type,
5866 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
5867 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
5868 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
5869 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
5870 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
5871 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
5872 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
5873 "depends on the very hardware in use. (default: [autodetected])\n");
5874
5875MODULE_PARM_DESC(scalelcd,
5876 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
5877 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
5878 "show black bars around the image, TMDS panels will probably do the scaling\n"
5879 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
5880
5881MODULE_PARM_DESC(pdc,
5882 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
5883 "should detect this correctly in most cases; however, sometimes this is not\n"
5884 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
5885 "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
5886 "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
5887 "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
5888
5889#ifdef CONFIG_FB_SIS_315
5890MODULE_PARM_DESC(pdc1,
5891 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
5892 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
5893 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
5894 "implemented yet.\n");
5895#endif
5896
5897MODULE_PARM_DESC(specialtiming,
5898 "\nPlease refer to documentation for more information on this option.\n");
5899
5900MODULE_PARM_DESC(lvdshl,
5901 "\nPlease refer to documentation for more information on this option.\n");
5902
5903MODULE_PARM_DESC(tvstandard,
5904 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
5905 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
5906
5907MODULE_PARM_DESC(tvxposoffset,
5908 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
5909 "Default: 0\n");
5910
5911MODULE_PARM_DESC(tvyposoffset,
5912 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
5913 "Default: 0\n");
5914
5915MODULE_PARM_DESC(filter,
5916 "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
5917 "(Possible values 0-7, default: [no filter])\n");
5918
5919MODULE_PARM_DESC(nocrt2rate,
5920 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
5921 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
5922
5923#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5924MODULE_PARM_DESC(inverse,
5925 "\nSetting this to anything but 0 should invert the display colors, but this\n"
5926 "does not seem to work. (default: 0)\n");
5927#endif
5928
5929#if !defined(__i386__) && !defined(__x86_64__)
5930#ifdef CONFIG_FB_SIS_300
5931MODULE_PARM_DESC(resetcard,
5932 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
5933 "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
5934 "Default: 0\n");
5935
5936MODULE_PARM_DESC(videoram,
5937 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
5938 "some non-x86 architectures where the memory auto detection fails. Only\n"
5939 "relevant if resetcard is set, too. Default: [auto-detect]\n");
5940#endif
5941#endif
5942
5943int __devinit sisfb_init_module(void)
5944{
5945 sisfb_setdefaultparms();
5946
5947 if(rate) sisfb_parm_rate = rate;
5948
5949 if((scalelcd == 0) || (scalelcd == 1)) {
5950 sisfb_scalelcd = scalelcd ^ 1;
5951 }
5952
5953 /* Need to check crt2 type first for fstn/dstn */
5954
5955 if(forcecrt2type)
5956 sisfb_search_crt2type(forcecrt2type);
5957
5958 if(tvstandard)
5959 sisfb_search_tvstd(tvstandard);
5960
5961 if(mode)
5962 sisfb_search_mode(mode, FALSE);
5963 else if(vesa != -1)
5964 sisfb_search_vesamode(vesa, FALSE);
5965
5966 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
5967
5968 sisfb_forcecrt1 = forcecrt1;
5969 if(forcecrt1 == 1) sisfb_crt1off = 0;
5970 else if(forcecrt1 == 0) sisfb_crt1off = 1;
5971
5972 if(noaccel == 1) sisfb_accel = 0;
5973 else if(noaccel == 0) sisfb_accel = 1;
5974
5975 if(noypan == 1) sisfb_ypan = 0;
5976 else if(noypan == 0) sisfb_ypan = 1;
5977
5978 if(nomax == 1) sisfb_max = 0;
5979 else if(nomax == 0) sisfb_max = 1;
5980
5981#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5982 if(inverse) sisfb_inverse = 1;
5983#endif
5984
5985 if(mem) sisfb_parm_mem = mem;
5986
5987 if(userom != -1) sisfb_userom = userom;
5988 if(useoem != -1) sisfb_useoem = useoem;
5989
5990 if(pdc != -1) sisfb_pdc = (pdc & 0x7f);
5991 if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
5992
5993 sisfb_nocrt2rate = nocrt2rate;
5994
5995 if(specialtiming)
5996 sisfb_search_specialtiming(specialtiming);
5997
5998 if((lvdshl >= 0) && (lvdshl <= 3)) sisfb_lvdshl = lvdshl;
5999
6000 if(filter != -1) sisfb_filter = filter;
6001
6002 sisfb_tvxposoffset = tvxposoffset;
6003 sisfb_tvyposoffset = tvyposoffset;
6004
6005#if !defined(__i386__) && !defined(__x86_64__)
6006 sisfb_resetcard = (resetcard) ? 1 : 0;
6007 if(videoram) sisfb_videoram = videoram;
6008#endif
6009
6010 return(sisfb_init());
6011}
6012
6013static void __exit sisfb_remove_module(void)
6014{
6015 pci_unregister_driver(&sisfb_driver);
6016 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6017}
6018
6019module_init(sisfb_init_module);
6020module_exit(sisfb_remove_module);
6021
6022#endif /* /MODULE */
6023
6024EXPORT_SYMBOL(sis_malloc);
6025EXPORT_SYMBOL(sis_free);
6026
6027