[PATCH] W1: w1_netlink: New init/fini netlink callbacks.
[linux-2.6/verdex.git] / drivers / video / sis / sis_main.c
blob6982660368193735cc2034c9f68dee1627b028b5
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
6 * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
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.
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.
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
22 * Author: Thomas Winischhofer <thomas@winischhofer.net>
24 * Author of (practically wiped) code base:
25 * SiS (www.sis.com)
26 * Copyright (C) 1999 Silicon Integrated Systems, Inc.
28 * See http://www.winischhofer.net/ for more information and updates
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>
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
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
76 #include "sis.h"
77 #include "sis_main.h"
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
85 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
86 #ifdef FBCON_HAS_CFB8
87 extern struct display_switch fbcon_sis8;
88 #endif
89 #ifdef FBCON_HAS_CFB16
90 extern struct display_switch fbcon_sis16;
91 #endif
92 #ifdef FBCON_HAS_CFB32
93 extern struct display_switch fbcon_sis32;
94 #endif
95 #endif
97 /* ------------------ Internal helper routines ----------------- */
99 static void __init
100 sisfb_setdefaultparms(void)
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
148 static void __devinit
149 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
151 int i = 0, j = 0;
153 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
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");
162 sisfb_mode_idx = DEFAULT_MODE;
163 #endif
164 return;
167 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
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;
180 sisfb_mode_idx = i - 1;
181 j = 1;
182 break;
185 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
188 static void
189 sisfb_search_mode(char *name, BOOLEAN quiet)
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;
196 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
198 if(name == NULL) {
199 if(!quiet) {
200 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
202 sisfb_mode_idx = DEFAULT_MODE;
203 return;
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");
211 sisfb_mode_idx = DEFAULT_MODE;
212 return;
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] = ' ';
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;
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;
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;
255 sisfb_mode_idx = i - 1;
256 j = 1;
257 break;
260 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
263 #ifndef MODULE
264 static void __devinit
265 sisfb_get_vga_mode_from_kernel(void)
267 #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
268 char mymode[32];
269 int mydepth = screen_info.lfb_depth;
271 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
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) ) {
277 if(mydepth == 24) mydepth = 32;
279 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
280 screen_info.lfb_height,
281 mydepth);
283 printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode);
285 sisfb_search_mode(mymode, TRUE);
287 #endif
288 return;
290 #endif
292 static void __init
293 sisfb_search_crt2type(const char *name)
295 int i = 0;
297 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
299 if(name == NULL) return;
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;
308 i++;
311 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
312 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
314 if(sisfb_crt2type < 0) {
315 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
319 static void __init
320 sisfb_search_tvstd(const char *name)
322 int i = 0;
324 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
326 if(name == NULL) return;
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;
333 i++;
337 static void __init
338 sisfb_search_specialtiming(const char *name)
340 int i = 0;
341 BOOLEAN found = FALSE;
343 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
345 if(name == NULL) return;
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;
360 i++;
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++;
377 static BOOLEAN __devinit
378 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
380 int i, j, xres, yres, refresh, index;
381 u32 emodes;
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;
391 if(buffer[0x12] != 0x01) {
392 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
393 buffer[0x12]);
394 return FALSE;
397 monitor->feature = buffer[0x18];
399 if(!buffer[0x14] & 0x80) {
400 if(!(buffer[0x14] & 0x08)) {
401 printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n");
405 if(buffer[0x13] >= 0x01) {
406 /* EDID V1 rev 1 and 2: Search for monitor descriptor
407 * to extract ranges
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;
422 j += 18;
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.
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;
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;
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;
468 index += 2;
470 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
471 monitor->datavalid = TRUE;
475 return(monitor->datavalid);
478 static void __devinit
479 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
481 USHORT temp, i, realcrtno = crtno;
482 u8 buffer[256];
484 monitor->datavalid = FALSE;
486 if(crtno) {
487 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
488 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
489 else return;
492 if((ivideo->sisfb_crt1off) && (!crtno)) return;
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);
521 } else {
522 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
524 } else {
525 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
530 static BOOLEAN
531 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
532 int mode_idx, int rate_idx, int rate)
534 int htotal, vtotal;
535 unsigned int dclock, hsync;
537 if(!monitor->datavalid) return TRUE;
539 if(mode_idx < 0) return FALSE;
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
560 if(rate < (monitor->vmin - 1)) return FALSE;
561 if(rate > (monitor->vmax + 1)) return FALSE;
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;
574 return TRUE;
577 static int
578 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
580 u16 xres=0, yres, myres;
582 #ifdef CONFIG_FB_SIS_300
583 if(ivideo->sisvga_engine == SIS_300_VGA) {
584 if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1);
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);
591 #endif
593 myres = sisbios_mode[myindex].yres;
595 switch(vbflags & VB_DISPTYPE_DISP2) {
597 case CRT2_LCD:
599 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
601 if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) {
602 if(sisbios_mode[myindex].xres > xres) return(-1);
603 if(myres > yres) return(-1);
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);
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);
628 break;
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);
635 break;
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);
642 break;
645 return(myindex);
648 static u8
649 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
651 u16 xres, yres;
652 int i = 0;
654 xres = sisbios_mode[mode_idx].xres;
655 yres = sisbios_mode[mode_idx].yres;
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;
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;
684 i++;
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;
695 static BOOLEAN
696 sisfb_bridgeisslave(struct sis_video_info *ivideo)
698 unsigned char P1_00;
700 if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE;
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;
711 static BOOLEAN
712 sisfballowretracecrt1(struct sis_video_info *ivideo)
714 u8 temp;
716 inSISIDXREG(SISCR,0x17,temp);
717 if(!(temp & 0x80)) return FALSE;
719 inSISIDXREG(SISSR,0x1f,temp);
720 if(temp & 0xc0) return FALSE;
722 return TRUE;
725 static BOOLEAN
726 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
728 if(!sisfballowretracecrt1(ivideo)) return FALSE;
730 if(inSISREG(SISINPSTAT) & 0x08) return TRUE;
731 else return FALSE;
734 static void
735 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
737 int watchdog;
739 if(!sisfballowretracecrt1(ivideo)) return;
741 watchdog = 65536;
742 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
743 watchdog = 65536;
744 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
747 static BOOLEAN
748 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
750 unsigned char temp, reg;
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;
758 inSISIDXREG(SISPART1, reg, temp);
759 if(temp & 0x02) return TRUE;
760 else return FALSE;
763 static BOOLEAN
764 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
766 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
767 if(sisfb_bridgeisslave(ivideo)) {
768 return(sisfbcheckvretracecrt1(ivideo));
769 } else {
770 return(sisfbcheckvretracecrt2(ivideo));
773 return(sisfbcheckvretracecrt1(ivideo));
776 static u32
777 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
779 u8 idx, reg1, reg2, reg3, reg4;
780 u32 ret = 0;
782 (*vcount) = (*hcount) = 0;
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;
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;
819 return ret;
822 static int
823 sisfb_myblank(struct sis_video_info *ivideo, int blank)
825 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
826 BOOLEAN backlight = TRUE;
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;
878 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
880 if( (!ivideo->sisfb_thismonitor.datavalid) ||
881 ((ivideo->sisfb_thismonitor.datavalid) &&
882 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
884 if(ivideo->sisvga_engine == SIS_315_VGA) {
885 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
888 if(!(sisfb_bridgeisslave(ivideo))) {
889 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
890 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
896 if(ivideo->currentvbflags & CRT2_LCD) {
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);
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);
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);
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);
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);
933 } else if(ivideo->currentvbflags & CRT2_VGA) {
935 if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) {
936 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
941 return(0);
944 /* ----------- FBDev related routines for all series ----------- */
946 static int
947 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
949 return (var->bits_per_pixel == 8) ? 256 : 16;
952 static void
953 sisfb_set_vparms(struct sis_video_info *ivideo)
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;
979 static int
980 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
982 int maxyres = ivideo->heapstart / (var->xres_virtual * (var->bits_per_pixel >> 3));
984 if(maxyres > 32767) maxyres = 32767;
986 return maxyres;
989 static void
990 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
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;
1002 static void
1003 sisfb_set_pitch(struct sis_video_info *ivideo)
1005 BOOLEAN isslavemode = FALSE;
1006 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1007 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1009 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
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));
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));
1025 static void
1026 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1028 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
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;
1058 static int
1059 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
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;
1068 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1070 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1072 pixclock = var->pixclock;
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;
1085 if(!(htotal) || !(vtotal)) {
1086 DPRINTK("sisfb: Invalid 'var' information\n");
1087 return -EINVAL;
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;
1098 old_mode = ivideo->sisfb_mode_idx;
1099 ivideo->sisfb_mode_idx = 0;
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;
1110 ivideo->sisfb_mode_idx++;
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;
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;
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;
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");
1139 #endif
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);
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;
1153 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1155 sisfb_post_setmode(ivideo);
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;
1161 sisfb_calc_pitch(ivideo, var);
1162 sisfb_set_pitch(ivideo);
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;
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
1178 sisfb_set_vparms(ivideo);
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
1193 return 0;
1196 static int
1197 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1199 unsigned int base;
1201 if(var->xoffset > (var->xres_virtual - var->xres)) {
1202 return -EINVAL;
1204 if(var->yoffset > (var->yres_virtual - var->yres)) {
1205 return -EINVAL;
1208 base = (var->yoffset * var->xres_virtual) + var->xoffset;
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;
1223 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
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);
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);
1240 return 0;
1243 /* ------------ FBDev related routines for 2.4 series ----------- */
1245 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1247 static void
1248 sisfb_crtc_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
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;
1256 inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
1258 if(sr_data & SIS_INTERLACED_MODE)
1259 var->vmode = FB_VMODE_INTERLACED;
1260 else
1261 var->vmode = FB_VMODE_NONINTERLACED;
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;
1275 sisfb_bpp_to_var(ivideo, var);
1277 inSISIDXREG(SISSR, 0x0A, sr_data);
1278 inSISIDXREG(SISCR, 0x06, cr_data);
1279 inSISIDXREG(SISCR, 0x07, cr_data2);
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;
1287 inSISIDXREG(SISCR, 0x12, cr_data);
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;
1295 inSISIDXREG(SISCR, 0x10, cr_data);
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;
1303 inSISIDXREG(SISCR, 0x15, cr_data);
1304 inSISIDXREG(SISCR, 0x09, cr_data3);
1306 if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE;
1308 VBS = (cr_data & 0xff) |
1309 ((u16) (cr_data2 & 0x08) << 5) |
1310 ((u16) (cr_data3 & 0x20) << 4) |
1311 ((u16) (sr_data & 0x04) << 8);
1313 inSISIDXREG(SISCR, 0x16, cr_data);
1315 VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
1316 temp = VBE - ((E - 1) & 511);
1317 B = (temp > 0) ? temp : (temp + 512);
1319 inSISIDXREG(SISCR, 0x11, cr_data);
1321 VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
1322 temp = VRE - ((E + F - 1) & 31);
1323 C = (temp > 0) ? temp : (temp + 32);
1325 D = B - F - C;
1327 var->yres = E;
1328 var->upper_margin = D;
1329 var->lower_margin = F;
1330 var->vsync_len = C;
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;
1344 inSISIDXREG(SISSR, 0x0b, sr_data);
1345 inSISIDXREG(SISCR, 0x00, cr_data);
1347 HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
1348 A = HT + 5;
1350 inSISIDXREG(SISCR, 0x01, cr_data);
1352 HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
1353 E = HDE + 1;
1355 inSISIDXREG(SISCR, 0x04, cr_data);
1357 HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
1358 F = HRS - E - 3;
1360 inSISIDXREG(SISCR, 0x02, cr_data);
1362 HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
1364 inSISIDXREG(SISSR, 0x0c, sr_data);
1365 inSISIDXREG(SISCR, 0x03, cr_data);
1366 inSISIDXREG(SISCR, 0x05, cr_data2);
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);
1373 temp = HBE - ((E - 1) & 255);
1374 B = (temp > 0) ? temp : (temp + 256);
1376 temp = HRE - ((E + F + 3) & 63);
1377 C = (temp > 0) ? temp : (temp + 64);
1379 D = B - F - C;
1381 var->xres = E * 8;
1382 if(var->xres_virtual < var->xres) {
1383 var->xres_virtual = var->xres;
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...
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;
1399 var->activate = FB_ACTIVATE_NOW;
1401 var->sync = 0;
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;
1409 if(mr_data & 0x40)
1410 var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
1411 else
1412 var->sync |= FB_SYNC_HOR_HIGH_ACT;
1414 VT += 2;
1415 VT <<= 1;
1416 HT = (HT + 5) * 8;
1418 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1419 VT <<= 1;
1421 hrate = ivideo->refresh_rate * VT / 2;
1422 drate = (hrate * HT) / 1000;
1423 var->pixclock = (u32) (1000000000 / drate);
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;
1434 if(var->yres_virtual <= var->yres) {
1435 var->yres_virtual = var->yres;
1437 } else {
1438 var->yres_virtual = var->yres;
1443 static int
1444 sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
1445 unsigned *transp, struct fb_info *info)
1447 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1449 if(regno >= ivideo->video_cmap_len) return 1;
1451 *red = ivideo->sis_palette[regno].red;
1452 *green = ivideo->sis_palette[regno].green;
1453 *blue = ivideo->sis_palette[regno].blue;
1454 *transp = 0;
1456 return 0;
1459 static int
1460 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1461 unsigned transp, struct fb_info *info)
1463 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1465 if(regno >= ivideo->video_cmap_len) return 1;
1467 ivideo->sis_palette[regno].red = red;
1468 ivideo->sis_palette[regno].green = green;
1469 ivideo->sis_palette[regno].blue = blue;
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));
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
1502 return 0;
1505 static void
1506 sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info)
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;
1514 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1516 sisfb_get_fix(&fix, con, info);
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;
1530 save_flags(flags);
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;
1550 memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw));
1551 display->dispsw = &ivideo->sisfb_sw;
1553 restore_flags(flags);
1555 if(ivideo->sisfb_ypan) {
1556 /* display->scrollmode = 0; */
1557 } else {
1558 display->scrollmode = SCROLL_YREDRAW;
1559 ivideo->sisfb_sw.bmove = fbcon_redraw_bmove;
1563 static void
1564 sisfb_do_install_cmap(int con, struct fb_info *info)
1566 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1568 if(con != ivideo->currcon) return;
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);
1578 static int
1579 sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1581 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1583 if(con == -1) {
1584 memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo));
1585 } else {
1586 *var = fb_display[con].var;
1589 if(ivideo->sisfb_fstn) {
1590 if(var->xres == 320 && var->yres == 480) var->yres = 240;
1593 return 0;
1596 static int
1597 sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1599 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1600 int err;
1602 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1604 if(sisfb_do_set_var(var, con == ivideo->currcon, info)) {
1605 sisfb_crtc_to_var(ivideo, var);
1606 return -EINVAL;
1609 sisfb_crtc_to_var(ivideo, var);
1611 sisfb_set_disp(con, var, info);
1613 if(info->changevar) {
1614 (*info->changevar)(con);
1617 if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) {
1618 return err;
1621 sisfb_do_install_cmap(con, info);
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;
1632 static int
1633 sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1635 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1636 struct display *display;
1638 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1640 if(con == ivideo->currcon) {
1642 return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
1644 } else if(display->cmap.len) {
1646 fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2);
1648 } else {
1650 int size = sisfb_get_cmap_len(&display->var);
1651 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
1655 return 0;
1658 static int
1659 sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1661 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1662 struct display *display;
1663 int err, size;
1665 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
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;
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);
1679 return 0;
1682 static int
1683 sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info)
1685 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1686 int err;
1688 if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
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;
1695 if(con == ivideo->currcon) {
1696 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
1699 fb_display[con].var.xoffset = var->xoffset;
1700 fb_display[con].var.yoffset = var->yoffset;
1702 return 0;
1705 static int
1706 sisfb_update_var(int con, struct fb_info *info)
1708 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1710 return(sisfb_pan_var(ivideo, &fb_display[con].var));
1713 static int
1714 sisfb_switch(int con, struct fb_info *info)
1716 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1717 int cols, rows;
1719 if(fb_display[ivideo->currcon].cmap.len) {
1720 fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info);
1723 fb_display[con].var.activate = FB_ACTIVATE_NOW;
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;
1731 ivideo->currcon = con;
1733 sisfb_do_set_var(&fb_display[con].var, 1, info);
1735 sisfb_set_disp(con, &fb_display[con].var, info);
1737 sisfb_do_install_cmap(con, info);
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);
1743 sisfb_update_var(con, info);
1745 return 1;
1748 static void
1749 sisfb_blank(int blank, struct fb_info *info)
1751 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1753 sisfb_myblank(ivideo, blank);
1755 #endif
1757 /* ------------ FBDev related routines for 2.6 series ----------- */
1759 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1761 static int
1762 sisfb_open(struct fb_info *info, int user)
1764 return 0;
1767 static int
1768 sisfb_release(struct fb_info *info, int user)
1770 return 0;
1773 static int
1774 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1775 unsigned transp, struct fb_info *info)
1777 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1779 if(regno >= sisfb_get_cmap_len(&info->var)) return 1;
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));
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;
1806 return 0;
1809 static int
1810 sisfb_set_par(struct fb_info *info)
1812 int err;
1814 if((err = sisfb_do_set_var(&info->var, 1, info))) {
1815 return err;
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;
1825 static int
1826 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
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;
1836 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1838 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1840 pixclock = var->pixclock;
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;
1853 if(!(htotal) || !(vtotal)) {
1854 SISFAIL("sisfb: no valid timing data");
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;
1868 search_idx++;
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;
1882 search_idx++;
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;
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;
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;
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;
1936 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
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;
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");
1959 /* Adapt RGB settings */
1960 sisfb_bpp_to_var(ivideo, var);
1962 /* Sanity check for offsets */
1963 if(var->xoffset < 0) var->xoffset = 0;
1964 if(var->yoffset < 0) var->yoffset = 0;
1966 if(var->xres > var->xres_virtual) {
1967 var->xres_virtual = var->xres;
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;
1979 if(var->yres_virtual <= var->yres) {
1980 var->yres_virtual = var->yres;
1982 } else {
1983 if(var->yres != var->yres_virtual) {
1984 var->yres_virtual = var->yres;
1986 var->xoffset = 0;
1987 var->yoffset = 0;
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;
1995 if(var->yoffset > var->yres_virtual - var->yres) {
1996 var->yoffset = var->yres_virtual - var->yres - 1;
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;
2007 return 0;
2010 static int
2011 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
2013 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2014 int err;
2016 if(var->xoffset > (var->xres_virtual - var->xres)) {
2017 return -EINVAL;
2019 if(var->yoffset > (var->yres_virtual - var->yres)) {
2020 return -EINVAL;
2023 if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
2025 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
2026 var->yoffset + info->var.yres > info->var.yres_virtual) {
2027 return -EINVAL;
2030 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
2032 info->var.xoffset = var->xoffset;
2033 info->var.yoffset = var->yoffset;
2035 return 0;
2038 static int
2039 sisfb_blank(int blank, struct fb_info *info)
2041 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2043 return(sisfb_myblank(ivideo, blank));
2046 #endif
2048 /* ----------- FBDev related routines for all series ---------- */
2050 static int
2051 sisfb_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)
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;
2068 switch (cmd) {
2069 case FBIO_ALLOC:
2070 if(!capable(CAP_SYS_RAWIO)) {
2071 return -EPERM;
2073 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq))) {
2074 return -EFAULT;
2076 sis_malloc(&sismemreq);
2077 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
2078 sis_free((u32)sismemreq.offset);
2079 return -EFAULT;
2081 break;
2083 case FBIO_FREE:
2084 if(!capable(CAP_SYS_RAWIO)) {
2085 return -EPERM;
2087 if(get_user(gpu32, argp)) {
2088 return -EFAULT;
2090 sis_free(gpu32);
2091 break;
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;
2099 break;
2101 case SISFB_GET_INFO_SIZE:
2102 return put_user(sizeof(sisfb_info), argp);
2104 case SISFB_GET_INFO_OLD:
2105 if(ivideo->warncount++ < 50) {
2106 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
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;
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);
2142 if(copy_to_user((void __user *)arg, &x, sizeof(x))) {
2143 return -EFAULT;
2145 break;
2147 case SISFB_GET_VBRSTATUS_OLD:
2148 if(ivideo->warncount++ < 50) {
2149 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
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);
2158 case SISFB_GET_AUTOMAXIMIZE_OLD:
2159 if(ivideo->warncount++ < 50) {
2160 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2162 case SISFB_GET_AUTOMAXIMIZE:
2163 if(ivideo->sisfb_max) return put_user((u32)1, argp);
2164 else return put_user((u32)0, argp);
2166 case SISFB_SET_AUTOMAXIMIZE_OLD:
2167 if(ivideo->warncount++ < 50) {
2168 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2170 case SISFB_SET_AUTOMAXIMIZE:
2171 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2172 return -EFAULT;
2174 ivideo->sisfb_max = (gpu32) ? 1 : 0;
2175 break;
2177 case SISFB_SET_TVPOSOFFSET:
2178 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2179 return -EFAULT;
2181 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
2182 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
2183 break;
2185 case SISFB_GET_TVPOSOFFSET:
2186 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
2187 argp);
2189 case SISFB_SET_LOCK:
2190 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2191 return -EFAULT;
2193 ivideo->sisfblocked = (gpu32) ? 1 : 0;
2194 break;
2196 default:
2197 return -ENOIOCTLCMD;
2199 return 0;
2202 #ifdef CONFIG_COMPAT
2203 static long sisfb_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg, struct fb_info *info)
2205 int ret;
2206 lock_kernel();
2207 ret = sisfb_ioctl(NULL, f, cmd, arg, info);
2208 unlock_kernel();
2209 return ret;
2211 #endif
2213 static int
2214 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
2216 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2218 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2220 strcpy(fix->id, ivideo->myid);
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;
2241 return 0;
2244 /* ---------------- fb_ops structures ----------------- */
2246 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2247 static 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
2257 #endif
2259 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
2260 static 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
2279 #endif
2281 /* ---------------- Chip generation dependent routines ---------------- */
2283 static struct pci_dev * sisfb_get_northbridge(int basechipid)
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
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;
2313 for(i = 0; i < nbridgenum; i++) {
2314 if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break;
2316 return pdev;
2319 static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
2321 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2322 u8 reg;
2323 #endif
2325 ivideo->video_size = 0;
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);
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);
2383 break;
2384 #endif
2385 default:
2386 return -1;
2388 return 0;
2391 /* -------------- video bridge device detection --------------- */
2393 static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2395 u8 cr32, temp;
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;
2411 #endif
2413 inSISIDXREG(SISCR, 0x32, cr32);
2415 if(cr32 & SIS_CRT1) {
2416 ivideo->sisfb_crt1off = 0;
2417 } else {
2418 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2421 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
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;
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)
2432 if(ivideo->chip != SIS_550) {
2433 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
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");
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");
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");
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;
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;
2482 if(ivideo->vbflags & TV_SCART) {
2483 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2484 ivideo->vbflags |= TV_PAL;
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;
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;
2509 static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo)
2511 char stdstr[] = "sisfb: Detected";
2512 char bridgestr[] = "video bridge";
2513 u8 vb_chipid;
2514 u8 reg;
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);
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
2552 break;
2553 case 0x02:
2554 ivideo->vbflags |= VB_302B;
2555 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2556 break;
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;
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;
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;
2608 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2609 #endif
2611 if(ivideo->vbflags & VB_LVDS) {
2612 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2614 if(ivideo->vbflags & VB_TRUMPION) {
2615 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2617 if(ivideo->vbflags & VB_CHRONTEL) {
2618 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2620 if(ivideo->vbflags & VB_CONEXANT) {
2621 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2625 if(ivideo->vbflags & VB_SISBRIDGE) {
2626 SiS_Sense30x(ivideo);
2627 } else if(ivideo->vbflags & VB_CHRONTEL) {
2628 SiS_SenseCh(ivideo);
2632 /* ------------------ Sensing routines ------------------ */
2634 static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo)
2636 unsigned short old;
2637 int count = 48;
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;
2646 static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
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;
2656 inSISIDXREG(SISSR,0x1F,sr1F);
2657 orSISIDXREG(SISSR,0x1F,0x04);
2658 andSISIDXREG(SISSR,0x1F,0x3F);
2659 if(sr1F & 0xc0) mustwait = TRUE;
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);
2667 #endif
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);
2678 if(mustwait) {
2679 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
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);
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);
2697 #endif
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--);
2705 if((temp == 0) || (temp == 0xffff)) {
2706 if(sisfb_test_DDC1(ivideo)) temp = 1;
2710 if((temp) && (temp != 0xffff)) {
2711 orSISIDXREG(SISCR,0x32,0x20);
2714 #ifdef CONFIG_FB_SIS_315
2715 if(ivideo->sisvga_engine == SIS_315_VGA) {
2716 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2718 #endif
2720 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2722 outSISIDXREG(SISSR,0x1F,sr1F);
2725 /* Determine and detect attached devices on SiS30x */
2726 static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2728 int temp, mytest, result, i, j;
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
2750 if((result == 0) || (result >= 2)) break;
2752 return(result);
2755 static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
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";
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;
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;
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;
2783 biosflag = 2;
2785 if(ivideo->chip == SIS_300) {
2786 inSISIDXREG(SISSR,0x3b,myflag);
2787 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2790 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2791 orSISIDXREG(SISSR,0x1e,0x20);
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);
2799 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2801 inSISIDXREG(SISPART2,0x00,backupP2_00);
2802 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
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));
2809 if(!(ivideo->vbflags & VB_301C)) {
2810 SISDoSense(ivideo, 0, 0);
2813 andSISIDXREG(SISCR, 0x32, ~0x14);
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);
2827 andSISIDXREG(SISCR, 0x32, 0x3f);
2829 if(ivideo->vbflags & VB_301C) {
2830 orSISIDXREG(SISPART4,0x0d,0x04);
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);
2843 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2846 andSISIDXREG(SISCR, 0x32, ~0x03);
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);
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);
2861 SISDoSense(ivideo, 0, 0);
2863 outSISIDXREG(SISPART2,0x00,backupP2_00);
2864 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2865 outSISIDXREG(SISSR,0x1e,backupSR_1e);
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);
2877 outSISIDXREG(SISPART2,0x00,backupP2_00);
2880 /* Determine and detect attached TV's on Chrontel */
2881 static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
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
2892 if(ivideo->chip < SIS_315H) {
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);
2905 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2906 if(temp2 != temp1) temp1 = temp2;
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);
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);
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];
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);
2951 } else if(temp1 == 0) {
2952 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2953 andSISIDXREG(SISCR, 0x32, ~0x07);
2955 /* Set general purpose IO for Chrontel communication */
2956 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2957 #endif
2959 } else {
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);
3001 #endif
3005 /* ------------------------ Heap routines -------------------------- */
3007 static u32 __devinit
3008 sisfb_getheapstart(struct sis_video_info *ivideo)
3010 u32 ret = ivideo->sisfb_parm_mem * 1024;
3011 u32 max = ivideo->video_size - ivideo->hwcursor_size;
3012 u32 def;
3014 /* Calculate heap start = end of memory for console
3016 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3017 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3019 * Basically given by "mem" parameter
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
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;
3036 } else {
3037 max -= COMMAND_QUEUE_AREA_SIZE;
3038 def = max - 0x8000;
3041 if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) {
3042 ret = def;
3045 return ret;
3048 static int __devinit
3049 sisfb_heap_init(struct sis_video_info *ivideo)
3051 SIS_OH *poh;
3053 ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo);
3055 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3056 ivideo->sisfb_heap_end = ivideo->video_vbase + ivideo->video_size;
3058 /* Initialize command queue (We use MMIO only) */
3060 #ifdef CONFIG_FB_SIS_315
3061 if(ivideo->sisvga_engine == SIS_315_VGA) {
3062 u32 tempq = 0;
3063 u8 temp = 0;
3065 ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
3067 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
3068 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3070 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3071 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
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);
3077 tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE);
3078 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3080 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3082 #endif
3084 #ifdef CONFIG_FB_SIS_300
3085 if(ivideo->sisvga_engine == SIS_300_VGA) {
3086 unsigned long tqueue_pos;
3087 u8 tq_state;
3089 ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
3091 tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
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);
3099 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
3101 ivideo->caps |= TURBO_QUEUE_CAP;
3103 #endif
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;
3110 ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start;
3112 if(ivideo->cardnumber == 0) {
3114 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3115 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3117 sisfb_heap.vinfo = ivideo;
3119 sisfb_heap.poha_chain = NULL;
3120 sisfb_heap.poh_freelist = NULL;
3122 poh = sisfb_poh_new_node();
3123 if(poh == NULL) return 1;
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;
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;
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;
3139 } else {
3141 printk(KERN_INFO "Skipped heap initialization for secondary cards\n");
3145 return 0;
3148 static SIS_OH *
3149 sisfb_poh_new_node(void)
3151 int i;
3152 unsigned long cOhs;
3153 SIS_OHALLOC *poha;
3154 SIS_OH *poh;
3156 if(sisfb_heap.poh_freelist == NULL) {
3157 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3158 if(!poha) return NULL;
3160 poha->poha_next = sisfb_heap.poha_chain;
3161 sisfb_heap.poha_chain = poha;
3163 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
3165 poh = &poha->aoh[0];
3166 for(i = cOhs - 1; i != 0; i--) {
3167 poh->poh_next = poh + 1;
3168 poh = poh + 1;
3171 poh->poh_next = NULL;
3172 sisfb_heap.poh_freelist = &poha->aoh[0];
3175 poh = sisfb_heap.poh_freelist;
3176 sisfb_heap.poh_freelist = poh->poh_next;
3178 return (poh);
3181 static SIS_OH *
3182 sisfb_poh_allocate(u32 size)
3184 SIS_OH *pohThis;
3185 SIS_OH *pohRoot;
3186 int bAllocated = 0;
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);
3194 pohThis = sisfb_heap.oh_free.poh_next;
3196 while(pohThis != &sisfb_heap.oh_free) {
3197 if (size <= pohThis->size) {
3198 bAllocated = 1;
3199 break;
3201 pohThis = pohThis->poh_next;
3204 if(!bAllocated) {
3205 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3206 (unsigned int) size / 1024);
3207 return (NULL);
3210 if(size == pohThis->size) {
3211 pohRoot = pohThis;
3212 sisfb_delete_node(pohThis);
3213 } else {
3214 pohRoot = sisfb_poh_new_node();
3216 if(pohRoot == NULL) {
3217 return (NULL);
3220 pohRoot->offset = pohThis->offset;
3221 pohRoot->size = size;
3223 pohThis->offset += size;
3224 pohThis->size -= size;
3227 sisfb_heap.max_freesize -= size;
3229 pohThis = &sisfb_heap.oh_used;
3230 sisfb_insert_node(pohThis, pohRoot);
3232 return (pohRoot);
3235 static void
3236 sisfb_delete_node(SIS_OH *poh)
3238 SIS_OH *poh_prev;
3239 SIS_OH *poh_next;
3241 poh_prev = poh->poh_prev;
3242 poh_next = poh->poh_next;
3244 poh_prev->poh_next = poh_next;
3245 poh_next->poh_prev = poh_prev;
3248 static void
3249 sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
3251 SIS_OH *pohTemp;
3253 pohTemp = pohList->poh_next;
3255 pohList->poh_next = poh;
3256 pohTemp->poh_prev = poh;
3258 poh->poh_prev = pohList;
3259 poh->poh_next = pohTemp;
3262 static SIS_OH *
3263 sisfb_poh_free(u32 base)
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;
3273 poh_freed = sisfb_heap.oh_used.poh_next;
3275 while(poh_freed != &sisfb_heap.oh_used) {
3276 if(poh_freed->offset == base) {
3277 foundNode = 1;
3278 break;
3281 poh_freed = poh_freed->poh_next;
3284 if(!foundNode) return(NULL);
3286 sisfb_heap.max_freesize += poh_freed->size;
3288 poh_prev = poh_next = NULL;
3289 ulUpper = poh_freed->offset + poh_freed->size;
3290 ulLower = poh_freed->offset;
3292 pohThis = sisfb_heap.oh_free.poh_next;
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;
3300 pohThis = pohThis->poh_next;
3303 sisfb_delete_node(poh_freed);
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);
3313 if(poh_prev) {
3314 poh_prev->size += poh_freed->size;
3315 sisfb_free_node(poh_freed);
3316 return(poh_prev);
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);
3326 sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
3328 return(poh_freed);
3331 static void
3332 sisfb_free_node(SIS_OH *poh)
3334 if(poh == NULL) return;
3336 poh->poh_next = sisfb_heap.poh_freelist;
3337 sisfb_heap.poh_freelist = poh;
3340 void
3341 sis_malloc(struct sis_memreq *req)
3343 struct sis_video_info *ivideo = sisfb_heap.vinfo;
3344 SIS_OH *poh = NULL;
3346 if((ivideo) && (!ivideo->havenoheap)) {
3347 poh = sisfb_poh_allocate((u32)req->size);
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));
3361 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3363 void
3364 sis_free(u32 base)
3366 struct sis_video_info *ivideo = sisfb_heap.vinfo;
3367 SIS_OH *poh;
3369 if((!ivideo) || (ivideo->havenoheap)) return;
3371 poh = sisfb_poh_free((u32)base);
3373 if(poh == NULL) {
3374 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3375 (unsigned int) base);
3379 /* --------------------- SetMode routines ------------------------- */
3381 static void
3382 sisfb_pre_setmode(struct sis_video_info *ivideo)
3384 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3385 int tvregnum = 0;
3387 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3389 inSISIDXREG(SISCR, 0x31, cr31);
3390 cr31 &= ~0x60;
3391 cr31 |= 0x04;
3393 cr33 = ivideo->rate_idx & 0x0F;
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 */
3406 #endif
3407 #ifdef CONFIG_FB_SIS_300
3408 if(ivideo->sisvga_engine == SIS_300_VGA) {
3409 tvregnum = 0x35;
3410 inSISIDXREG(SISCR, tvregnum, cr38);
3412 #endif
3414 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3415 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3417 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
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));
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;
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;
3462 if(ivideo->vbflags & TV_AVIDEO) {
3463 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3464 ivideo->currentvbflags |= TV_AVIDEO;
3467 cr31 |= SIS_DRIVER_MODE;
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;
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;
3489 break;
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;
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);
3506 break;
3508 default: /* disable CRT2 */
3509 cr30 = 0x00;
3510 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3513 outSISIDXREG(SISCR, 0x30, cr30);
3514 outSISIDXREG(SISCR, 0x33, cr33);
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);
3526 outSISIDXREG(SISCR, 0x31, cr31);
3528 if(ivideo->accel) sisfb_syncaccel(ivideo);
3530 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3533 /* Fix SR11 for 661 and later */
3534 #ifdef CONFIG_FB_SIS_315
3535 static void
3536 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3538 u8 tmpreg;
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);
3548 if(tmpreg & 0xf0) {
3549 andSISIDXREG(SISSR,0x11,0x0f);
3553 #endif
3555 static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3557 if(val > 32) val = 32;
3558 if(val < -32) val = -32;
3559 ivideo->tvxpos = val;
3561 if(ivideo->sisfblocked) return;
3562 if(!ivideo->modechanged) return;
3564 if(ivideo->currentvbflags & CRT2_TV) {
3566 if(ivideo->vbflags & VB_CHRONTEL) {
3568 int x = ivideo->tvx;
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;
3583 } else if(ivideo->vbflags & VB_SISBRIDGE) {
3585 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3586 unsigned short temp;
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;
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);
3612 static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3614 if(val > 32) val = 32;
3615 if(val < -32) val = -32;
3616 ivideo->tvypos = val;
3618 if(ivideo->sisfblocked) return;
3619 if(!ivideo->modechanged) return;
3621 if(ivideo->currentvbflags & CRT2_TV) {
3623 if(ivideo->vbflags & VB_CHRONTEL) {
3625 int y = ivideo->tvy;
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;
3640 } else if(ivideo->vbflags & VB_SISBRIDGE) {
3642 char p2_01, p2_02;
3643 val /= 2;
3644 p2_01 = ivideo->p2_01;
3645 p2_02 = ivideo->p2_02;
3647 p2_01 += val;
3648 p2_02 += val;
3649 while((p2_01 <= 0) || (p2_02 <= 0)) {
3650 p2_01 += 2;
3651 p2_02 += 2;
3653 outSISIDXREG(SISPART2,0x01,p2_01);
3654 outSISIDXREG(SISPART2,0x02,p2_02);
3659 static void
3660 sisfb_post_setmode(struct sis_video_info *ivideo)
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
3671 outSISIDXREG(SISSR,0x05,0x86);
3673 #ifdef CONFIG_FB_SIS_315
3674 sisfb_fixup_SR11(ivideo);
3675 #endif
3677 /* Now we actually HAVE changed the display mode */
3678 ivideo->modechanged = 1;
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;
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;
3694 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
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;
3709 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3710 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3712 #endif
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;
3726 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
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);
3747 if(ivideo->tvxpos) {
3748 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3750 if(ivideo->tvypos) {
3751 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3754 if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) { /* Set filter for SiS301 */
3756 unsigned char filter_tb = 0;
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;
3777 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
3779 if(ivideo->vbflags & TV_NTSC) {
3781 andSISIDXREG(SISPART2, 0x3a, 0x1f);
3783 if (ivideo->vbflags & TV_SVIDEO) {
3785 andSISIDXREG(SISPART2, 0x30, 0xdf);
3787 } else if (ivideo->vbflags & TV_AVIDEO) {
3789 orSISIDXREG(SISPART2, 0x30, 0x20);
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;
3814 } else if(ivideo->vbflags & TV_PAL) {
3816 andSISIDXREG(SISPART2, 0x3A, 0x1F);
3818 if (ivideo->vbflags & TV_SVIDEO) {
3820 andSISIDXREG(SISPART2, 0x30, 0xDF);
3822 } else if (ivideo->vbflags & TV_AVIDEO) {
3824 orSISIDXREG(SISPART2, 0x30, 0x20);
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;
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]));
3860 #ifndef MODULE
3861 SISINITSTATIC int __init sisfb_setup(char *options)
3863 char *this_opt;
3865 sisfb_setdefaultparms();
3867 printk(KERN_DEBUG "sisfb: Options %s\n", options);
3869 if(!options || !(*options)) {
3870 return 0;
3873 while((this_opt = strsep(&options, ",")) != NULL) {
3875 if(!(*this_opt)) continue;
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';
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;
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;
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;
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;
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);
3972 return 0;
3974 #endif
3976 static UCHAR * __devinit sis_find_rom(struct pci_dev *pdev)
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;
3985 if(!(myrombase = vmalloc(65536))) return NULL;
3987 #if defined(__i386__) || defined(__x86_64__)
3989 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
3991 rom_base = ioremap(temp, 0x10000);
3992 if(!rom_base) continue;
3994 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) {
3995 iounmap(rom_base);
3996 continue;
3999 romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4000 if(romptr > (0x10000 - 8)) {
4001 iounmap(rom_base);
4002 continue;
4005 rom = rom_base + romptr;
4007 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4008 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) {
4009 iounmap(rom_base);
4010 continue;
4013 pciid = readb(rom + 4) | (readb(rom + 5) << 8);
4014 if(pciid != 0x1039) {
4015 iounmap(rom_base);
4016 continue;
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;
4026 iounmap(rom_base);
4029 #else
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);
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;
4056 iounmap(rom_base);
4058 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4060 #endif
4062 vfree(myrombase);
4063 return NULL;
4066 #ifdef CONFIG_FB_SIS_300
4067 static int __devinit
4068 sisfb_chkbuswidth300(struct pci_dev *pdev, SIS_IOTYPE1 *FBAddress)
4070 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4071 int i, j;
4072 USHORT temp;
4073 UCHAR reg;
4075 andSISIDXREG(SISSR,0x15,0xFB);
4076 orSISIDXREG(SISSR,0x15,0x04);
4077 outSISIDXREG(SISSR,0x13,0x00);
4078 outSISIDXREG(SISSR,0x14,0xBF);
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++;
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 */
4103 if(readl((FBAddress+4)) == 0x456789ABL) return(2); /* Channel B 64bit */
4104 return(1); /* 32bit */
4107 static void __devinit
4108 sisfb_setramsize300(struct pci_dev *pdev)
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}
4137 buswidth = sisfb_chkbuswidth300(pdev, FBAddr);
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;
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 */
4199 static void __devinit sisfb_post_sis300(struct pci_dev *pdev)
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;
4205 outSISIDXREG(SISSR,0x05,0x86);
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);
4213 memtype &= 0x07;
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++];
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];
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);
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];
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];
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];
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);
4319 } else {
4320 v2 &= ~0x10;
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 */
4345 #if !defined(__i386__) && !defined(__x86_64__)
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;
4361 outSISIDXREG(SISSR,0x21,v1);
4362 outSISIDXREG(SISSR,0x22,v2);
4364 #endif
4366 #ifdef CONFIG_FB_SIS_315
4367 static void __devinit sisfb_post_sis315330(struct pci_dev *pdev)
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;
4376 /* Unlock */
4377 /* outSISIDXREG(0x3c4,0x05,0x86); */
4378 outSISIDXREG(SISSR,0x05,0x86);
4380 /* Enable relocated i/o ports */
4381 /* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */
4382 setSISIDXREG(SISSR,0x20,~0x10,0x20);
4384 /* Clear regs */
4385 for(i = 0; i < 0x22; i++) {
4386 outSISIDXREG(SISSR,(0x06 + i),0x00);
4388 v1 = 0x0d;
4389 if( is 330) v1 = 0x0b;
4390 for(i = 0; i < v1; i++) {
4391 outSISIDXREG(SISSR,(0x31 + i),0x00);
4393 for(i = 0; i < 0x10; i++) {
4394 outSISIDXREG(SISCR,(0x30 + i),0x00);
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);
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);
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;
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++];
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) {
4459 outSISIDXREG(SISSR,0x2e,v4);
4460 outSISIDXREG(SISSR,0x2f,v5);
4461 outSISIDXREG(SISSR,0x30,v6);
4463 /* End of comp with 330 */
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);
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];
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); /* ---- */
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];
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);
4506 if( is 330 ) {
4508 v1 = 0x;
4509 if(ivideo->sishw_ext.UseROM) {
4510 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4512 outSISIDXREG(SISCR,0x59,v1);
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];
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);
4536 v1 = 0x20;
4537 inSISIDXREG(SISSR,0x3b,reg);
4539 if(!(reg & 0x04)) {
4540 inSISIDXREG(SISCR,0x5F,reg);
4541 reg &= 0x30;
4542 if(reg) v1 = 0x23;
4544 outSISIDXREG(SISCR,0x48,v1);
4545 outSISIDXREG(SISCR,0x4c,0x20);
4547 xx= xxx();
4548 if(xx >= 1) {
4549 v1 = 0x;
4550 if(ivideo->sishw_ext.UseROM) {
4551 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4553 outSISIDXREG(SISCR,0x59,v1);
4558 } else {
4560 outSISIDXREG(SISCR,0x48,0x23);
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];
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);
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]);
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]);
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);
4612 v1 = 0x00;
4613 if(ivideo->sishw_ext.UseROM) {
4614 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x99];
4616 outSISIDXREG(SISSR,0x1f,v1);
4618 outSISIDXREG(SISSR,0x20,0x20);
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];
4626 outSISIDXREG(SISSR,0x23,v1);
4627 outSISIDXREG(SISSR,0x24,v2);
4628 outSISIDXREG(SISSR,0x25,v3);
4630 outSISIDXREG(SISSR,0x21,0x84);
4631 outSISIDXREG(SISSR,0x22,0x00);
4632 outSISIDXREG(SISSR,0x27,0x1f);
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];
4639 outSISIDXREG(SISSR,0x31,v1);
4640 outSISIDXREG(SISSR,0x33,v2);
4642 v1 = 0x11;
4643 if(ivideo->sishw_ext.UseROM) {
4644 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xA0];
4646 v2 = inSISIDXREG(SISPART4,0x00);
4647 if((v2 != 1) && (v2 != 2)) v1 &= 0xef;
4648 outSISIDXREG(SISSR,0x32,v1);
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];
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];
4667 outSISIDXREG(SISCR,0x49,v1);
4668 outSISIDXREG(SISSR,0x25,v2);
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];
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];
4687 outSISIDXREG(SISPART4,0x0d,v1);
4688 outSISIDXREG(SISPART4,0x0e,v2);
4689 outSISIDXREG(SISPART4,0x10,v3);
4690 outSISIDXREG(SISPART4,0x0F,0x3F);
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);
4700 outSISIDXREG(SISCR,0x37,0x02); /* Why? */
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 */
4713 /* Set Mode 0x2e */
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);
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);
4735 } else {
4741 /* Find out about size */
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 */
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];
4756 outSISIDXREG(SISSR,0x21,v1);
4757 outSISIDXREG(SISSR,0x22,v2);
4759 #endif
4760 return;
4762 #endif
4765 static int __devinit sisfb_probe(struct pci_dev *pdev,
4766 const struct pci_device_id *ent)
4768 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
4769 struct sis_video_info *ivideo = NULL;
4770 struct fb_info *sis_fb_info = NULL;
4771 u16 reg16;
4772 u8 reg;
4773 int sisvga_enabled = 0, i;
4775 if(sisfb_off) return -ENXIO;
4777 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
4778 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
4779 if(!sis_fb_info) return -ENOMEM;
4780 #else
4781 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
4782 if(!sis_fb_info) return -ENOMEM;
4783 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
4784 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
4785 #endif
4787 ivideo = (struct sis_video_info *)sis_fb_info->par;
4788 ivideo->memyselfandi = sis_fb_info;
4790 if(card_list == NULL) {
4791 ivideo->cardnumber = 0;
4792 } else {
4793 struct sis_video_info *countvideo = card_list;
4794 ivideo->cardnumber = 1;
4795 while((countvideo = countvideo->next) != NULL) ivideo->cardnumber++;
4798 strncpy(ivideo->myid, chipinfo->chip_name, 30);
4800 ivideo->warncount = 0;
4801 ivideo->chip_id = pdev->device;
4802 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
4803 ivideo->sishw_ext.jChipRevision = ivideo->revision_id;
4804 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
4805 sisvga_enabled = reg16 & 0x01;
4806 ivideo->pcibus = pdev->bus->number;
4807 ivideo->pcislot = PCI_SLOT(pdev->devfn);
4808 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
4809 ivideo->subsysvendor = pdev->subsystem_vendor;
4810 ivideo->subsysdevice = pdev->subsystem_device;
4812 #ifndef MODULE
4813 if(sisfb_mode_idx == -1) {
4814 sisfb_get_vga_mode_from_kernel();
4816 #endif
4818 ivideo->chip = chipinfo->chip;
4819 ivideo->sisvga_engine = chipinfo->vgaengine;
4820 ivideo->hwcursor_size = chipinfo->hwcursor_size;
4821 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
4822 ivideo->mni = chipinfo->mni;
4824 ivideo->detectedpdc = 0xff;
4825 ivideo->detectedpdca = 0xff;
4826 ivideo->detectedlcda = 0xff;
4828 ivideo->sisfb_thismonitor.datavalid = FALSE;
4830 ivideo->sisfb_parm_mem = sisfb_parm_mem;
4831 ivideo->sisfb_accel = sisfb_accel;
4832 ivideo->sisfb_ypan = sisfb_ypan;
4833 ivideo->sisfb_max = sisfb_max;
4834 ivideo->sisfb_userom = sisfb_userom;
4835 ivideo->sisfb_useoem = sisfb_useoem;
4836 ivideo->sisfb_mode_idx = sisfb_mode_idx;
4837 ivideo->sisfb_parm_rate = sisfb_parm_rate;
4838 ivideo->sisfb_crt1off = sisfb_crt1off;
4839 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
4840 ivideo->sisfb_crt2type = sisfb_crt2type;
4841 ivideo->sisfb_crt2flags = sisfb_crt2flags;
4842 /* pdc(a), scalelcd, special timing, lvdshl handled below */
4843 ivideo->sisfb_dstn = sisfb_dstn;
4844 ivideo->sisfb_fstn = sisfb_fstn;
4845 ivideo->sisfb_tvplug = sisfb_tvplug;
4846 ivideo->sisfb_tvstd = sisfb_tvstd;
4847 ivideo->tvxpos = sisfb_tvxposoffset;
4848 ivideo->tvypos = sisfb_tvyposoffset;
4849 ivideo->sisfb_filter = sisfb_filter;
4850 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
4851 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4852 ivideo->sisfb_inverse = sisfb_inverse;
4853 #endif
4855 ivideo->refresh_rate = 0;
4856 if(ivideo->sisfb_parm_rate != -1) {
4857 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
4860 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
4861 ivideo->SiS_Pr.CenterScreen = -1;
4862 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
4863 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
4865 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
4866 ivideo->SiS_Pr.SiS_CHOverScan = -1;
4867 ivideo->SiS_Pr.SiS_ChSW = FALSE;
4868 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
4869 ivideo->SiS_Pr.HaveEMI = FALSE;
4870 ivideo->SiS_Pr.HaveEMILCD = FALSE;
4871 ivideo->SiS_Pr.OverruleEMI = FALSE;
4872 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
4873 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
4874 ivideo->SiS_Pr.PDC = -1;
4875 ivideo->SiS_Pr.PDCA = -1;
4876 #ifdef CONFIG_FB_SIS_315
4877 if(ivideo->chip >= SIS_330) {
4878 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
4879 if(ivideo->chip >= SIS_661) {
4880 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
4883 #endif
4885 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
4887 pci_set_drvdata(pdev, ivideo);
4889 /* Patch special cases */
4890 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
4891 switch(ivideo->nbridge->device) {
4892 #ifdef CONFIG_FB_SIS_300
4893 case PCI_DEVICE_ID_SI_730:
4894 ivideo->chip = SIS_730;
4895 strcpy(ivideo->myid, "SiS 730");
4896 break;
4897 #endif
4898 #ifdef CONFIG_FB_SIS_315
4899 case PCI_DEVICE_ID_SI_651:
4900 /* ivideo->chip is ok */
4901 strcpy(ivideo->myid, "SiS 651");
4902 break;
4903 case PCI_DEVICE_ID_SI_740:
4904 ivideo->chip = SIS_740;
4905 strcpy(ivideo->myid, "SiS 740");
4906 break;
4907 case PCI_DEVICE_ID_SI_661:
4908 ivideo->chip = SIS_661;
4909 strcpy(ivideo->myid, "SiS 661");
4910 break;
4911 case PCI_DEVICE_ID_SI_741:
4912 ivideo->chip = SIS_741;
4913 strcpy(ivideo->myid, "SiS 741");
4914 break;
4915 case PCI_DEVICE_ID_SI_760:
4916 ivideo->chip = SIS_760;
4917 strcpy(ivideo->myid, "SiS 760");
4918 break;
4919 #endif
4923 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4924 strcpy(sis_fb_info->modename, ivideo->myid);
4925 #endif
4927 ivideo->sishw_ext.jChipType = ivideo->chip;
4929 #ifdef CONFIG_FB_SIS_315
4930 if((ivideo->sishw_ext.jChipType == SIS_315PRO) ||
4931 (ivideo->sishw_ext.jChipType == SIS_315)) {
4932 ivideo->sishw_ext.jChipType = SIS_315H;
4934 #endif
4936 ivideo->video_base = pci_resource_start(pdev, 0);
4937 ivideo->mmio_base = pci_resource_start(pdev, 1);
4938 ivideo->mmio_size = pci_resource_len(pdev, 1);
4939 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
4940 ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
4942 if(!sisvga_enabled) {
4943 if(pci_enable_device(pdev)) {
4944 pci_set_drvdata(pdev, NULL);
4945 kfree(sis_fb_info);
4946 return -EIO;
4950 SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress);
4952 #ifdef CONFIG_FB_SIS_300
4953 /* Find PCI systems for Chrontel/GPIO communication setup */
4954 if(ivideo->chip == SIS_630) {
4955 i=0;
4956 do {
4957 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
4958 mychswtable[i].subsysCard == ivideo->subsysdevice) {
4959 ivideo->SiS_Pr.SiS_ChSW = TRUE;
4960 printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
4961 mychswtable[i].vendorName, mychswtable[i].cardName);
4962 break;
4964 i++;
4965 } while(mychswtable[i].subsysVendor != 0);
4967 #endif
4969 outSISIDXREG(SISSR, 0x05, 0x86);
4971 if( (!sisvga_enabled)
4972 #if !defined(__i386__) && !defined(__x86_64__)
4973 || (sisfb_resetcard)
4974 #endif
4976 for(i = 0x30; i <= 0x3f; i++) {
4977 outSISIDXREG(SISCR,i,0x00);
4981 /* Find out about current video mode */
4982 ivideo->modeprechange = 0x03;
4983 inSISIDXREG(SISCR,0x34,reg);
4984 if(reg & 0x7f) {
4985 ivideo->modeprechange = reg & 0x7f;
4986 } else if(sisvga_enabled) {
4987 #if defined(__i386__) || defined(__x86_64__)
4988 unsigned char SIS_IOTYPE2 *tt = ioremap(0, 0x1000);
4989 if(tt) {
4990 ivideo->modeprechange = readb(tt + 0x449);
4991 iounmap(tt);
4993 #endif
4996 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4997 #ifdef MODULE
4998 if((reg & 0x80) && (reg != 0xff)) {
4999 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) {
5000 printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
5001 pci_set_drvdata(pdev, NULL);
5002 kfree(sis_fb_info);
5003 return -EBUSY;
5006 #endif
5007 #endif
5009 ivideo->sishw_ext.bIntegratedMMEnabled = TRUE;
5010 #ifdef CONFIG_FB_SIS_300
5011 if(ivideo->sisvga_engine == SIS_300_VGA) {
5012 if(ivideo->chip != SIS_300) {
5013 inSISIDXREG(SISSR, 0x1a, reg);
5014 if(!(reg & 0x10)) {
5015 ivideo->sishw_ext.bIntegratedMMEnabled = FALSE;
5019 #endif
5021 ivideo->bios_abase = NULL;
5022 if(ivideo->sisfb_userom) {
5023 ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
5024 ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase;
5025 if(ivideo->sishw_ext.pjVirtualRomBase) {
5026 printk(KERN_INFO "sisfb: Video ROM found and copied\n");
5027 ivideo->sishw_ext.UseROM = TRUE;
5028 } else {
5029 ivideo->sishw_ext.UseROM = FALSE;
5030 printk(KERN_INFO "sisfb: Video ROM not found\n");
5032 } else {
5033 ivideo->sishw_ext.pjVirtualRomBase = NULL;
5034 ivideo->sishw_ext.UseROM = FALSE;
5035 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
5038 /* Find systems for special custom timing */
5039 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
5040 int j;
5041 unsigned char *biosver = NULL;
5042 unsigned char *biosdate = NULL;
5043 BOOLEAN footprint;
5044 u32 chksum = 0;
5046 if(ivideo->sishw_ext.UseROM) {
5047 biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
5048 biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
5049 for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
5052 i=0;
5053 do {
5054 if( (mycustomttable[i].chipID == ivideo->chip) &&
5055 ((!strlen(mycustomttable[i].biosversion)) ||
5056 (ivideo->sishw_ext.UseROM &&
5057 (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
5058 ((!strlen(mycustomttable[i].biosdate)) ||
5059 (ivideo->sishw_ext.UseROM &&
5060 (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
5061 ((!mycustomttable[i].bioschksum) ||
5062 (ivideo->sishw_ext.UseROM &&
5063 (mycustomttable[i].bioschksum == chksum))) &&
5064 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
5065 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
5066 footprint = TRUE;
5067 for(j = 0; j < 5; j++) {
5068 if(mycustomttable[i].biosFootprintAddr[j]) {
5069 if(ivideo->sishw_ext.UseROM) {
5070 if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
5071 mycustomttable[i].biosFootprintData[j]) {
5072 footprint = FALSE;
5074 } else footprint = FALSE;
5077 if(footprint) {
5078 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
5079 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
5080 mycustomttable[i].vendorName,
5081 mycustomttable[i].cardName);
5082 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
5083 mycustomttable[i].optionName);
5084 break;
5087 i++;
5088 } while(mycustomttable[i].chipID);
5091 #ifdef CONFIG_FB_SIS_300
5092 if(ivideo->sisvga_engine == SIS_300_VGA) {
5093 if( (!sisvga_enabled)
5094 #if !defined(__i386__) && !defined(__x86_64__)
5095 || (sisfb_resetcard)
5096 #endif
5098 if(ivideo->chip == SIS_300) {
5099 sisfb_post_sis300(pdev);
5103 #endif
5105 #ifdef CONFIG_FB_SIS_315
5106 if(ivideo->sisvga_engine == SIS_315_VGA) {
5107 if( (!sisvga_enabled)
5108 #if !defined(__i386__) && !defined(__x86_64__)
5109 || (sisfb_resetcard)
5110 #endif
5112 if((ivideo->chip == SIS_315H) ||
5113 (ivideo->chip == SIS_315) ||
5114 (ivideo->chip == SIS_315PRO) ||
5115 (ivideo->chip == SIS_330)) {
5116 sisfb_post_sis315330(pdev);
5120 #endif
5122 if(sisfb_get_dram_size(ivideo)) {
5123 printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
5124 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5125 pci_set_drvdata(pdev, NULL);
5126 kfree(sis_fb_info);
5127 return -ENODEV;
5130 if((ivideo->sisfb_mode_idx < 0) ||
5131 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5132 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
5133 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
5134 /* Enable 2D accelerator engine */
5135 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
5138 if(sisfb_pdc != 0xff) {
5139 if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
5140 else sisfb_pdc &= 0x1f;
5141 ivideo->SiS_Pr.PDC = sisfb_pdc;
5143 #ifdef CONFIG_FB_SIS_315
5144 if(ivideo->sisvga_engine == SIS_315_VGA) {
5145 if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
5147 #endif
5149 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
5150 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
5151 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
5152 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5153 pci_set_drvdata(pdev, NULL);
5154 kfree(sis_fb_info);
5155 return -ENODEV;
5158 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
5159 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
5160 release_mem_region(ivideo->video_base, ivideo->video_size);
5161 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5162 pci_set_drvdata(pdev, NULL);
5163 kfree(sis_fb_info);
5164 return -ENODEV;
5167 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
5168 ivideo->sishw_ext.pjVideoMemoryAddress = ivideo->video_vbase;
5169 if(!ivideo->video_vbase) {
5170 printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
5171 release_mem_region(ivideo->video_base, ivideo->video_size);
5172 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5173 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5174 pci_set_drvdata(pdev, NULL);
5175 kfree(sis_fb_info);
5176 return -ENODEV;
5179 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
5180 if(!ivideo->mmio_vbase) {
5181 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
5182 iounmap(ivideo->video_vbase);
5183 release_mem_region(ivideo->video_base, ivideo->video_size);
5184 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5185 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5186 pci_set_drvdata(pdev, NULL);
5187 kfree(sis_fb_info);
5188 return -ENODEV;
5191 printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n",
5192 ivideo->video_base, (ULONG)ivideo->video_vbase, ivideo->video_size / 1024);
5194 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
5195 ivideo->mmio_base, (ULONG)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
5197 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
5198 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
5201 /* Used for clearing the screen only, therefore respect our mem limit */
5202 ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
5204 ivideo->mtrr = 0;
5206 ivideo->vbflags = 0;
5207 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
5208 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
5209 ivideo->defmodeidx = DEFAULT_MODE;
5211 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
5213 if((ivideo->sisfb_mode_idx < 0) ||
5214 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5216 sisfb_sense_crt1(ivideo);
5218 sisfb_get_VB_type(ivideo);
5220 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5221 sisfb_detect_VB_connect(ivideo);
5224 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
5226 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5227 if(ivideo->sisfb_crt2type != -1) {
5228 if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
5229 ivideo->currentvbflags |= CRT2_LCD;
5230 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
5231 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
5233 } else {
5234 /* Chrontel 700x TV detection often unreliable, therefore use a
5235 * different default order on such machines
5237 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
5238 if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5239 else if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
5240 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5241 } else {
5242 if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
5243 else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5244 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5249 if(ivideo->vbflags & CRT2_LCD) {
5250 inSISIDXREG(SISCR, 0x36, reg);
5251 reg &= 0x0f;
5252 if(ivideo->sisvga_engine == SIS_300_VGA) {
5253 ivideo->CRT2LCDType = sis300paneltype[reg];
5254 } else if(ivideo->chip >= SIS_661) {
5255 ivideo->CRT2LCDType = sis661paneltype[reg];
5256 } else {
5257 ivideo->CRT2LCDType = sis310paneltype[reg];
5258 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
5259 if((ivideo->CRT2LCDType != LCD_640x480_2) &&
5260 (ivideo->CRT2LCDType != LCD_640x480_3)) {
5261 ivideo->CRT2LCDType = LCD_320x480;
5265 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
5266 /* For broken BIOSes: Assume 1024x768, RGB18 */
5267 ivideo->CRT2LCDType = LCD_1024x768;
5268 setSISIDXREG(SISCR,0x36,0xf0,0x02);
5269 setSISIDXREG(SISCR,0x37,0xee,0x01);
5270 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
5272 for(i = 0; i < SIS_LCD_NUMBER; i++) {
5273 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
5274 ivideo->lcdxres = sis_lcd_data[i].xres;
5275 ivideo->lcdyres = sis_lcd_data[i].yres;
5276 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
5277 break;
5280 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
5281 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
5282 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
5283 ivideo->lcdxres = 848; ivideo->lcdyres = 480; ivideo->lcddefmodeidx = 47;
5285 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
5286 ivideo->lcdxres, ivideo->lcdyres);
5289 #ifdef CONFIG_FB_SIS_300
5290 /* Save the current PanelDelayCompensation if the LCD is currently used */
5291 if(ivideo->sisvga_engine == SIS_300_VGA) {
5292 if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
5293 int tmp;
5294 inSISIDXREG(SISCR,0x30,tmp);
5295 if(tmp & 0x20) {
5296 /* Currently on LCD? If yes, read current pdc */
5297 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
5298 ivideo->detectedpdc &= 0x3c;
5299 if(ivideo->SiS_Pr.PDC == -1) {
5300 /* Let option override detection */
5301 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5303 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
5304 ivideo->detectedpdc);
5306 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5307 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
5308 ivideo->SiS_Pr.PDC);
5312 #endif
5314 #ifdef CONFIG_FB_SIS_315
5315 if(ivideo->sisvga_engine == SIS_315_VGA) {
5317 /* Try to find about LCDA */
5318 if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
5319 int tmp;
5320 inSISIDXREG(SISPART1,0x13,tmp);
5321 if(tmp & 0x04) {
5322 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
5323 ivideo->detectedlcda = 0x03;
5327 /* Save PDC */
5328 if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
5329 int tmp;
5330 inSISIDXREG(SISCR,0x30,tmp);
5331 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5332 /* Currently on LCD? If yes, read current pdc */
5333 u8 pdc;
5334 inSISIDXREG(SISPART1,0x2D,pdc);
5335 ivideo->detectedpdc = (pdc & 0x0f) << 1;
5336 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
5337 inSISIDXREG(SISPART1,0x35,pdc);
5338 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
5339 inSISIDXREG(SISPART1,0x20,pdc);
5340 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
5341 if(ivideo->newrom) {
5342 /* New ROM invalidates other PDC resp. */
5343 if(ivideo->detectedlcda != 0xff) {
5344 ivideo->detectedpdc = 0xff;
5345 } else {
5346 ivideo->detectedpdca = 0xff;
5349 if(ivideo->SiS_Pr.PDC == -1) {
5350 if(ivideo->detectedpdc != 0xff) {
5351 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5354 if(ivideo->SiS_Pr.PDCA == -1) {
5355 if(ivideo->detectedpdca != 0xff) {
5356 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
5359 if(ivideo->detectedpdc != 0xff) {
5360 printk(KERN_INFO
5361 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
5362 ivideo->detectedpdc);
5364 if(ivideo->detectedpdca != 0xff) {
5365 printk(KERN_INFO
5366 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
5367 ivideo->detectedpdca);
5371 /* Save EMI */
5372 if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
5373 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
5374 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
5375 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
5376 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
5377 ivideo->SiS_Pr.HaveEMI = TRUE;
5378 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5379 ivideo->SiS_Pr.HaveEMILCD = TRUE;
5384 /* Let user override detected PDCs (all bridges) */
5385 if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
5386 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5387 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
5388 ivideo->SiS_Pr.PDC);
5390 if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
5391 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
5392 ivideo->SiS_Pr.PDCA);
5397 #endif
5399 if(!ivideo->sisfb_crt1off) {
5400 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
5401 } else {
5402 if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
5403 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
5404 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
5408 if(ivideo->sisfb_mode_idx >= 0) {
5409 int bu = ivideo->sisfb_mode_idx;
5410 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
5411 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
5412 if(bu != ivideo->sisfb_mode_idx) {
5413 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
5414 sisbios_mode[bu].xres,
5415 sisbios_mode[bu].yres,
5416 sisbios_mode[bu].bpp);
5420 if(ivideo->sisfb_mode_idx < 0) {
5421 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
5422 case CRT2_LCD:
5423 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
5424 break;
5425 case CRT2_TV:
5426 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
5427 break;
5428 default:
5429 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
5430 break;
5434 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
5436 if(ivideo->refresh_rate != 0) {
5437 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
5440 if(ivideo->rate_idx == 0) {
5441 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
5442 ivideo->refresh_rate = 60;
5445 if(ivideo->sisfb_thismonitor.datavalid) {
5446 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
5447 ivideo->rate_idx, ivideo->refresh_rate)) {
5448 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
5452 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
5453 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
5454 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
5456 sisfb_set_vparms(ivideo);
5458 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5460 /* ---------------- For 2.4: Now switch the mode ------------------ */
5462 printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
5463 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5464 ivideo->refresh_rate);
5466 sisfb_pre_setmode(ivideo);
5468 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
5469 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
5470 ivideo->mode_no);
5471 iounmap(ivideo->video_vbase);
5472 iounmap(ivideo->mmio_vbase);
5473 release_mem_region(ivideo->video_base, ivideo->video_size);
5474 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5475 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5476 pci_set_drvdata(pdev, NULL);
5477 kfree(sis_fb_info);
5478 return -EINVAL;
5481 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
5483 sisfb_post_setmode(ivideo);
5485 /* Maximize regardless of sisfb_max at startup */
5486 ivideo->default_var.yres_virtual = 32767;
5488 /* Force reset of x virtual in crtc_to_var */
5489 ivideo->default_var.xres_virtual = 0;
5491 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
5493 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5494 sisfb_set_pitch(ivideo);
5496 ivideo->accel = 0;
5497 if(ivideo->sisfb_accel) {
5498 ivideo->accel = -1;
5499 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5501 sisfb_initaccel(ivideo);
5503 sis_fb_info->node = -1;
5504 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5505 sis_fb_info->fbops = &sisfb_ops;
5506 sis_fb_info->disp = &ivideo->sis_disp;
5507 sis_fb_info->blank = &sisfb_blank;
5508 sis_fb_info->switch_con = &sisfb_switch;
5509 sis_fb_info->updatevar = &sisfb_update_var;
5510 sis_fb_info->changevar = NULL;
5511 strcpy(sis_fb_info->fontname, sisfb_fontname);
5513 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
5515 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
5517 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
5518 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5519 ivideo->refresh_rate);
5521 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
5522 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
5523 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
5525 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
5527 ivideo->default_var.pixclock = (u32) (1000000000 /
5528 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5529 ivideo->mode_no, ivideo->rate_idx));
5531 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5532 ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
5533 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
5534 ivideo->default_var.pixclock <<= 1;
5538 if(ivideo->sisfb_ypan) {
5539 /* Maximize regardless of sisfb_max at startup */
5540 ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var);
5541 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
5542 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
5546 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5548 ivideo->accel = 0;
5549 if(ivideo->sisfb_accel) {
5550 ivideo->accel = -1;
5551 #ifdef STUPID_ACCELF_TEXT_SHIT
5552 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5553 #endif
5555 sisfb_initaccel(ivideo);
5557 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
5558 sis_fb_info->flags = FBINFO_DEFAULT |
5559 FBINFO_HWACCEL_YPAN |
5560 FBINFO_HWACCEL_XPAN |
5561 FBINFO_HWACCEL_COPYAREA |
5562 FBINFO_HWACCEL_FILLRECT |
5563 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
5564 #else
5565 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5566 #endif
5567 sis_fb_info->var = ivideo->default_var;
5568 sis_fb_info->fix = ivideo->sisfb_fix;
5569 sis_fb_info->screen_base = ivideo->video_vbase;
5570 sis_fb_info->fbops = &sisfb_ops;
5572 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
5573 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
5575 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
5576 #endif /* 2.6 */
5578 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
5580 #ifdef CONFIG_MTRR
5581 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
5582 MTRR_TYPE_WRCOMB, 1);
5583 if(!ivideo->mtrr) {
5584 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
5586 #endif
5588 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5589 vc_resize_con(1, 1, 0);
5590 #endif
5592 if(register_framebuffer(sis_fb_info) < 0) {
5593 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
5594 iounmap(ivideo->video_vbase);
5595 iounmap(ivideo->mmio_vbase);
5596 release_mem_region(ivideo->video_base, ivideo->video_size);
5597 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5598 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5599 pci_set_drvdata(pdev, NULL);
5600 kfree(sis_fb_info);
5601 return -EINVAL;
5604 ivideo->registered = 1;
5606 /* Enlist us */
5607 ivideo->next = card_list;
5608 card_list = ivideo;
5610 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
5611 ivideo->sisfb_accel ? "enabled" : "disabled",
5612 ivideo->sisfb_ypan ?
5613 (ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
5616 printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n",
5617 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5618 GET_FB_IDX(sis_fb_info->node),
5619 #else
5620 sis_fb_info->node,
5621 #endif
5622 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
5624 printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
5626 } /* if mode = "none" */
5628 return 0;
5631 /*****************************************************/
5632 /* PCI DEVICE HANDLING */
5633 /*****************************************************/
5635 static void __devexit sisfb_remove(struct pci_dev *pdev)
5637 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5638 struct fb_info *sis_fb_info = ivideo->memyselfandi;
5639 int registered = ivideo->registered;
5641 /* Unmap */
5642 iounmap(ivideo->video_vbase);
5643 iounmap(ivideo->mmio_vbase);
5644 vfree(ivideo->bios_abase);
5646 /* Release mem regions */
5647 release_mem_region(ivideo->video_base, ivideo->video_size);
5648 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5650 #ifdef CONFIG_MTRR
5651 /* Release MTRR region */
5652 if(ivideo->mtrr) {
5653 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
5655 #endif
5657 /* Unregister the framebuffer */
5658 if(ivideo->registered) {
5659 unregister_framebuffer(sis_fb_info);
5660 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5661 framebuffer_release(sis_fb_info);
5662 #else
5663 kfree(sis_fb_info);
5664 #endif
5667 pci_set_drvdata(pdev, NULL);
5669 /* TODO: Restore the initial mode
5670 * This sounds easy but is as good as impossible
5671 * on many machines with SiS chip and video bridge
5672 * since text modes are always set up differently
5673 * from machine to machine. Depends on the type
5674 * of integration between chipset and bridge.
5676 if(registered) {
5677 printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
5681 static struct pci_driver sisfb_driver = {
5682 .name = "sisfb",
5683 .id_table = sisfb_pci_table,
5684 .probe = sisfb_probe,
5685 .remove = __devexit_p(sisfb_remove)
5688 SISINITSTATIC int __init sisfb_init(void)
5690 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5691 #ifndef MODULE
5692 char *options = NULL;
5694 if(fb_get_options("sisfb", &options))
5695 return -ENODEV;
5696 sisfb_setup(options);
5697 #endif
5698 #endif
5699 return(pci_register_driver(&sisfb_driver));
5702 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5703 #ifndef MODULE
5704 module_init(sisfb_init);
5705 #endif
5706 #endif
5708 /*****************************************************/
5709 /* MODULE */
5710 /*****************************************************/
5712 #ifdef MODULE
5714 static char *mode = NULL;
5715 static int vesa = -1;
5716 static unsigned int rate = 0;
5717 static unsigned int crt1off = 1;
5718 static unsigned int mem = 0;
5719 static char *forcecrt2type = NULL;
5720 static int forcecrt1 = -1;
5721 static int pdc = -1;
5722 static int pdc1 = -1;
5723 static int noaccel = -1;
5724 static int noypan = -1;
5725 static int nomax = -1;
5726 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5727 static int inverse = 0;
5728 #endif
5729 static int userom = -1;
5730 static int useoem = -1;
5731 static char *tvstandard = NULL;
5732 static int nocrt2rate = 0;
5733 static int scalelcd = -1;
5734 static char *specialtiming = NULL;
5735 static int lvdshl = -1;
5736 static int tvxposoffset = 0, tvyposoffset = 0;
5737 static int filter = -1;
5738 #if !defined(__i386__) && !defined(__x86_64__)
5739 static int resetcard = 0;
5740 static int videoram = 0;
5741 #endif
5743 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
5744 MODULE_LICENSE("GPL");
5745 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
5747 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5748 MODULE_PARM(mem, "i");
5749 MODULE_PARM(noaccel, "i");
5750 MODULE_PARM(noypan, "i");
5751 MODULE_PARM(nomax, "i");
5752 MODULE_PARM(userom, "i");
5753 MODULE_PARM(useoem, "i");
5754 MODULE_PARM(mode, "s");
5755 MODULE_PARM(vesa, "i");
5756 MODULE_PARM(rate, "i");
5757 MODULE_PARM(forcecrt1, "i");
5758 MODULE_PARM(forcecrt2type, "s");
5759 MODULE_PARM(scalelcd, "i");
5760 MODULE_PARM(pdc, "i");
5761 MODULE_PARM(pdc1, "i");
5762 MODULE_PARM(specialtiming, "s");
5763 MODULE_PARM(lvdshl, "i");
5764 MODULE_PARM(tvstandard, "s");
5765 MODULE_PARM(tvxposoffset, "i");
5766 MODULE_PARM(tvyposoffset, "i");
5767 MODULE_PARM(filter, "i");
5768 MODULE_PARM(nocrt2rate, "i");
5769 MODULE_PARM(inverse, "i");
5770 #if !defined(__i386__) && !defined(__x86_64__)
5771 MODULE_PARM(resetcard, "i");
5772 MODULE_PARM(videoram, "i");
5773 #endif
5774 #endif
5776 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5777 module_param(mem, int, 0);
5778 module_param(noaccel, int, 0);
5779 module_param(noypan, int, 0);
5780 module_param(nomax, int, 0);
5781 module_param(userom, int, 0);
5782 module_param(useoem, int, 0);
5783 module_param(mode, charp, 0);
5784 module_param(vesa, int, 0);
5785 module_param(rate, int, 0);
5786 module_param(forcecrt1, int, 0);
5787 module_param(forcecrt2type, charp, 0);
5788 module_param(scalelcd, int, 0);
5789 module_param(pdc, int, 0);
5790 module_param(pdc1, int, 0);
5791 module_param(specialtiming, charp, 0);
5792 module_param(lvdshl, int, 0);
5793 module_param(tvstandard, charp, 0);
5794 module_param(tvxposoffset, int, 0);
5795 module_param(tvyposoffset, int, 0);
5796 module_param(filter, int, 0);
5797 module_param(nocrt2rate, int, 0);
5798 #if !defined(__i386__) && !defined(__x86_64__)
5799 module_param(resetcard, int, 0);
5800 module_param(videoram, int, 0);
5801 #endif
5802 #endif
5804 MODULE_PARM_DESC(mem,
5805 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
5806 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
5807 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
5808 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
5809 "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
5810 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
5811 "for XFree86 4.x/X.org 6.7 and later.\n");
5813 MODULE_PARM_DESC(noaccel,
5814 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
5815 "(default: 0)\n");
5817 MODULE_PARM_DESC(noypan,
5818 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
5819 "will be performed by redrawing the screen. (default: 0)\n");
5821 MODULE_PARM_DESC(nomax,
5822 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
5823 "memory for the virtual screen in order to optimize scrolling performance. If\n"
5824 "this is set to anything other than 0, sisfb will not do this and thereby \n"
5825 "enable the user to positively specify a virtual Y size of the screen using\n"
5826 "fbset. (default: 0)\n");
5828 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5829 MODULE_PARM_DESC(mode,
5830 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
5831 "1024x768x16. Other formats supported include XxY-Depth and\n"
5832 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5833 "number, it will be interpreted as a VESA mode number. (default: none if\n"
5834 "sisfb is a module; this leaves the console untouched and the driver will\n"
5835 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
5836 "is in the kernel)\n");
5837 MODULE_PARM_DESC(vesa,
5838 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
5839 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
5840 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
5841 "0x0103 if sisfb is in the kernel)\n");
5842 #endif
5844 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5845 MODULE_PARM_DESC(mode,
5846 "\nSelects the desired default display mode in the format XxYxDepth,\n"
5847 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
5848 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5849 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
5851 MODULE_PARM_DESC(vesa,
5852 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
5853 "0x117 (default: 0x0103)\n");
5854 #endif
5856 MODULE_PARM_DESC(rate,
5857 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
5858 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
5859 "will be ignored (default: 60)\n");
5861 MODULE_PARM_DESC(forcecrt1,
5862 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
5863 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
5864 "0=CRT1 OFF) (default: [autodetected])\n");
5866 MODULE_PARM_DESC(forcecrt2type,
5867 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
5868 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
5869 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
5870 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
5871 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
5872 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
5873 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
5874 "depends on the very hardware in use. (default: [autodetected])\n");
5876 MODULE_PARM_DESC(scalelcd,
5877 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
5878 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
5879 "show black bars around the image, TMDS panels will probably do the scaling\n"
5880 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
5882 MODULE_PARM_DESC(pdc,
5883 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
5884 "should detect this correctly in most cases; however, sometimes this is not\n"
5885 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
5886 "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
5887 "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
5888 "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
5890 #ifdef CONFIG_FB_SIS_315
5891 MODULE_PARM_DESC(pdc1,
5892 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
5893 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
5894 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
5895 "implemented yet.\n");
5896 #endif
5898 MODULE_PARM_DESC(specialtiming,
5899 "\nPlease refer to documentation for more information on this option.\n");
5901 MODULE_PARM_DESC(lvdshl,
5902 "\nPlease refer to documentation for more information on this option.\n");
5904 MODULE_PARM_DESC(tvstandard,
5905 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
5906 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
5908 MODULE_PARM_DESC(tvxposoffset,
5909 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
5910 "Default: 0\n");
5912 MODULE_PARM_DESC(tvyposoffset,
5913 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
5914 "Default: 0\n");
5916 MODULE_PARM_DESC(filter,
5917 "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
5918 "(Possible values 0-7, default: [no filter])\n");
5920 MODULE_PARM_DESC(nocrt2rate,
5921 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
5922 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
5924 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5925 MODULE_PARM_DESC(inverse,
5926 "\nSetting this to anything but 0 should invert the display colors, but this\n"
5927 "does not seem to work. (default: 0)\n");
5928 #endif
5930 #if !defined(__i386__) && !defined(__x86_64__)
5931 #ifdef CONFIG_FB_SIS_300
5932 MODULE_PARM_DESC(resetcard,
5933 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
5934 "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
5935 "Default: 0\n");
5937 MODULE_PARM_DESC(videoram,
5938 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
5939 "some non-x86 architectures where the memory auto detection fails. Only\n"
5940 "relevant if resetcard is set, too. Default: [auto-detect]\n");
5941 #endif
5942 #endif
5944 static int __devinit sisfb_init_module(void)
5946 sisfb_setdefaultparms();
5948 if(rate) sisfb_parm_rate = rate;
5950 if((scalelcd == 0) || (scalelcd == 1)) {
5951 sisfb_scalelcd = scalelcd ^ 1;
5954 /* Need to check crt2 type first for fstn/dstn */
5956 if(forcecrt2type)
5957 sisfb_search_crt2type(forcecrt2type);
5959 if(tvstandard)
5960 sisfb_search_tvstd(tvstandard);
5962 if(mode)
5963 sisfb_search_mode(mode, FALSE);
5964 else if(vesa != -1)
5965 sisfb_search_vesamode(vesa, FALSE);
5967 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
5969 sisfb_forcecrt1 = forcecrt1;
5970 if(forcecrt1 == 1) sisfb_crt1off = 0;
5971 else if(forcecrt1 == 0) sisfb_crt1off = 1;
5973 if(noaccel == 1) sisfb_accel = 0;
5974 else if(noaccel == 0) sisfb_accel = 1;
5976 if(noypan == 1) sisfb_ypan = 0;
5977 else if(noypan == 0) sisfb_ypan = 1;
5979 if(nomax == 1) sisfb_max = 0;
5980 else if(nomax == 0) sisfb_max = 1;
5982 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5983 if(inverse) sisfb_inverse = 1;
5984 #endif
5986 if(mem) sisfb_parm_mem = mem;
5988 if(userom != -1) sisfb_userom = userom;
5989 if(useoem != -1) sisfb_useoem = useoem;
5991 if(pdc != -1) sisfb_pdc = (pdc & 0x7f);
5992 if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
5994 sisfb_nocrt2rate = nocrt2rate;
5996 if(specialtiming)
5997 sisfb_search_specialtiming(specialtiming);
5999 if((lvdshl >= 0) && (lvdshl <= 3)) sisfb_lvdshl = lvdshl;
6001 if(filter != -1) sisfb_filter = filter;
6003 sisfb_tvxposoffset = tvxposoffset;
6004 sisfb_tvyposoffset = tvyposoffset;
6006 #if !defined(__i386__) && !defined(__x86_64__)
6007 sisfb_resetcard = (resetcard) ? 1 : 0;
6008 if(videoram) sisfb_videoram = videoram;
6009 #endif
6011 return(sisfb_init());
6014 static void __exit sisfb_remove_module(void)
6016 pci_unregister_driver(&sisfb_driver);
6017 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6020 module_init(sisfb_init_module);
6021 module_exit(sisfb_remove_module);
6023 #endif /* /MODULE */
6025 EXPORT_SYMBOL(sis_malloc);
6026 EXPORT_SYMBOL(sis_free);