2 * SiS 300/630/730/540/315/550/650/651/M650/661FX/M661FX/740/741/M741/330/760
3 * frame buffer driver for Linux kernels 2.4.x and 2.5.x
5 * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the named License,
10 * or any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
21 * Author: Thomas Winischhofer <thomas@winischhofer.net>
23 * Author of code base:
24 * SiS (www.sis.com.tw)
25 * Copyright (C) 1999 Silicon Integrated Systems, Inc.
27 * See http://www.winischhofer.net/ for more information and updates
29 * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
30 * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
34 #include <linux/config.h>
35 #include <linux/version.h>
36 #include <linux/module.h>
37 #include <linux/kernel.h>
38 #include <linux/errno.h>
39 #include <linux/string.h>
41 #include <linux/tty.h>
42 #include <linux/slab.h>
43 #include <linux/delay.h>
45 #include <linux/console.h>
46 #include <linux/selection.h>
47 #include <linux/ioport.h>
48 #include <linux/init.h>
49 #include <linux/pci.h>
50 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
51 #include <linux/vmalloc.h>
53 #include <linux/vt_kern.h>
54 #include <linux/capability.h>
56 #include <linux/agp_backend.h>
57 #include <linux/types.h>
58 #include <asm/uaccess.h>
60 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
61 #include <linux/spinlock.h>
66 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
67 #include <video/sisfb.h>
69 #include <linux/sisfb.h>
77 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
78 #include <video/fbcon.h>
79 #include <video/fbcon-cfb8.h>
80 #include <video/fbcon-cfb16.h>
81 #include <video/fbcon-cfb24.h>
82 #include <video/fbcon-cfb32.h>
89 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
90 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
91 #error "This version of sisfb requires at least 2.6.0"
94 #define NEWFBDEV /* Define this as soon as new fvdev code has been merged */
99 /* -------------------- Macro definitions ---------------------------- */
101 #undef SISFBDEBUG /* TW: no debugging */
104 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
106 #define DPRINTK(fmt, args...)
109 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
111 #ifdef FBCON_HAS_CFB8
112 extern struct display_switch fbcon_sis8;
114 #ifdef FBCON_HAS_CFB16
115 extern struct display_switch fbcon_sis16;
117 #ifdef FBCON_HAS_CFB32
118 extern struct display_switch fbcon_sis32;
123 /* --------------- Hardware Access Routines -------------------------- */
125 void sisfb_set_reg4(u16 port, unsigned long data)
127 outl((u32) (data & 0xffffffff), port);
130 u32 sisfb_get_reg3(u16 port)
138 /* ------------ Interface for init & mode switching code ------------- */
141 sisfb_query_VGA_config_space(PSIS_HW_INFO psishw_ext,
142 unsigned long offset, unsigned long set, unsigned long *value)
144 static struct pci_dev *pdev = NULL;
145 static unsigned char init = 0, valid_pdev = 0;
148 DPRINTK("sisfb: Get VGA offset 0x%lx\n", offset);
150 DPRINTK("sisfb: Set offset 0x%lx to 0x%lx\n", offset, *value);
154 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
155 pci_for_each_dev(pdev) {
157 while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
159 DPRINTK("sisfb: Current: 0x%x, target: 0x%x\n",
160 pdev->device, ivideo.chip_id);
161 if ((pdev->vendor == PCI_VENDOR_ID_SI)
162 && (pdev->device == ivideo.chip_id)) {
170 printk(KERN_DEBUG "sisfb: Can't find SiS %d VGA device.\n",
176 pci_read_config_dword(pdev, offset, (u32 *)value);
178 pci_write_config_dword(pdev, offset, (u32)(*value));
183 BOOLEAN sisfb_query_north_bridge_space(PSIS_HW_INFO psishw_ext,
184 unsigned long offset, unsigned long set, unsigned long *value)
186 static struct pci_dev *pdev = NULL;
187 static unsigned char init = 0, valid_pdev = 0;
192 switch (ivideo.chip) {
193 #ifdef CONFIG_FB_SIS_300
195 nbridge_id = PCI_DEVICE_ID_SI_540;
198 nbridge_id = PCI_DEVICE_ID_SI_630;
201 nbridge_id = PCI_DEVICE_ID_SI_730;
204 #ifdef CONFIG_FB_SIS_315
206 nbridge_id = PCI_DEVICE_ID_SI_550;
209 nbridge_id = PCI_DEVICE_ID_SI_650;
212 nbridge_id = PCI_DEVICE_ID_SI_740;
215 nbridge_id = PCI_DEVICE_ID_SI_660;
218 nbridge_id = PCI_DEVICE_ID_SI_741;
221 nbridge_id = PCI_DEVICE_ID_SI_660;
224 nbridge_id = PCI_DEVICE_ID_SI_760;
232 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
233 pci_for_each_dev(pdev) {
235 while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
237 DPRINTK("Current: 0x%x, target: 0x%x\n",
238 pdev->device, ivideo.chip_id);
239 if ((pdev->vendor == PCI_VENDOR_ID_SI)
240 && (pdev->device == nbridge_id)) {
248 printk(KERN_DEBUG "sisfb: Can't find SiS %d North Bridge device.\n",
254 pci_read_config_dword(pdev, offset, (u32 *)value);
256 pci_write_config_dword(pdev, offset, (u32)(*value));
261 /* ------------------ Internal helper routines ----------------- */
263 static BOOLEAN sisfb_verify_rate(struct sisfb_monitor *monitor, int mode_idx, int rate_idx, int rate)
266 unsigned int dclock, hsync;
268 if(!monitor->datavalid) return TRUE;
270 if(mode_idx < 0) return FALSE;
272 if(rate < (monitor->vmin - 1)) return FALSE;
273 if(rate > (monitor->vmax + 1)) return FALSE;
275 if(sisfb_gettotalfrommode(&SiS_Pr, &sishw_ext, sisbios_mode[mode_idx].mode_no,
276 &htotal, &vtotal, rate_idx)) {
277 dclock = (htotal * vtotal * rate) / 1000;
278 if(dclock > (monitor->dclockmax + 1000)) return FALSE;
279 hsync = dclock / htotal;
280 if(hsync < (monitor->hmin - 1)) return FALSE;
281 if(hsync > (monitor->hmax + 1)) return FALSE;
288 static BOOLEAN sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
290 int i, j, xres, yres, refresh, index;
293 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
294 buffer[2] != 0xff || buffer[3] != 0xff ||
295 buffer[4] != 0xff || buffer[5] != 0xff ||
296 buffer[6] != 0xff || buffer[7] != 0x00) {
297 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
301 if(buffer[0x12] != 0x01) {
302 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
307 monitor->feature = buffer[0x18];
309 if(!buffer[0x14] & 0x80) {
310 if(!(buffer[0x14] & 0x08)) {
311 printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n");
315 if(buffer[0x13] >= 0x01) {
316 /* EDID V1 rev 1 and 2: Search for monitor descriptor
321 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
322 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
323 buffer[j + 4] == 0x00) {
324 monitor->hmin = buffer[j + 7];
325 monitor->hmax = buffer[j + 8];
326 monitor->vmin = buffer[j + 5];
327 monitor->vmax = buffer[j + 6];
328 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
329 monitor->datavalid = TRUE;
336 if(!monitor->datavalid) {
337 /* Otherwise: Get a range from the list of supported
338 * Estabished Timings. This is not entirely accurate,
339 * because fixed frequency monitors are not supported
342 monitor->hmin = 65535; monitor->hmax = 0;
343 monitor->vmin = 65535; monitor->vmax = 0;
344 monitor->dclockmax = 0;
345 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
346 for(i = 0; i < 13; i++) {
347 if(emodes & sisfb_ddcsmodes[i].mask) {
348 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
349 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
350 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
351 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
352 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
356 for(i = 0; i < 8; i++) {
357 xres = (buffer[index] + 31) * 8;
358 switch(buffer[index + 1] & 0xc0) {
359 case 0xc0: yres = (xres * 9) / 16; break;
360 case 0x80: yres = (xres * 4) / 5; break;
361 case 0x40: yres = (xres * 3) / 4; break;
362 default: yres = xres; break;
364 refresh = (buffer[index + 1] & 0x3f) + 60;
365 if((xres >= 640) && (yres >= 480)) {
366 for(j = 0; j < 8; j++) {
367 if((xres == sisfb_ddcfmodes[j].x) &&
368 (yres == sisfb_ddcfmodes[j].y) &&
369 (refresh == sisfb_ddcfmodes[j].v)) {
370 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
371 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
372 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
373 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
374 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
380 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
381 monitor->datavalid = TRUE;
385 return(monitor->datavalid);
388 static void sisfb_handle_ddc(struct sisfb_monitor *monitor, int crtno)
390 USHORT temp, i, realcrtno = crtno;
393 monitor->datavalid = FALSE;
396 if(ivideo.vbflags & CRT2_LCD) realcrtno = 1;
397 else if(ivideo.vbflags & CRT2_VGA) realcrtno = 2;
401 if((sisfb_crt1off) && (!crtno)) return;
403 temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine, realcrtno, 0, &buffer[0]);
404 if((!temp) || (temp == 0xffff)) {
405 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
408 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
409 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
411 (temp & 0x1a) ? "" : "[none of the supported]",
412 (temp & 0x02) ? "2 " : "",
413 (temp & 0x08) ? "D&P" : "",
414 (temp & 0x10) ? "FPDI-2" : "");
416 i = 3; /* Number of retrys */
418 temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine,
419 realcrtno, 1, &buffer[0]);
420 } while((temp) && i--);
422 if(sisfb_interpret_edid(monitor, &buffer[0])) {
423 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
424 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
425 monitor->dclockmax / 1000);
427 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
430 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
433 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
438 static void sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
443 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
444 sisfb_mode_idx = MODE_INDEX_NONE;
447 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
448 sisfb_mode_idx = DEFAULT_MODE;
453 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
455 while(sisbios_mode[i++].mode_no != 0) {
456 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
457 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
459 if(sisbios_mode[i-1].mode_no == 0x50 ||
460 sisbios_mode[i-1].mode_no == 0x56 ||
461 sisbios_mode[i-1].mode_no == 0x53) continue;
463 if(sisbios_mode[i-1].mode_no == 0x5a ||
464 sisbios_mode[i-1].mode_no == 0x5b) continue;
466 sisfb_mode_idx = i - 1;
471 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
474 static void sisfb_search_mode(char *name, BOOLEAN quiet)
477 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
478 char strbuf[16], strbuf1[20];
479 char *nameptr = name;
483 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
484 sisfb_mode_idx = DEFAULT_MODE;
488 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
489 if (!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
491 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
492 sisfb_mode_idx = DEFAULT_MODE;
496 if(strlen(name) <= 19) {
497 strcpy(strbuf1, name);
498 for(i=0; i<strlen(strbuf1); i++) {
499 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
502 /* This does some fuzzy mode naming detection */
503 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
504 if((rate <= 32) || (depth > 32)) {
505 j = rate; rate = depth; depth = j;
507 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
509 ivideo.refresh_rate = sisfb_parm_rate = rate;
510 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
511 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
515 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
516 sprintf(strbuf, "%ux%ux8", xres, yres);
519 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
526 while(sisbios_mode[i].mode_no != 0) {
527 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
529 if(sisbios_mode[i-1].mode_no == 0x50 ||
530 sisbios_mode[i-1].mode_no == 0x56 ||
531 sisbios_mode[i-1].mode_no == 0x53) continue;
533 if(sisbios_mode[i-1].mode_no == 0x5a ||
534 sisbios_mode[i-1].mode_no == 0x5b) continue;
536 sisfb_mode_idx = i - 1;
541 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
545 static int sisfb_validate_mode(int myindex, unsigned long vbflags)
547 u16 xres, yres, myres;
549 #ifdef CONFIG_FB_SIS_300
550 if(sisvga_engine == SIS_300_VGA) {
551 if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1);
554 #ifdef CONFIG_FB_SIS_315
555 if(sisvga_engine == SIS_315_VGA) {
556 if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1);
560 myres = sisbios_mode[myindex].yres;
562 switch (vbflags & VB_DISPTYPE_DISP2) {
564 switch (sishw_ext.ulCRT2LCDType) {
565 case LCD_640x480: xres = 640; yres = 480; break;
566 case LCD_800x600: xres = 800; yres = 600; break;
567 case LCD_1024x600: xres = 1024; yres = 600; break;
568 case LCD_1024x768: xres = 1024; yres = 768; break;
569 case LCD_1152x768: xres = 1152; yres = 768; break;
570 case LCD_1280x960: xres = 1280; yres = 960; break;
571 case LCD_1280x768: xres = 1280; yres = 768; break;
572 case LCD_1280x1024:xres = 1280; yres = 1024; break;
573 case LCD_1400x1050:xres = 1400; yres = 1050; break;
574 case LCD_1600x1200:xres = 1600; yres = 1200; break;
575 case LCD_320x480: xres = 320; yres = 480; break; /* FSTN (old) */
577 case LCD_640x480_3:xres = 640; yres = 480; break; /* FSTN (new) */
578 default: xres = 0; yres = 0; break;
581 if(SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
582 xres = 1360; yres = 1024;
585 if(SiS_Pr.SiS_CustomT == CUT_PANEL848) {
586 xres = 848; yres = 480;
588 if(sisbios_mode[myindex].xres > xres) return(-1);
589 if(myres > yres) return(-1);
592 if(vbflags & (VB_LVDS | VB_30xBDH)) {
593 if(sisbios_mode[myindex].xres == 320) {
594 if((myres == 240) || (myres == 480)) {
596 if(sisbios_mode[myindex].mode_no == 0x5a ||
597 sisbios_mode[myindex].mode_no == 0x5b)
600 if(sisbios_mode[myindex].mode_no == 0x50 ||
601 sisbios_mode[myindex].mode_no == 0x56 ||
602 sisbios_mode[myindex].mode_no == 0x53)
609 if(SiS_GetModeID_LCD(sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres,
610 0, sisfb_fstn, SiS_Pr.SiS_CustomT, xres, yres) < 0x14) {
616 if(SiS_GetModeID_TV(sisvga_engine, vbflags, sisbios_mode[myindex].xres,
617 sisbios_mode[myindex].yres, 0) < 0x14) {
623 if(SiS_GetModeID_VGA2(sisvga_engine, vbflags, sisbios_mode[myindex].xres,
624 sisbios_mode[myindex].yres, 0) < 0x14) {
633 static void sisfb_search_crt2type(const char *name)
640 while(sis_crt2type[i].type_no != -1) {
641 if (!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
642 sisfb_crt2type = sis_crt2type[i].type_no;
643 sisfb_tvplug = sis_crt2type[i].tvplug_no;
644 sisfb_dstn = (sis_crt2type[i].flags & FL_550_DSTN) ? 1 : 0;
645 sisfb_fstn = (sis_crt2type[i].flags & FL_550_FSTN) ? 1 : 0;
650 if(sisfb_crt2type < 0)
651 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
652 if(ivideo.chip != SIS_550) {
653 sisfb_dstn = sisfb_fstn = 0;
657 static void sisfb_search_queuemode(const char *name)
664 while (sis_queuemode[i].type_no != -1) {
665 if (!strnicmp(name, sis_queuemode[i].name, strlen(sis_queuemode[i].name))) {
666 sisfb_queuemode = sis_queuemode[i].type_no;
671 if (sisfb_queuemode < 0)
672 printk(KERN_ERR "sisfb: Invalid queuemode type: %s\n", name);
675 static u8 sisfb_search_refresh_rate(unsigned int rate, int mode_idx)
680 xres = sisbios_mode[mode_idx].xres;
681 yres = sisbios_mode[mode_idx].yres;
684 while ((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
685 if ((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
686 if (sisfb_vrate[i].refresh == rate) {
687 sisfb_rate_idx = sisfb_vrate[i].idx;
689 } else if (sisfb_vrate[i].refresh > rate) {
690 if ((sisfb_vrate[i].refresh - rate) <= 3) {
691 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
692 rate, sisfb_vrate[i].refresh);
693 sisfb_rate_idx = sisfb_vrate[i].idx;
694 ivideo.refresh_rate = sisfb_vrate[i].refresh;
695 } else if (((rate - sisfb_vrate[i-1].refresh) <= 2)
696 && (sisfb_vrate[i].idx != 1)) {
697 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
698 rate, sisfb_vrate[i-1].refresh);
699 sisfb_rate_idx = sisfb_vrate[i-1].idx;
700 ivideo.refresh_rate = sisfb_vrate[i-1].refresh;
703 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
704 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
705 rate, sisfb_vrate[i].refresh);
706 sisfb_rate_idx = sisfb_vrate[i].idx;
712 if (sisfb_rate_idx > 0) {
713 return sisfb_rate_idx;
716 "sisfb: Unsupported rate %d for %dx%d\n", rate, xres, yres);
721 static void sisfb_search_tvstd(const char *name)
728 while (sis_tvtype[i].type_no != -1) {
729 if (!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
730 ivideo.vbflags |= sis_tvtype[i].type_no;
737 static void sisfb_search_specialtiming(const char *name)
740 BOOLEAN found = FALSE;
745 if(!strnicmp(name, "none", 4)) {
746 SiS_Pr.SiS_CustomT = CUT_FORCENONE;
747 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
749 while(mycustomttable[i].chipID != 0) {
750 if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {
751 SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
753 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
754 mycustomttable[i].vendorName, mycustomttable[i].cardName,
755 mycustomttable[i].optionName);
761 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
762 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
764 while(mycustomttable[i].chipID != 0) {
765 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
766 mycustomttable[i].optionName,
767 mycustomttable[i].vendorName,
768 mycustomttable[i].cardName);
775 static BOOLEAN sisfb_bridgeisslave(void)
779 if(!(ivideo.vbflags & VB_VIDEOBRIDGE)) return FALSE;
781 inSISIDXREG(SISPART1,0x00,P1_00);
782 if( ((sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
783 ((sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
790 static BOOLEAN sisfballowretracecrt1(void)
794 inSISIDXREG(SISCR,0x17,temp);
795 if(!(temp & 0x80)) return FALSE;
797 inSISIDXREG(SISSR,0x1f,temp);
798 if(temp & 0xc0) return FALSE;
803 static BOOLEAN sisfbcheckvretracecrt1(void)
806 if(!sisfballowretracecrt1()) return FALSE;
808 if(inSISREG(SISINPSTAT) & 0x08) return TRUE;
812 static void sisfbwaitretracecrt1(void)
816 if(!sisfballowretracecrt1()) return;
819 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
821 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
824 static BOOLEAN sisfbcheckvretracecrt2(void)
826 unsigned char temp, reg;
828 switch(sisvga_engine) {
839 inSISIDXREG(SISPART1, reg, temp);
840 if(temp & 0x02) return FALSE;
844 static BOOLEAN sisfb_CheckVBRetrace(void)
846 if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
847 if(sisfb_bridgeisslave()) {
848 return(sisfbcheckvretracecrt1());
850 return(sisfbcheckvretracecrt2());
853 return(sisfbcheckvretracecrt1());
856 static int sisfb_myblank(int blank)
858 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
859 BOOLEAN backlight = TRUE;
880 case 2: /* no vsync */
889 case 3: /* no hsync */
911 if(ivideo.currentvbflags & VB_DISPTYPE_CRT1) {
913 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
915 if( (!sisfb_thismonitor.datavalid) ||
916 ((sisfb_thismonitor.datavalid) &&
917 (sisfb_thismonitor.feature & 0xe0))) {
919 if(sisvga_engine == SIS_315_VGA) {
920 setSISIDXREG(SISCR, SiS_Pr.SiS_MyCR63, 0xbf, cr63);
923 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
928 if(ivideo.currentvbflags & CRT2_LCD) {
930 if(ivideo.vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
932 SiS_SiS30xBLOn(&SiS_Pr, &sishw_ext);
934 SiS_SiS30xBLOff(&SiS_Pr, &sishw_ext);
936 } else if(sisvga_engine == SIS_315_VGA) {
937 if(ivideo.vbflags & VB_CHRONTEL) {
939 SiS_Chrontel701xBLOn(&SiS_Pr,&sishw_ext);
941 SiS_Chrontel701xBLOff(&SiS_Pr);
946 if(((sisvga_engine == SIS_300_VGA) &&
947 (ivideo.vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
948 ((sisvga_engine == SIS_315_VGA) &&
949 ((ivideo.vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
950 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
953 if(sisvga_engine == SIS_300_VGA) {
954 if((ivideo.vbflags & (VB_301B|VB_301C|VB_302B)) &&
955 (!(ivideo.vbflags & VB_30xBDH))) {
956 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
958 } else if(sisvga_engine == SIS_315_VGA) {
959 if((ivideo.vbflags & (VB_301B|VB_301C|VB_302B)) &&
960 (!(ivideo.vbflags & VB_30xBDH))) {
961 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
965 } else if(ivideo.currentvbflags & CRT2_VGA) {
967 if(ivideo.vbflags & (VB_301B|VB_301C|VB_302B)) {
968 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
976 /* ----------- FBDev related routines for all series ----------- */
978 static void sisfb_set_vparms(void)
980 switch(ivideo.video_bpp) {
982 ivideo.DstColor = 0x0000;
983 ivideo.SiS310_AccelDepth = 0x00000000;
984 ivideo.video_cmap_len = 256;
987 ivideo.DstColor = 0x8000;
988 ivideo.SiS310_AccelDepth = 0x00010000;
989 ivideo.video_cmap_len = 16;
992 ivideo.DstColor = 0xC000;
993 ivideo.SiS310_AccelDepth = 0x00020000;
994 ivideo.video_cmap_len = 16;
997 ivideo.video_cmap_len = 16;
998 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo.video_bpp);
1004 static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
1005 struct fb_info *info)
1007 unsigned int htotal = 0, vtotal = 0;
1008 unsigned int drate = 0, hrate = 0;
1013 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1015 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1017 pixclock = var->pixclock;
1019 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1020 vtotal += var->yres;
1022 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1023 vtotal += var->yres;
1025 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1026 vtotal += var->yres;
1028 } else vtotal += var->yres;
1030 if(!(htotal) || !(vtotal)) {
1031 DPRINTK("sisfb: Invalid 'var' information\n");
1035 if(pixclock && htotal && vtotal) {
1036 drate = 1000000000 / pixclock;
1037 hrate = (drate * 1000) / htotal;
1038 ivideo.refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1039 } else ivideo.refresh_rate = 60;
1042 printk(KERN_DEBUG "sisfb: Change mode to %dx%dx%d-%dHz\n",
1043 var->xres,var->yres,var->bits_per_pixel,ivideo.refresh_rate);
1046 old_mode = sisfb_mode_idx;
1049 while( (sisbios_mode[sisfb_mode_idx].mode_no != 0) &&
1050 (sisbios_mode[sisfb_mode_idx].xres <= var->xres) ) {
1051 if( (sisbios_mode[sisfb_mode_idx].xres == var->xres) &&
1052 (sisbios_mode[sisfb_mode_idx].yres == var->yres) &&
1053 (sisbios_mode[sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1054 sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no;
1062 sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx, ivideo.currentvbflags);
1064 sisfb_mode_idx = -1;
1066 if(sisfb_mode_idx < 0) {
1067 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1068 var->yres, var->bits_per_pixel);
1069 sisfb_mode_idx = old_mode;
1073 if(sisfb_search_refresh_rate(ivideo.refresh_rate, sisfb_mode_idx) == 0) {
1074 sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
1075 ivideo.refresh_rate = 60;
1078 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1079 if(sisfb_thismonitor.datavalid) {
1080 if(!sisfb_verify_rate(&sisfb_thismonitor, sisfb_mode_idx,
1081 sisfb_rate_idx, ivideo.refresh_rate)) {
1082 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1087 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1088 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1092 sisfb_pre_setmode();
1094 if(SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
1095 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", sisfb_mode_no);
1099 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1101 ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp;
1102 ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres;
1103 ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres;
1104 ivideo.org_x = ivideo.org_y = 0;
1105 ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
1108 ivideo.accel = (var->accel_flags & FB_ACCELF_TEXT) ? -1 : 0;
1113 ivideo.current_width = ivideo.video_width;
1114 ivideo.current_height = ivideo.video_height;
1115 ivideo.current_bpp = ivideo.video_bpp;
1116 ivideo.current_htotal = htotal;
1117 ivideo.current_vtotal = vtotal;
1118 ivideo.current_pixclock = var->pixclock;
1119 ivideo.current_refresh_rate = ivideo.refresh_rate;
1120 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1121 sisfb_lastrates[sisfb_mode_no] = ivideo.refresh_rate;
1124 sisfb_post_setmode();
1130 static int sisfb_pan_var(struct fb_var_screeninfo *var)
1134 if (var->xoffset > (var->xres_virtual - var->xres)) {
1137 if(var->yoffset > (var->yres_virtual - var->yres)) {
1141 base = var->yoffset * var->xres_virtual + var->xoffset;
1143 /* calculate base bpp dep. */
1144 switch(var->bits_per_pixel) {
1156 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1158 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1159 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1160 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1161 if(sisvga_engine == SIS_315_VGA) {
1162 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1164 if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
1165 orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
1166 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1167 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1168 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1169 if(sisvga_engine == SIS_315_VGA) {
1170 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1176 static void sisfb_bpp_to_var(struct fb_var_screeninfo *var)
1178 switch(var->bits_per_pixel) {
1180 var->red.offset = var->green.offset = var->blue.offset = 0;
1181 var->red.length = var->green.length = var->blue.length = 6;
1182 ivideo.video_cmap_len = 256;
1185 var->red.offset = 11;
1186 var->red.length = 5;
1187 var->green.offset = 5;
1188 var->green.length = 6;
1189 var->blue.offset = 0;
1190 var->blue.length = 5;
1191 var->transp.offset = 0;
1192 var->transp.length = 0;
1193 ivideo.video_cmap_len = 16;
1196 var->red.offset = 16;
1197 var->red.length = 8;
1198 var->green.offset = 8;
1199 var->green.length = 8;
1200 var->blue.offset = 0;
1201 var->blue.length = 8;
1202 var->transp.offset = 24;
1203 var->transp.length = 8;
1204 ivideo.video_cmap_len = 16;
1209 void sis_dispinfo(struct ap_data *rec)
1211 rec->minfo.bpp = ivideo.video_bpp;
1212 rec->minfo.xres = ivideo.video_width;
1213 rec->minfo.yres = ivideo.video_height;
1214 rec->minfo.v_xres = ivideo.video_vwidth;
1215 rec->minfo.v_yres = ivideo.video_vheight;
1216 rec->minfo.org_x = ivideo.org_x;
1217 rec->minfo.org_y = ivideo.org_y;
1218 rec->minfo.vrate = ivideo.refresh_rate;
1219 rec->iobase = ivideo.vga_base - 0x30;
1220 rec->mem_size = ivideo.video_size;
1221 rec->disp_state = ivideo.disp_state;
1222 rec->version = (VER_MAJOR << 24) | (VER_MINOR << 16) | VER_LEVEL;
1223 rec->hasVB = ivideo.hasVB;
1224 rec->TV_type = ivideo.TV_type;
1225 rec->TV_plug = ivideo.TV_plug;
1226 rec->chip = ivideo.chip;
1227 rec->vbflags = ivideo.vbflags;
1228 rec->currentvbflags = ivideo.currentvbflags;
1231 /* ------------ FBDev related routines for 2.4 series ----------- */
1233 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
1235 static void sisfb_crtc_to_var(struct fb_var_screeninfo *var)
1237 u16 VRE, VBE, VRS, VBS, VDE, VT;
1238 u16 HRE, HBE, HRS, HBS, HDE, HT;
1239 u8 sr_data, cr_data, cr_data2, cr_data3, mr_data;
1240 int A, B, C, D, E, F, temp;
1241 unsigned int hrate, drate, maxyres;
1243 inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
1245 if(sr_data & SIS_INTERLACED_MODE)
1246 var->vmode = FB_VMODE_INTERLACED;
1248 var->vmode = FB_VMODE_NONINTERLACED;
1250 switch ((sr_data & 0x1C) >> 2) {
1251 case SIS_8BPP_COLOR_MODE:
1252 var->bits_per_pixel = 8;
1254 case SIS_16BPP_COLOR_MODE:
1255 var->bits_per_pixel = 16;
1257 case SIS_32BPP_COLOR_MODE:
1258 var->bits_per_pixel = 32;
1262 sisfb_bpp_to_var(var);
1264 inSISIDXREG(SISSR, 0x0A, sr_data);
1266 inSISIDXREG(SISCR, 0x06, cr_data);
1268 inSISIDXREG(SISCR, 0x07, cr_data2);
1270 VT = (cr_data & 0xFF) | ((u16) (cr_data2 & 0x01) << 8) |
1271 ((u16) (cr_data2 & 0x20) << 4) | ((u16) (sr_data & 0x01) << 10);
1274 inSISIDXREG(SISCR, 0x12, cr_data);
1276 VDE = (cr_data & 0xff) | ((u16) (cr_data2 & 0x02) << 7) |
1277 ((u16) (cr_data2 & 0x40) << 3) | ((u16) (sr_data & 0x02) << 9);
1280 inSISIDXREG(SISCR, 0x10, cr_data);
1282 VRS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x04) << 6) |
1283 ((u16) (cr_data2 & 0x80) << 2) | ((u16) (sr_data & 0x08) << 7);
1286 inSISIDXREG(SISCR, 0x15, cr_data);
1288 inSISIDXREG(SISCR, 0x09, cr_data3);
1290 if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE;
1292 VBS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x08) << 5) |
1293 ((u16) (cr_data3 & 0x20) << 4) | ((u16) (sr_data & 0x04) << 8);
1295 inSISIDXREG(SISCR, 0x16, cr_data);
1297 VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
1298 temp = VBE - ((E - 1) & 511);
1299 B = (temp > 0) ? temp : (temp + 512);
1301 inSISIDXREG(SISCR, 0x11, cr_data);
1303 VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
1304 temp = VRE - ((E + F - 1) & 31);
1305 C = (temp > 0) ? temp : (temp + 32);
1310 var->upper_margin = D;
1311 var->lower_margin = F;
1314 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1316 var->upper_margin <<= 1;
1317 var->lower_margin <<= 1;
1318 var->vsync_len <<= 1;
1319 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1321 var->upper_margin >>= 1;
1322 var->lower_margin >>= 1;
1323 var->vsync_len >>= 1;
1326 inSISIDXREG(SISSR, 0x0b, sr_data);
1328 inSISIDXREG(SISCR, 0x00, cr_data);
1330 HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
1333 inSISIDXREG(SISCR, 0x01, cr_data);
1335 HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
1338 inSISIDXREG(SISCR, 0x04, cr_data);
1340 HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
1343 inSISIDXREG(SISCR, 0x02, cr_data);
1345 HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
1347 inSISIDXREG(SISSR, 0x0c, sr_data);
1349 inSISIDXREG(SISCR, 0x03, cr_data);
1351 inSISIDXREG(SISCR, 0x05, cr_data2);
1353 HBE = (cr_data & 0x1f) | ((u16) (cr_data2 & 0x80) >> 2) |
1354 ((u16) (sr_data & 0x03) << 6);
1355 HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
1357 temp = HBE - ((E - 1) & 255);
1358 B = (temp > 0) ? temp : (temp + 256);
1360 temp = HRE - ((E + F + 3) & 63);
1361 C = (temp > 0) ? temp : (temp + 64);
1365 var->xres = var->xres_virtual = E * 8;
1367 if((var->xres == 320) &&
1368 (var->yres == 200 || var->yres == 240)) {
1369 /* Terrible hack, but the correct CRTC data for
1370 * these modes only produces a black screen...
1372 var->left_margin = (400 - 376);
1373 var->right_margin = (328 - 320);
1374 var->hsync_len = (376 - 328);
1376 var->left_margin = D * 8;
1377 var->right_margin = F * 8;
1378 var->hsync_len = C * 8;
1380 var->activate = FB_ACTIVATE_NOW;
1384 mr_data = inSISREG(SISMISCR);
1386 var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
1388 var->sync |= FB_SYNC_VERT_HIGH_ACT;
1391 var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
1393 var->sync |= FB_SYNC_HOR_HIGH_ACT;
1399 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1402 hrate = ivideo.refresh_rate * VT / 2;
1403 drate = (hrate * HT) / 1000;
1404 var->pixclock = (u32) (1000000000 / drate);
1407 maxyres = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));
1408 if(maxyres > 32767) maxyres = 32767;
1410 var->yres_virtual = maxyres;
1412 if(var->yres_virtual > maxyres) {
1413 var->yres_virtual = maxyres;
1416 if(var->yres_virtual <= var->yres) {
1417 var->yres_virtual = var->yres;
1420 var->yres_virtual = var->yres;
1424 static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
1425 unsigned *transp, struct fb_info *fb_info)
1427 if (regno >= ivideo.video_cmap_len)
1430 *red = sis_palette[regno].red;
1431 *green = sis_palette[regno].green;
1432 *blue = sis_palette[regno].blue;
1437 static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1438 unsigned transp, struct fb_info *fb_info)
1440 if (regno >= ivideo.video_cmap_len)
1443 sis_palette[regno].red = red;
1444 sis_palette[regno].green = green;
1445 sis_palette[regno].blue = blue;
1447 switch (ivideo.video_bpp) {
1448 #ifdef FBCON_HAS_CFB8
1450 outSISREG(SISDACA, regno);
1451 outSISREG(SISDACD, (red >> 10));
1452 outSISREG(SISDACD, (green >> 10));
1453 outSISREG(SISDACD, (blue >> 10));
1454 if (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
1455 outSISREG(SISDAC2A, regno);
1456 outSISREG(SISDAC2D, (red >> 8));
1457 outSISREG(SISDAC2D, (green >> 8));
1458 outSISREG(SISDAC2D, (blue >> 8));
1462 #ifdef FBCON_HAS_CFB16
1464 sis_fbcon_cmap.cfb16[regno] =
1465 ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1468 #ifdef FBCON_HAS_CFB32
1473 sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
1480 static void sisfb_set_disp(int con, struct fb_var_screeninfo *var,
1481 struct fb_info *info)
1483 struct fb_fix_screeninfo fix;
1485 struct display *display;
1486 struct display_switch *sw;
1489 display = &fb_display[con];
1491 display = &sis_disp;
1493 sisfb_get_fix(&fix, con, 0);
1495 display->screen_base = ivideo.video_vbase;
1496 display->visual = fix.visual;
1497 display->type = fix.type;
1498 display->type_aux = fix.type_aux;
1499 display->ypanstep = fix.ypanstep;
1500 display->ywrapstep = fix.ywrapstep;
1501 display->line_length = fix.line_length;
1502 display->next_line = fix.line_length;
1503 display->can_soft_blank = 1;
1504 display->inverse = sisfb_inverse;
1505 display->var = *var;
1509 switch (ivideo.video_bpp) {
1510 #ifdef FBCON_HAS_CFB8
1513 sw = ivideo.accel ? &fbcon_sis8 : &fbcon_cfb8;
1519 #ifdef FBCON_HAS_CFB16
1522 sw = ivideo.accel ? &fbcon_sis16 : &fbcon_cfb16;
1526 display->dispsw_data = sis_fbcon_cmap.cfb16;
1529 #ifdef FBCON_HAS_CFB32
1532 sw = ivideo.accel ? &fbcon_sis32 : &fbcon_cfb32;
1536 display->dispsw_data = sis_fbcon_cmap.cfb32;
1543 memcpy(&sisfb_sw, sw, sizeof(*sw));
1544 display->dispsw = &sisfb_sw;
1545 restore_flags(flags);
1548 /* display->scrollmode = 0; */
1550 display->scrollmode = SCROLL_YREDRAW;
1551 sisfb_sw.bmove = fbcon_redraw_bmove;
1555 static void sisfb_do_install_cmap(int con, struct fb_info *info)
1560 if (fb_display[con].cmap.len)
1561 fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
1563 fb_set_cmap(fb_default_cmap(ivideo.video_cmap_len), 1,
1564 sisfb_setcolreg, info);
1568 static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
1569 struct fb_info *info)
1572 memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
1574 *var = fb_display[con].var;
1577 if (var->xres == 320 && var->yres == 480)
1584 static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
1585 struct fb_info *info)
1588 unsigned int cols, rows;
1590 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1591 if(sisfb_do_set_var(var, con == currcon, info)) {
1592 sisfb_crtc_to_var(var);
1596 sisfb_crtc_to_var(var);
1598 sisfb_set_disp(con, var, info);
1601 (*info->changevar) (con);
1603 if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
1606 sisfb_do_install_cmap(con, info);
1608 cols = sisbios_mode[sisfb_mode_idx].cols;
1609 rows = sisbios_mode[sisfb_mode_idx].rows;
1611 /* Why was this called here? */
1612 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1618 static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
1619 struct fb_info *info)
1622 return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
1624 else if (fb_display[con].cmap.len)
1625 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
1627 fb_copy_cmap(fb_default_cmap(ivideo.video_cmap_len), cmap, kspc ? 0 : 2);
1632 static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
1633 struct fb_info *info)
1637 if (!fb_display[con].cmap.len) {
1638 err = fb_alloc_cmap(&fb_display[con].cmap, ivideo.video_cmap_len, 0);
1644 return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
1647 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
1652 static int sisfb_pan_display(struct fb_var_screeninfo *var, int con,
1653 struct fb_info* info)
1657 if (var->vmode & FB_VMODE_YWRAP) {
1658 if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
1661 if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
1662 var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
1666 if(con == currcon) {
1667 if((err = sisfb_pan_var(var)) < 0) return err;
1670 fb_display[con].var.xoffset = var->xoffset;
1671 fb_display[con].var.yoffset = var->yoffset;
1672 if (var->vmode & FB_VMODE_YWRAP)
1673 fb_display[con].var.vmode |= FB_VMODE_YWRAP;
1675 fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
1680 static int sisfb_mmap(struct fb_info *info, struct file *file,
1681 struct vm_area_struct *vma)
1683 struct fb_var_screeninfo var;
1684 unsigned long start;
1688 if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL;
1690 off = vma->vm_pgoff << PAGE_SHIFT;
1692 start = (unsigned long) ivideo.video_base;
1693 len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
1698 /* By Jake Page: Treat mmap request with offset beyond heapstart
1699 * as request for mapping the mmio area
1701 mmio_off = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.heapstart);
1702 if(off >= mmio_off) {
1704 sisfb_get_var(&var, currcon, info);
1705 if(var.accel_flags) return -EINVAL;
1707 start = (unsigned long) ivideo.mmio_base;
1708 len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);
1712 if((vma->vm_end - vma->vm_start + off) > len) return -EINVAL;
1715 vma->vm_pgoff = off >> PAGE_SHIFT;
1716 vma->vm_flags |= VM_IO; /* by Jake Page; is that really needed? */
1718 #if defined(__i386__) || defined(__x86_64__)
1719 if (boot_cpu_data.x86 > 3)
1720 pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
1722 /* RedHat requires vma as the first paramater to the following call */
1723 if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
1730 static void sis_get_glyph(struct fb_info *info, SIS_GLYINFO *gly)
1732 struct display *p = &fb_display[currcon];
1736 u8 *gbuf = gly->gmask;
1739 gly->fontheight = fontheight(p);
1740 gly->fontwidth = fontwidth(p);
1741 widthb = (fontwidth(p) + 7) / 8;
1743 c = gly->ch & p->charmask;
1744 if (fontwidth(p) <= 8)
1745 cdat = p->fontdata + c * fontheight(p);
1747 cdat = p->fontdata + (c * fontheight(p) << 1);
1749 size = fontheight(p) * widthb;
1750 memcpy(gbuf, cdat, size);
1754 static int sisfb_update_var(int con, struct fb_info *info)
1756 return(sisfb_pan_var(&fb_display[con].var));
1759 static int sisfb_switch(int con, struct fb_info *info)
1763 if(fb_display[currcon].cmap.len)
1764 fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
1766 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1768 if(!memcmp(&fb_display[con].var, &fb_display[currcon].var,
1769 sizeof(struct fb_var_screeninfo))) {
1776 sisfb_do_set_var(&fb_display[con].var, 1, info);
1778 sisfb_set_disp(con, &fb_display[con].var, info);
1780 sisfb_do_install_cmap(con, info);
1782 cols = sisbios_mode[sisfb_mode_idx].cols;
1783 rows = sisbios_mode[sisfb_mode_idx].rows;
1784 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1786 sisfb_update_var(con, info);
1791 static void sisfb_blank(int blank, struct fb_info *info)
1793 sisfb_myblank(blank);
1797 /* ------------ FBDev related routines for 2.5 series ----------- */
1799 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1801 static int sisfb_open(struct fb_info *info, int user)
1806 static int sisfb_release(struct fb_info *info, int user)
1811 static int sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1815 switch(var->bits_per_pixel) {
1827 static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1828 unsigned transp, struct fb_info *info)
1830 if (regno >= sisfb_get_cmap_len(&info->var))
1833 switch (info->var.bits_per_pixel) {
1835 outSISREG(SISDACA, regno);
1836 outSISREG(SISDACD, (red >> 10));
1837 outSISREG(SISDACD, (green >> 10));
1838 outSISREG(SISDACD, (blue >> 10));
1839 if (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
1840 outSISREG(SISDAC2A, regno);
1841 outSISREG(SISDAC2D, (red >> 8));
1842 outSISREG(SISDAC2D, (green >> 8));
1843 outSISREG(SISDAC2D, (blue >> 8));
1847 ((u32 *)(info->pseudo_palette))[regno] =
1848 ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1854 ((u32 *) (info->pseudo_palette))[regno] =
1855 (red << 16) | (green << 8) | (blue);
1861 static int sisfb_set_par(struct fb_info *info)
1865 if((err = sisfb_do_set_var(&info->var, 1, info)))
1868 sisfb_get_fix(&info->fix, info->currcon, info);
1873 static int sisfb_check_var(struct fb_var_screeninfo *var,
1874 struct fb_info *info)
1876 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1877 unsigned int drate = 0, hrate = 0, maxyres;
1879 int refresh_rate, search_idx;
1880 BOOLEAN recalc_clock = FALSE;
1883 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1885 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1887 pixclock = var->pixclock;
1889 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1890 vtotal += var->yres;
1892 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1893 vtotal += var->yres;
1895 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1896 vtotal += var->yres;
1898 } else vtotal += var->yres;
1900 if(!(htotal) || !(vtotal)) {
1901 SISFAIL("sisfb: no valid timing data");
1905 while( (sisbios_mode[search_idx].mode_no != 0) &&
1906 (sisbios_mode[search_idx].xres <= var->xres) ) {
1907 if( (sisbios_mode[search_idx].xres == var->xres) &&
1908 (sisbios_mode[search_idx].yres == var->yres) &&
1909 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1910 if(sisfb_validate_mode(search_idx, ivideo.currentvbflags) > 0) {
1921 while(sisbios_mode[search_idx].mode_no != 0) {
1922 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1923 (var->yres <= sisbios_mode[search_idx].yres) &&
1924 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1925 if(sisfb_validate_mode(search_idx, ivideo.currentvbflags) > 0) {
1933 printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1934 var->xres, var->yres, var->bits_per_pixel,
1935 sisbios_mode[search_idx].xres,
1936 sisbios_mode[search_idx].yres,
1937 var->bits_per_pixel);
1938 var->xres = sisbios_mode[search_idx].xres;
1939 var->yres = sisbios_mode[search_idx].yres;
1943 printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n",
1944 var->xres, var->yres, var->bits_per_pixel);
1949 if( ((ivideo.vbflags & VB_LVDS) || /* Slave modes on LVDS and 301B-DH */
1950 ((ivideo.vbflags & VB_30xBDH) && (ivideo.currentvbflags & CRT2_LCD))) &&
1951 (var->bits_per_pixel == 8) ) {
1953 recalc_clock = TRUE;
1954 } else if( (ivideo.current_htotal == htotal) && /* x=x & y=y & c=c -> assume depth change */
1955 (ivideo.current_vtotal == vtotal) &&
1956 (ivideo.current_pixclock == pixclock) ) {
1957 drate = 1000000000 / pixclock;
1958 hrate = (drate * 1000) / htotal;
1959 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1960 } else if( ( (ivideo.current_htotal != htotal) || /* x!=x | y!=y & c=c -> invalid pixclock */
1961 (ivideo.current_vtotal != vtotal) ) &&
1962 (ivideo.current_pixclock == var->pixclock) ) {
1963 if(sisfb_lastrates[sisbios_mode[search_idx].mode_no]) {
1964 refresh_rate = sisfb_lastrates[sisbios_mode[search_idx].mode_no];
1965 } else if(sisfb_parm_rate != -1) {
1966 refresh_rate = sisfb_parm_rate;
1970 recalc_clock = TRUE;
1971 } else if((pixclock) && (htotal) && (vtotal)) {
1972 drate = 1000000000 / pixclock;
1973 hrate = (drate * 1000) / htotal;
1974 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1975 } else if(ivideo.current_refresh_rate) {
1976 refresh_rate = ivideo.current_refresh_rate;
1977 recalc_clock = TRUE;
1980 recalc_clock = TRUE;
1983 myrateindex = sisfb_search_refresh_rate(refresh_rate, search_idx);
1985 /* Eventually recalculate timing and clock */
1987 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1988 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&SiS_Pr, &sishw_ext,
1989 sisbios_mode[search_idx].mode_no, myrateindex));
1990 sisfb_mode_rate_to_ddata(&SiS_Pr, &sishw_ext,
1991 sisbios_mode[search_idx].mode_no, myrateindex,
1992 &var->left_margin, &var->right_margin,
1993 &var->upper_margin, &var->lower_margin,
1994 &var->hsync_len, &var->vsync_len,
1995 &var->sync, &var->vmode);
1996 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1997 var->pixclock <<= 1;
2001 if(sisfb_thismonitor.datavalid) {
2002 if(!sisfb_verify_rate(&sisfb_thismonitor, search_idx,
2003 myrateindex, refresh_rate)) {
2004 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
2008 /* Adapt RGB settings */
2009 sisfb_bpp_to_var(var);
2011 /* Sanity check for offsets */
2012 if (var->xoffset < 0)
2014 if (var->yoffset < 0)
2017 /* Horiz-panning not supported */
2018 if(var->xres != var->xres_virtual)
2019 var->xres_virtual = var->xres;
2022 maxyres = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));
2023 if(maxyres > 32767) maxyres = 32767;
2025 var->yres_virtual = maxyres;
2027 if(var->yres_virtual > maxyres) {
2028 var->yres_virtual = maxyres;
2031 if(var->yres_virtual <= var->yres) {
2032 var->yres_virtual = var->yres;
2035 if(var->yres != var->yres_virtual) {
2036 var->yres_virtual = var->yres;
2042 /* Truncate offsets to maximum if too high */
2043 if(var->xoffset > var->xres_virtual - var->xres)
2044 var->xoffset = var->xres_virtual - var->xres - 1;
2046 if(var->yoffset > var->yres_virtual - var->yres)
2047 var->yoffset = var->yres_virtual - var->yres - 1;
2049 /* Set everything else to 0 */
2050 var->red.msb_right =
2051 var->green.msb_right =
2052 var->blue.msb_right =
2053 var->transp.offset = var->transp.length = var->transp.msb_right = 0;
2058 static int sisfb_pan_display(struct fb_var_screeninfo *var,
2059 struct fb_info* info)
2063 if (var->xoffset > (var->xres_virtual - var->xres))
2065 if (var->yoffset > (var->yres_virtual - var->yres))
2068 if (var->vmode & FB_VMODE_YWRAP) {
2069 if (var->yoffset < 0 ||
2070 var->yoffset >= info->var.yres_virtual ||
2074 if (var->xoffset + info->var.xres > info->var.xres_virtual ||
2075 var->yoffset + info->var.yres > info->var.yres_virtual)
2079 if((err = sisfb_pan_var(var)) < 0) return err;
2081 info->var.xoffset = var->xoffset;
2082 info->var.yoffset = var->yoffset;
2083 if (var->vmode & FB_VMODE_YWRAP)
2084 info->var.vmode |= FB_VMODE_YWRAP;
2086 info->var.vmode &= ~FB_VMODE_YWRAP;
2091 static int sisfb_mmap(struct fb_info *info, struct file *file,
2092 struct vm_area_struct *vma)
2094 unsigned long start;
2098 if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL;
2100 off = vma->vm_pgoff << PAGE_SHIFT;
2102 start = (unsigned long) ivideo.video_base;
2103 len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
2108 /* By Jake Page: Treat mmap request with offset beyond heapstart
2109 * as request for mapping the mmio area
2111 mmio_off = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.heapstart);
2112 if(off >= mmio_off) {
2114 if(info->var.accel_flags) return -EINVAL;
2116 start = (unsigned long) ivideo.mmio_base;
2117 len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);
2121 if((vma->vm_end - vma->vm_start + off) > len) return -EINVAL;
2124 vma->vm_pgoff = off >> PAGE_SHIFT;
2125 vma->vm_flags |= VM_IO; /* by Jake Page; is that really needed? */
2127 #if defined(__i386__) || defined(__x86_64__)
2128 if (boot_cpu_data.x86 > 3)
2129 pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
2131 if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start,
2138 static int sisfb_blank(int blank, struct fb_info *info)
2140 return(sisfb_myblank(blank));
2145 /* ----------- FBDev related routines for all series ---------- */
2148 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
2149 static int sisfb_ioctl(struct inode *inode, struct file *file,
2150 unsigned int cmd, unsigned long arg,
2151 struct fb_info *info)
2153 static int sisfb_ioctl(struct inode *inode, struct file *file,
2154 unsigned int cmd, unsigned long arg, int con,
2155 struct fb_info *info)
2158 struct sis_memreq sismemreq;
2159 struct ap_data sisapdata;
2160 unsigned long sismembase = 0;
2161 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2162 SIS_GLYINFO sisglyinfo;
2167 if(!capable(CAP_SYS_RAWIO))
2169 if(copy_from_user(&sismemreq, (void *)arg, sizeof(sismemreq)))
2171 sis_malloc(&sismemreq);
2172 if(copy_to_user((void *)arg, &sismemreq, sizeof(sismemreq))) {
2173 sis_free(sismemreq.offset);
2178 if(!capable(CAP_SYS_RAWIO))
2180 if(get_user(sismembase, (unsigned long *) arg))
2182 sis_free(sismembase);
2184 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2186 if(copy_from_user(&sisglyinfo, (void *)arg, sizeof(sisglyinfo)))
2188 sis_get_glyph(info, &sisglyinfo);
2190 case FBIOPUT_MODEINFO:
2194 if(copy_from_user(&x, (void *)arg, sizeof(x)))
2197 ivideo.video_bpp = x.bpp;
2198 ivideo.video_width = x.xres;
2199 ivideo.video_height = x.yres;
2200 ivideo.video_vwidth = x.v_xres;
2201 ivideo.video_vheight = x.v_yres;
2202 ivideo.org_x = x.org_x;
2203 ivideo.org_y = x.org_y;
2204 ivideo.refresh_rate = x.vrate;
2205 ivideo.video_linelength = ivideo.video_vwidth * (ivideo.video_bpp >> 3);
2210 case FBIOGET_HWCINFO:
2212 unsigned long myhwcoffset = 0;
2214 if(sisfb_caps & HW_CURSOR_CAP)
2215 myhwcoffset = sisfb_hwcursor_vbase -
2216 (unsigned long) ivideo.video_vbase;
2218 return put_user(myhwcoffset, (unsigned long *)arg);
2222 case FBIOGET_DISPINFO:
2223 sis_dispinfo(&sisapdata);
2224 if(copy_to_user((void *)arg, &sisapdata, sizeof(sisapdata)))
2227 case SISFB_GET_INFO: /* For communication with X driver */
2231 x.sisfb_id = SISFB_ID;
2232 x.sisfb_version = VER_MAJOR;
2233 x.sisfb_revision = VER_MINOR;
2234 x.sisfb_patchlevel = VER_LEVEL;
2235 x.chip_id = ivideo.chip_id;
2236 x.memory = ivideo.video_size / 1024;
2237 x.heapstart = ivideo.heapstart / 1024;
2238 x.fbvidmode = sisfb_mode_no;
2239 x.sisfb_caps = sisfb_caps;
2240 x.sisfb_tqlen = 512; /* yet fixed */
2241 x.sisfb_pcibus = ivideo.pcibus;
2242 x.sisfb_pcislot = ivideo.pcislot;
2243 x.sisfb_pcifunc = ivideo.pcifunc;
2244 x.sisfb_lcdpdc = sisfb_detectedpdc;
2245 x.sisfb_lcda = sisfb_detectedlcda;
2246 x.sisfb_vbflags = ivideo.vbflags;
2247 x.sisfb_currentvbflags = ivideo.currentvbflags;
2248 x.sisfb_scalelcd = SiS_Pr.UsePanelScaler;
2249 x.sisfb_specialtiming = SiS_Pr.SiS_CustomT;
2250 x.sisfb_haveemi = SiS_Pr.HaveEMI ? 1 : 0;
2251 x.sisfb_haveemilcd = SiS_Pr.HaveEMILCD ? 1 : 0;
2252 x.sisfb_emi30 = SiS_Pr.EMI_30;
2253 x.sisfb_emi31 = SiS_Pr.EMI_31;
2254 x.sisfb_emi32 = SiS_Pr.EMI_32;
2255 x.sisfb_emi33 = SiS_Pr.EMI_33;
2256 if(copy_to_user((void *)arg, &x, sizeof(x)))
2260 case SISFB_GET_VBRSTATUS:
2262 if(sisfb_CheckVBRetrace())
2263 return put_user(1UL, (unsigned long *) arg);
2265 return put_user(0UL, (unsigned long *) arg);
2268 case SISFB_GET_AUTOMAXIMIZE:
2271 return put_user(1UL, (unsigned long *) arg);
2273 return put_user(0UL, (unsigned long *) arg);
2276 case SISFB_SET_AUTOMAXIMIZE:
2278 unsigned long newmax;
2280 if(copy_from_user(&newmax, (unsigned long *)arg, sizeof(newmax)))
2283 if(newmax) sisfb_max = 1;
2294 static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
2295 struct fb_info *info)
2297 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2299 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2300 strcpy(fix->id, sis_fb_info->modename);
2302 strcpy(fix->id, myid);
2305 fix->smem_start = ivideo.video_base;
2307 if((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
2308 if(sisvga_engine == SIS_300_VGA) {
2309 if(ivideo.video_size > 0x1000000) {
2310 fix->smem_len = 0xc00000;
2311 } else if(ivideo.video_size > 0x800000)
2312 fix->smem_len = 0x800000;
2314 fix->smem_len = 0x400000;
2316 fix->smem_len = ivideo.video_size - 0x100000;
2319 fix->smem_len = sisfb_mem * 1024;
2321 fix->type = FB_TYPE_PACKED_PIXELS;
2323 if(ivideo.video_bpp == 8)
2324 fix->visual = FB_VISUAL_PSEUDOCOLOR;
2326 fix->visual = FB_VISUAL_TRUECOLOR;
2329 if(sisfb_ypan) fix->ypanstep = 1;
2332 fix->line_length = ivideo.video_linelength;
2333 fix->mmio_start = ivideo.mmio_base;
2334 fix->mmio_len = sisfb_mmio_size;
2335 if(sisvga_engine == SIS_300_VGA)
2336 fix->accel = FB_ACCEL_SIS_GLAMOUR;
2337 else if((ivideo.chip == SIS_330) || (ivideo.chip == SIS_760))
2338 fix->accel = FB_ACCEL_SIS_XABRE;
2340 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
2342 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2343 fix->reserved[0] = ivideo.video_size & 0xFFFF;
2344 fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
2345 fix->reserved[2] = sisfb_caps;
2351 /* ---------------- fb_ops structures ----------------- */
2353 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2354 static struct fb_ops sisfb_ops = {
2355 .owner = THIS_MODULE,
2356 .fb_get_fix = sisfb_get_fix,
2357 .fb_get_var = sisfb_get_var,
2358 .fb_set_var = sisfb_set_var,
2359 .fb_get_cmap = sisfb_get_cmap,
2360 .fb_set_cmap = sisfb_set_cmap,
2361 .fb_pan_display = sisfb_pan_display,
2362 .fb_ioctl = sisfb_ioctl,
2363 .fb_mmap = sisfb_mmap,
2368 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
2369 static struct fb_ops sisfb_ops = {
2370 .owner = THIS_MODULE,
2371 .fb_open = sisfb_open,
2372 .fb_release = sisfb_release,
2373 .fb_check_var = sisfb_check_var,
2374 .fb_set_par = sisfb_set_par,
2375 .fb_setcolreg = sisfb_setcolreg,
2376 .fb_pan_display = sisfb_pan_display,
2377 .fb_blank = sisfb_blank,
2378 .fb_fillrect = fbcon_sis_fillrect,
2379 .fb_copyarea = fbcon_sis_copyarea,
2380 .fb_imageblit = cfb_imageblit,
2381 .fb_cursor = soft_cursor,
2382 .fb_sync = fbcon_sis_sync,
2383 .fb_ioctl = sisfb_ioctl,
2384 .fb_mmap = sisfb_mmap,
2389 /* ---------------- Chip generation dependent routines ---------------- */
2391 #ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */
2393 static int sisfb_get_dram_size_300(void)
2395 struct pci_dev *pdev = NULL;
2400 switch (ivideo.chip) {
2402 nbridge_id = PCI_DEVICE_ID_SI_540;
2405 nbridge_id = PCI_DEVICE_ID_SI_630;
2408 nbridge_id = PCI_DEVICE_ID_SI_730;
2415 if (nbridge_id == 0) { /* 300 */
2417 inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE,reg);
2419 ((unsigned int) ((reg & SIS_DRAM_SIZE_MASK) + 1) << 20);
2421 } else { /* 540, 630, 730 */
2423 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
2424 pci_for_each_dev(pdev) {
2426 while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
2428 if ((pdev->vendor == PCI_VENDOR_ID_SI)
2429 && (pdev->device == nbridge_id)) {
2430 pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data);
2431 pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
2432 ivideo.video_size = (unsigned int)(1 << (pci_data+21));
2435 reg = SIS_DATA_BUS_64 << 6;
2437 case BRI_DRAM_SIZE_2MB:
2438 reg |= SIS_DRAM_SIZE_2MB;
2440 case BRI_DRAM_SIZE_4MB:
2441 reg |= SIS_DRAM_SIZE_4MB;
2443 case BRI_DRAM_SIZE_8MB:
2444 reg |= SIS_DRAM_SIZE_8MB;
2446 case BRI_DRAM_SIZE_16MB:
2447 reg |= SIS_DRAM_SIZE_16MB;
2449 case BRI_DRAM_SIZE_32MB:
2450 reg |= SIS_DRAM_SIZE_32MB;
2452 case BRI_DRAM_SIZE_64MB:
2453 reg |= SIS_DRAM_SIZE_64MB;
2456 outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
2461 if (!pdev_valid) return -1;
2466 #endif /* CONFIG_FB_SIS_300 */
2469 #ifdef CONFIG_FB_SIS_315 /* for SiS 315/550/650/740/330/661/741/760 */
2471 static int sisfb_get_dram_size_315(void)
2475 if(ivideo.chip == SIS_550 ||
2476 ivideo.chip == SIS_650 ||
2477 ivideo.chip == SIS_740) {
2479 inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
2483 ivideo.video_size = reg << 20;
2486 } else if(ivideo.chip == SIS_661 ||
2487 ivideo.chip == SIS_741 ||
2488 ivideo.chip == SIS_660 ||
2489 ivideo.chip == SIS_760) {
2491 inSISIDXREG(SISCR, 0x79, reg);
2494 ivideo.video_size = (1 << reg) << 20;
2497 } else { /* 315, 330 */
2499 inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
2500 ivideo.video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2502 reg &= SIS315_DUAL_CHANNEL_MASK;
2505 if(ivideo.chip == SIS_330) {
2507 if(reg) ivideo.video_size <<= 1;
2512 case SIS315_SINGLE_CHANNEL_2_RANK:
2513 ivideo.video_size <<= 1;
2515 case SIS315_DUAL_CHANNEL_1_RANK:
2516 ivideo.video_size <<= 1;
2518 case SIS315_ASYM_DDR: /* TW: DDR asymetric */
2519 ivideo.video_size += (ivideo.video_size/2);
2531 #endif /* CONFIG_FB_SIS_315 */
2534 /* -------------- video bridge detection --------------- */
2536 static void sisfb_detect_VB_connect()
2538 u8 sr16, sr17, cr32, temp;
2540 if(sisvga_engine == SIS_300_VGA) {
2542 inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_17, sr17);
2544 if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) {
2546 /* Old BIOSes store the detected CRT2 type in SR17
2547 * instead of CR32. However, since our detection
2548 * routines store their results to CR32, we now copy
2549 * the remaining bits (for LCD and VGA) to CR32 for
2551 * SR17[0] CRT1 [1] LCD [2] TV [3] VGA2
2552 * [4] AVIDEO [5] SVIDEO
2556 if (sr17 & 0x01) orSISIDXREG(SISCR, 0x32, SIS_CRT1);
2557 else andSISIDXREG(SISCR, 0x32, ~SIS_CRT1);
2559 if (sr17 & 0x02) orSISIDXREG(SISCR, 0x32, SIS_VB_LCD);
2560 else andSISIDXREG(SISCR, 0x32, ~SIS_VB_LCD);
2562 /* no HiVision and no DVI connector here */
2563 andSISIDXREG(SISCR, 0x32, ~0xc0);
2566 /* PAL/NTSC is stored on SR16 on such machines */
2567 if (!(ivideo.vbflags & (TV_PAL | TV_NTSC))) {
2568 inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_16, sr16);
2570 ivideo.vbflags |= TV_PAL;
2572 ivideo.vbflags |= TV_NTSC;
2579 inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32);
2581 if (cr32 & SIS_CRT1)
2590 ivideo.vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2592 if (cr32 & SIS_VB_TV)
2593 ivideo.vbflags |= CRT2_TV;
2594 if (cr32 & SIS_VB_LCD)
2595 ivideo.vbflags |= CRT2_LCD;
2596 if (cr32 & SIS_VB_CRT2)
2597 ivideo.vbflags |= CRT2_VGA;
2599 /* TW: Detect/set TV plug & type */
2600 if(sisfb_tvplug != -1)
2601 ivideo.vbflags |= sisfb_tvplug;
2603 if (cr32 & SIS_VB_SVIDEO)
2604 ivideo.vbflags |= TV_SVIDEO;
2605 else if (cr32 & SIS_VB_COMPOSITE)
2606 ivideo.vbflags |= TV_AVIDEO;
2607 else if (cr32 & SIS_VB_SCART)
2608 ivideo.vbflags |= TV_SCART;
2610 if (!(ivideo.vbflags & (TV_PAL | TV_NTSC))) {
2611 if(sisvga_engine == SIS_300_VGA) {
2612 inSISIDXREG(SISSR, IND_SIS_POWER_ON_TRAP, temp);
2614 ivideo.vbflags |= TV_PAL;
2616 ivideo.vbflags |= TV_NTSC;
2617 } else if((ivideo.chip <= SIS_315PRO) || (ivideo.chip >= SIS_330)) {
2619 inSISIDXREG(SISSR, 0x38, temp);
2621 ivideo.vbflags |= TV_PAL;
2623 ivideo.vbflags |= TV_NTSC;
2627 inSISIDXREG(SISCR, 0x79, temp);
2629 ivideo.vbflags |= TV_PAL;
2631 ivideo.vbflags |= TV_NTSC;
2635 /* TW: Copy forceCRT1 option to CRT1off if option is given */
2636 if (sisfb_forcecrt1 != -1) {
2637 if(sisfb_forcecrt1) sisfb_crt1off = 0;
2638 else sisfb_crt1off = 1;
2643 static void sisfb_get_VB_type(void)
2647 char stdstr[] = "sisfb: Detected";
2648 char bridgestr[] = "video bridge";
2649 char lvdsstr[] = "LVDS transmitter";
2650 char chrstr[] = "Chrontel TV encoder";
2652 ivideo.hasVB = HASVB_NONE;
2653 sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN;
2654 sishw_ext.Is301BDH = FALSE;
2655 sishw_ext.usExternalChip = 0;
2657 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2658 switch (vb_chipid) {
2660 ivideo.hasVB = HASVB_301;
2661 inSISIDXREG(SISPART4, 0x01, reg);
2663 ivideo.vbflags |= VB_301;
2664 sishw_ext.ujVBChipID = VB_CHIP_301;
2665 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2666 } else if(reg < 0xc0) {
2667 ivideo.vbflags |= VB_301B;
2668 sishw_ext.ujVBChipID = VB_CHIP_301B;
2669 inSISIDXREG(SISPART4,0x23,reg);
2671 sishw_ext.Is301BDH = TRUE;
2672 ivideo.vbflags |= VB_30xBDH;
2673 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2675 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2677 } else if(reg < 0xd0) {
2678 ivideo.vbflags |= VB_301C;
2679 sishw_ext.ujVBChipID = VB_CHIP_301C;
2680 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2681 } else if(reg < 0xe0) {
2682 ivideo.vbflags |= VB_301LV;
2683 sishw_ext.ujVBChipID = VB_CHIP_301LV;
2684 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2685 } else if(reg <= 0xe1) {
2686 inSISIDXREG(SISPART4,0x39,reg);
2688 ivideo.vbflags |= VB_302LV;
2689 sishw_ext.ujVBChipID = VB_CHIP_302LV;
2690 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2692 ivideo.vbflags |= VB_302ELV;
2693 sishw_ext.ujVBChipID = VB_CHIP_302ELV;
2694 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2699 ivideo.hasVB = HASVB_302;
2700 inSISIDXREG(SISPART4, 0x01, reg);
2702 ivideo.vbflags |= VB_302B;
2703 sishw_ext.ujVBChipID = VB_CHIP_302B;
2704 inSISIDXREG(SISPART4,0x23,reg);
2706 sishw_ext.Is301BDH = TRUE;
2707 ivideo.vbflags |= VB_30xBDH;
2708 printk(KERN_INFO "%s SiS302B-DH %s\n", stdstr, bridgestr);
2710 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2712 } else if(reg < 0xe0) {
2713 ivideo.vbflags |= VB_301LV;
2714 sishw_ext.ujVBChipID = VB_CHIP_301LV;
2715 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2716 } else if(reg <= 0xe1) {
2717 ivideo.vbflags |= VB_302LV;
2718 sishw_ext.ujVBChipID = VB_CHIP_302LV;
2719 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2724 if((!(ivideo.vbflags & VB_VIDEOBRIDGE)) && (ivideo.chip != SIS_300)) {
2725 inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg);
2726 reg &= SIS_EXTERNAL_CHIP_MASK;
2728 if(sisvga_engine == SIS_300_VGA) {
2730 case SIS_EXTERNAL_CHIP_LVDS:
2731 ivideo.hasVB = HASVB_LVDS;
2732 ivideo.vbflags |= VB_LVDS;
2733 sishw_ext.usExternalChip = 0x01;
2734 printk(KERN_INFO "%s %s\n", stdstr, lvdsstr);
2736 case SIS_EXTERNAL_CHIP_TRUMPION:
2737 ivideo.hasVB = HASVB_TRUMPION;
2738 sishw_ext.usExternalChip = 0x02;
2739 printk(KERN_INFO "%s Trumpion LCD scaler\n", stdstr);
2741 case SIS_EXTERNAL_CHIP_CHRONTEL:
2742 ivideo.hasVB = HASVB_CHRONTEL;
2743 ivideo.vbflags |= VB_CHRONTEL;
2744 sishw_ext.usExternalChip = 0x04;
2745 printk(KERN_INFO "%s %s\n", stdstr, chrstr);
2747 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2748 ivideo.hasVB = HASVB_LVDS_CHRONTEL;
2749 ivideo.vbflags |= (VB_LVDS | VB_CHRONTEL);
2750 sishw_ext.usExternalChip = 0x05;
2751 printk(KERN_INFO "%s %s and %s\n", stdstr, lvdsstr, chrstr);
2754 } else if(ivideo.chip < SIS_661) {
2756 case SIS310_EXTERNAL_CHIP_LVDS:
2757 ivideo.hasVB = HASVB_LVDS;
2758 ivideo.vbflags |= VB_LVDS;
2759 sishw_ext.usExternalChip = 0x01;
2760 printk(KERN_INFO "%s %s\n", stdstr, lvdsstr);
2762 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2763 ivideo.hasVB = HASVB_LVDS_CHRONTEL;
2764 ivideo.vbflags |= (VB_LVDS | VB_CHRONTEL);
2765 sishw_ext.usExternalChip = 0x05;
2766 printk(KERN_INFO "%s %s and %s\n", stdstr, lvdsstr, chrstr);
2773 if(ivideo.vbflags & VB_SISBRIDGE) {
2775 } else if(ivideo.vbflags & VB_CHRONTEL) {
2781 /* ------------------ Sensing routines ------------------ */
2784 sisfb_test_DDC1(void)
2789 old = SiS_ReadDDC1Bit(&SiS_Pr);
2791 if(old != SiS_ReadDDC1Bit(&SiS_Pr)) break;
2793 return (count == -1) ? FALSE : TRUE;
2797 sisfb_sense_crt1(void)
2799 unsigned char SR1F, CR63=0, CR17;
2800 unsigned short temp = 0xffff;
2802 BOOLEAN mustwait = FALSE;
2804 inSISIDXREG(SISSR,0x1F,SR1F);
2805 orSISIDXREG(SISSR,0x1F,0x04);
2806 andSISIDXREG(SISSR,0x1F,0x3F);
2807 if(SR1F & 0xc0) mustwait = TRUE;
2809 if(sisvga_engine == SIS_315_VGA) {
2810 inSISIDXREG(SISCR,SiS_Pr.SiS_MyCR63,CR63);
2812 andSISIDXREG(SISCR,SiS_Pr.SiS_MyCR63,0xBF);
2815 inSISIDXREG(SISCR,0x17,CR17);
2818 orSISIDXREG(SISCR,0x17,0x80);
2820 outSISIDXREG(SISSR, 0x00, 0x01);
2821 outSISIDXREG(SISSR, 0x00, 0x03);
2825 for(i=0; i < 10; i++) sisfbwaitretracecrt1();
2830 temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine, 0, 0, NULL);
2831 } while(((temp == 0) || (temp == 0xffff)) && i--);
2833 if((temp == 0) || (temp == 0xffff)) {
2834 if(sisfb_test_DDC1()) temp = 1;
2837 if((temp) && (temp != 0xffff)) {
2838 orSISIDXREG(SISCR,0x32,0x20);
2841 if(sisvga_engine == SIS_315_VGA) {
2842 setSISIDXREG(SISCR,SiS_Pr.SiS_MyCR63,0xBF,CR63);
2845 setSISIDXREG(SISCR,0x17,0x7F,CR17);
2847 outSISIDXREG(SISSR,0x1F,SR1F);
2850 /* Determine and detect attached devices on SiS30x */
2852 SISDoSense(int tempbl, int tempbh, int tempcl, int tempch)
2856 outSISIDXREG(SISPART4,0x11,tempbl);
2857 temp = tempbh | tempcl;
2858 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2859 SiS_DDC2Delay(&SiS_Pr, 0x1000);
2861 inSISIDXREG(SISPART4,0x03,temp);
2864 return((temp == tempch));
2870 u8 backupP4_0d,backupP2_00;
2871 u8 svhs_bl, svhs_bh;
2872 u8 svhs_cl, svhs_ch;
2873 u8 cvbs_bl, cvbs_bh;
2874 u8 cvbs_cl, cvbs_ch;
2875 u8 vga2_bl, vga2_bh;
2876 u8 vga2_cl, vga2_ch;
2877 int myflag, result, haveresult, i, j;
2878 char stdstr[] = "sisfb: Detected";
2879 char tvstr[] = "TV connected to";
2881 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2882 if(!(ivideo.vbflags & (VB_301C|VB_302ELV))) {
2883 outSISIDXREG(SISPART4,0x0d,(backupP4_0d | 0x04));
2886 inSISIDXREG(SISPART2,0x00,backupP2_00);
2887 outSISIDXREG(SISPART2,0x00,(backupP2_00 | 0x1c));
2889 if(sisvga_engine == SIS_300_VGA) {
2891 if(ivideo.vbflags & (VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV)) {
2892 vga2_bh = 0x01; vga2_bl = 0x90;
2893 svhs_bh = 0x01; svhs_bl = 0x6b;
2894 cvbs_bh = 0x01; cvbs_bl = 0x74;
2896 vga2_bh = 0x00; vga2_bl = 0xd1;
2897 svhs_bh = 0x00; svhs_bl = 0xb9;
2898 cvbs_bh = 0x00; cvbs_bl = 0xb3;
2900 inSISIDXREG(SISPART4,0x01,myflag);
2902 vga2_bh = 0x00; vga2_bl = 0xfd;
2903 svhs_bh = 0x00; svhs_bl = 0xdd;
2904 cvbs_bh = 0x00; cvbs_bl = 0xee;
2906 vga2_ch = 0x0e; vga2_cl = 0x08;
2907 svhs_ch = 0x04; svhs_cl = 0x04;
2908 cvbs_ch = 0x08; cvbs_cl = 0x04;
2909 if(ivideo.vbflags & (VB_301LV|VB_302LV)) {
2910 vga2_bh = 0x00; vga2_bl = 0x00;
2911 vga2_ch = 0x00; vga2_cl = 0x00;
2913 if(ivideo.chip == SIS_300) {
2914 inSISIDXREG(SISSR,0x3b,myflag);
2915 if(!(myflag & 0x01)) {
2916 vga2_bh = 0x00; vga2_bl = 0x00;
2917 vga2_ch = 0x00; vga2_cl = 0x00;
2923 if(ivideo.vbflags & (VB_301B|VB_302B)) {
2924 vga2_bh = 0x01; vga2_bl = 0x90;
2925 svhs_bh = 0x01; svhs_bl = 0x6b;
2926 cvbs_bh = 0x01; cvbs_bl = 0x74;
2927 } else if(ivideo.vbflags & (VB_301C|VB_302ELV)) {
2928 vga2_bh = 0x01; vga2_bl = 0x90;
2929 svhs_bh = 0x01; svhs_bl = 0x6b;
2930 cvbs_bh = 0x01; cvbs_bl = 0x10;
2931 } else if(ivideo.vbflags & (VB_301LV|VB_302LV)) {
2932 vga2_bh = 0x00; vga2_bl = 0x00;
2933 svhs_bh = 0x02; svhs_bl = 0x00;
2934 cvbs_bh = 0x01; cvbs_bl = 0x00;
2936 vga2_bh = 0x00; vga2_bl = 0xd1;
2937 svhs_bh = 0x00; svhs_bl = 0xb9;
2938 cvbs_bh = 0x00; cvbs_bl = 0xb3;
2939 inSISIDXREG(SISPART4,0x01,myflag);
2941 vga2_bh = 0x00; vga2_bl = 0xfd;
2942 svhs_bh = 0x00; svhs_bl = 0xdd;
2943 cvbs_bh = 0x00; cvbs_bl = 0xee;
2947 if(ivideo.vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
2948 vga2_bh = 0x00; vga2_bl = 0x00;
2949 vga2_ch = 0x00; vga2_cl = 0x00;
2950 svhs_ch = 0x04; svhs_cl = 0x08;
2951 cvbs_ch = 0x08; cvbs_cl = 0x08;
2953 vga2_ch = 0x0e; vga2_cl = 0x08;
2954 svhs_ch = 0x04; svhs_cl = 0x04;
2955 cvbs_ch = 0x08; cvbs_cl = 0x04;
2959 if(vga2_ch || vga2_cl || vga2_bh || vga2_bl) {
2961 for(j = 0; j < 10; j++) {
2963 for(i = 0; i < 3; i++) {
2964 if(SISDoSense(vga2_bl, vga2_bh, vga2_cl, vga2_ch))
2967 if((result == 0) || (result >= 2)) break;
2970 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2971 orSISIDXREG(SISCR, 0x32, 0x10);
2973 andSISIDXREG(SISCR, 0x32, ~0x10);
2977 if(ivideo.vbflags & (VB_301C|VB_302ELV)) {
2978 orSISIDXREG(SISPART4,0x0d,0x04);
2982 for(j = 0; j < 10; j++) {
2984 for(i = 0; i < 3; i++) {
2985 if(SISDoSense(svhs_bl, svhs_bh, svhs_cl, svhs_ch))
2988 if((result == 0) || (result >= 2)) break;
2991 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2992 ivideo.vbflags |= TV_SVIDEO;
2993 orSISIDXREG(SISCR, 0x32, 0x02);
2994 andSISIDXREG(SISCR, 0x32, ~0x05);
3000 for(j = 0; j < 10; j++) {
3002 for(i = 0; i < 3; i++) {
3003 if(SISDoSense(cvbs_bl, cvbs_bh, cvbs_cl, cvbs_ch))
3006 if((result == 0) || (result >= 2)) break;
3009 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
3010 ivideo.vbflags |= TV_AVIDEO;
3011 orSISIDXREG(SISCR, 0x32, 0x01);
3012 andSISIDXREG(SISCR, 0x32, ~0x06);
3014 andSISIDXREG(SISCR, 0x32, ~0x07);
3017 SISDoSense(0, 0, 0, 0);
3019 outSISIDXREG(SISPART2,0x00,backupP2_00);
3020 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
3023 /* Determine and detect attached TV's on Chrontel */
3029 #ifdef CONFIG_FB_SIS_300
3030 unsigned char test[3];
3033 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
3035 if(ivideo.chip < SIS_315H) {
3037 #ifdef CONFIG_FB_SIS_300
3038 SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
3039 SiS_SetChrontelGPIO(&SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
3040 SiS_DDC2Delay(&SiS_Pr, 1000);
3041 temp1 = SiS_GetCH700x(&SiS_Pr, 0x25);
3042 /* See Chrontel TB31 for explanation */
3043 temp2 = SiS_GetCH700x(&SiS_Pr, 0x0e);
3044 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
3045 SiS_SetCH700x(&SiS_Pr, 0x0b0e);
3046 SiS_DDC2Delay(&SiS_Pr, 300);
3048 temp2 = SiS_GetCH700x(&SiS_Pr, 0x25);
3049 if(temp2 != temp1) temp1 = temp2;
3051 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
3052 /* Read power status */
3053 temp1 = SiS_GetCH700x(&SiS_Pr, 0x0e);
3054 if((temp1 & 0x03) != 0x03) {
3055 /* Power all outputs */
3056 SiS_SetCH700x(&SiS_Pr, 0x0B0E);
3057 SiS_DDC2Delay(&SiS_Pr, 300);
3059 /* Sense connected TV devices */
3060 for(i = 0; i < 3; i++) {
3061 SiS_SetCH700x(&SiS_Pr, 0x0110);
3062 SiS_DDC2Delay(&SiS_Pr, 0x96);
3063 SiS_SetCH700x(&SiS_Pr, 0x0010);
3064 SiS_DDC2Delay(&SiS_Pr, 0x96);
3065 temp1 = SiS_GetCH700x(&SiS_Pr, 0x10);
3066 if(!(temp1 & 0x08)) test[i] = 0x02;
3067 else if(!(temp1 & 0x02)) test[i] = 0x01;
3069 SiS_DDC2Delay(&SiS_Pr, 0x96);
3072 if(test[0] == test[1]) temp1 = test[0];
3073 else if(test[0] == test[2]) temp1 = test[0];
3074 else if(test[1] == test[2]) temp1 = test[1];
3077 "sisfb: TV detection unreliable - test results varied\n");
3081 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
3082 ivideo.vbflags |= TV_SVIDEO;
3083 orSISIDXREG(SISCR, 0x32, 0x02);
3084 andSISIDXREG(SISCR, 0x32, ~0x05);
3085 } else if (temp1 == 0x01) {
3086 printk(KERN_INFO "%s CVBS output\n", stdstr);
3087 ivideo.vbflags |= TV_AVIDEO;
3088 orSISIDXREG(SISCR, 0x32, 0x01);
3089 andSISIDXREG(SISCR, 0x32, ~0x06);
3091 SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8);
3092 andSISIDXREG(SISCR, 0x32, ~0x07);
3094 } else if(temp1 == 0) {
3095 SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8);
3096 andSISIDXREG(SISCR, 0x32, ~0x07);
3098 /* Set general purpose IO for Chrontel communication */
3099 SiS_SetChrontelGPIO(&SiS_Pr, 0x00);
3104 #ifdef CONFIG_FB_SIS_315
3105 SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
3106 temp1 = SiS_GetCH701x(&SiS_Pr, 0x49);
3107 SiS_SetCH701x(&SiS_Pr, 0x2049);
3108 SiS_DDC2Delay(&SiS_Pr, 0x96);
3109 temp2 = SiS_GetCH701x(&SiS_Pr, 0x20);
3111 SiS_SetCH701x(&SiS_Pr, (temp2 << 8) | 0x20);
3112 SiS_DDC2Delay(&SiS_Pr, 0x96);
3114 SiS_SetCH701x(&SiS_Pr, (temp2 << 8) | 0x20);
3115 SiS_DDC2Delay(&SiS_Pr, 0x96);
3116 temp2 = SiS_GetCH701x(&SiS_Pr, 0x20);
3117 SiS_SetCH701x(&SiS_Pr, (temp1 << 8) | 0x49);
3119 if(temp2 & 0x02) temp1 |= 0x01;
3120 if(temp2 & 0x10) temp1 |= 0x01;
3121 if(temp2 & 0x04) temp1 |= 0x02;
3122 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
3125 printk(KERN_INFO "%s CVBS output\n", stdstr);
3126 ivideo.vbflags |= TV_AVIDEO;
3127 orSISIDXREG(SISCR, 0x32, 0x01);
3128 andSISIDXREG(SISCR, 0x32, ~0x06);
3131 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
3132 ivideo.vbflags |= TV_SVIDEO;
3133 orSISIDXREG(SISCR, 0x32, 0x02);
3134 andSISIDXREG(SISCR, 0x32, ~0x05);
3137 printk(KERN_INFO "%s SCART output\n", stdstr);
3138 orSISIDXREG(SISCR, 0x32, 0x04);
3139 andSISIDXREG(SISCR, 0x32, ~0x03);
3142 andSISIDXREG(SISCR, 0x32, ~0x07);
3150 /* ------------------------ Heap routines -------------------------- */
3152 static int sisfb_heap_init(void)
3156 #ifdef CONFIG_FB_SIS_315
3157 int agp_enabled = 1;
3159 unsigned long *cmdq_baseport = 0;
3160 unsigned long *read_port = 0;
3161 unsigned long *write_port = 0;
3162 SIS_CMDTYPE cmd_type;
3164 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
3165 struct agp_kern_info *agp_info;
3166 struct agp_memory *agp;
3168 agp_kern_info *agp_info;
3174 /* The heap start is either set manually using the "mem" parameter, or
3175 * defaults as follows:
3176 * -) If more than 16MB videoRAM available, let our heap start at 12MB.
3177 * -) If more than 8MB videoRAM available, let our heap start at 8MB.
3178 * -) If 4MB or less is available, let it start at 4MB.
3179 * This is for avoiding a clash with X driver which uses the beginning
3180 * of the videoRAM. To limit size of X framebuffer, use Option MaxXFBMem
3182 * The heap start can also be specified by parameter "mem" when starting the sisfb
3183 * driver. sisfb mem=1024 lets heap starts at 1MB, etc.
3185 * On the 315 and Xabre series, the default is a 1MB heap since DRI is not
3188 if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
3189 if(sisvga_engine == SIS_300_VGA) {
3190 if (ivideo.video_size > 0x1000000) {
3191 ivideo.heapstart = 0xc00000;
3192 } else if (ivideo.video_size > 0x800000) {
3193 ivideo.heapstart = 0x800000;
3195 ivideo.heapstart = 0x400000;
3198 ivideo.heapstart = ivideo.video_size - 0x100000;
3201 ivideo.heapstart = sisfb_mem * 1024;
3203 sisfb_heap_start = (unsigned long) (ivideo.video_vbase + ivideo.heapstart);
3204 printk(KERN_INFO "sisfb: Memory heap starting at %dK\n",
3205 (int)(ivideo.heapstart / 1024));
3207 sisfb_heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
3208 sisfb_heap_size = sisfb_heap_end - sisfb_heap_start;
3210 #ifdef CONFIG_FB_SIS_315
3211 if (sisvga_engine == SIS_315_VGA) {
3212 /* Now initialize the 315/330 series' command queue mode.
3213 * On 315, there are three queue modes available which
3214 * are chosen by setting bits 7:5 in SR26:
3215 * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
3216 * track of the queue, the FIFO, command parsing and so
3217 * on. This is the one comparable to the 300 series.
3218 * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
3219 * have to do queue management himself. Register 0x85c4 will
3220 * hold the location of the next free queue slot, 0x85c8
3221 * is the "queue read pointer" whose way of working is
3222 * unknown to me. Anyway, this mode would require a
3223 * translation of the MMIO commands to some kind of
3224 * accelerator assembly and writing these commands
3225 * to the memory location pointed to by 0x85c4.
3226 * We will not use this, as nobody knows how this
3227 * "assembly" works, and as it would require a complete
3228 * re-write of the accelerator code.
3229 * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
3230 * queue in AGP memory space.
3232 * SR26 bit 4 is called "Bypass H/W queue".
3233 * SR26 bit 1 is called "Enable Command Queue Auto Correction"
3234 * SR26 bit 0 resets the queue
3235 * Size of queue memory is encoded in bits 3:2 like this:
3240 * The queue location is to be written to 0x85C0.
3243 cmdq_baseport = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_PHYBASE);
3244 write_port = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_WRITEPORT);
3245 read_port = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_READPORT);
3247 DPRINTK("AGP base: 0x%p, read: 0x%p, write: 0x%p\n", cmdq_baseport, read_port, write_port);
3249 agp_size = COMMAND_QUEUE_AREA_SIZE;
3252 if (sisfb_queuemode == AGP_CMD_QUEUE) {
3253 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
3254 agp_info = vmalloc(sizeof(*agp_info));
3255 memset((void*)agp_info, 0x00, sizeof(*agp_info));
3257 agp_info = vmalloc(sizeof(agp_kern_info));
3258 memset((void*)agp_info, 0x00, sizeof(agp_kern_info));
3260 agp_copy_info(agp_info);
3262 agp_backend_acquire();
3264 agp = agp_allocate_memory(COMMAND_QUEUE_AREA_SIZE/PAGE_SIZE,
3267 DPRINTK("sisfb: Allocating AGP buffer failed.\n");
3270 if (agp_bind_memory(agp, agp->pg_start) != 0) {
3271 DPRINTK("sisfb: AGP: Failed to bind memory\n");
3272 /* TODO: Free AGP memory here */
3283 /* Now select the queue mode */
3285 if ((agp_enabled) && (sisfb_queuemode == AGP_CMD_QUEUE)) {
3286 cmd_type = AGP_CMD_QUEUE;
3287 printk(KERN_INFO "sisfb: Using AGP queue mode\n");
3288 /* } else if (sisfb_heap_size >= COMMAND_QUEUE_AREA_SIZE) */
3289 } else if (sisfb_queuemode == VM_CMD_QUEUE) {
3290 cmd_type = VM_CMD_QUEUE;
3291 printk(KERN_INFO "sisfb: Using VRAM queue mode\n");
3293 printk(KERN_INFO "sisfb: Using MMIO queue mode\n");
3294 cmd_type = MMIO_CMD;
3299 temp = SIS_CMD_QUEUE_SIZE_512k;
3302 temp = SIS_CMD_QUEUE_SIZE_1M;
3305 temp = SIS_CMD_QUEUE_SIZE_2M;
3308 temp = SIS_CMD_QUEUE_SIZE_4M;
3315 DPRINTK("sisfb: AGP buffer base = 0x%lx, offset = 0x%x, size = %dK\n",
3316 agp_info->aper_base, agp->physical, agp_size/1024);
3318 agp_phys = agp_info->aper_base + agp->physical;
3320 outSISIDXREG(SISCR, IND_SIS_AGP_IO_PAD, 0);
3321 outSISIDXREG(SISCR, IND_SIS_AGP_IO_PAD, SIS_AGP_2X);
3323 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
3325 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3327 *write_port = *read_port;
3329 temp |= SIS_AGP_CMDQUEUE_ENABLE;
3330 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3332 *cmdq_baseport = agp_phys;
3334 sisfb_caps |= AGP_CMD_QUEUE_CAP;
3339 sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
3340 sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
3342 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
3344 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3346 *write_port = *read_port;
3348 temp |= SIS_VRAM_CMDQUEUE_ENABLE;
3349 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3351 *cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
3353 sisfb_caps |= VM_CMD_QUEUE_CAP;
3355 DPRINTK("sisfb: VM Cmd Queue offset = 0x%lx, size is %dK\n",
3356 *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
3360 sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
3361 sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
3363 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
3364 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3366 *write_port = *read_port;
3368 /* Set Auto_Correction bit */
3369 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3370 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3372 *cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
3374 sisfb_caps |= MMIO_CMD_QUEUE_CAP;
3376 DPRINTK("sisfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n",
3377 *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
3380 } /* sisvga_engine = 315 */
3383 #ifdef CONFIG_FB_SIS_300
3384 if (sisvga_engine == SIS_300_VGA) {
3385 /* Now initialize TurboQueue. TB is always located at the very
3386 * top of the video RAM. */
3387 if (sisfb_heap_size >= TURBO_QUEUE_AREA_SIZE) {
3388 unsigned int tqueue_pos;
3391 tqueue_pos = (ivideo.video_size -
3392 TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
3394 temp = (u8) (tqueue_pos & 0xff);
3396 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3399 tq_state |= (u8) (tqueue_pos >> 8);
3400 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3402 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, temp);
3404 sisfb_caps |= TURBO_QUEUE_CAP;
3406 sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
3407 sisfb_heap_size -= TURBO_QUEUE_AREA_SIZE;
3408 DPRINTK("sisfb: TurboQueue start at 0x%lx, size is %dK\n",
3409 sisfb_heap_end, TURBO_QUEUE_AREA_SIZE/1024);
3413 /* Now reserve memory for the HWCursor. It is always located at the very
3414 top of the videoRAM, right below the TB memory area (if used). */
3415 if (sisfb_heap_size >= sisfb_hwcursor_size) {
3416 sisfb_heap_end -= sisfb_hwcursor_size;
3417 sisfb_heap_size -= sisfb_hwcursor_size;
3418 sisfb_hwcursor_vbase = sisfb_heap_end;
3420 sisfb_caps |= HW_CURSOR_CAP;
3422 DPRINTK("sisfb: Hardware Cursor start at 0x%lx, size is %dK\n",
3423 sisfb_heap_end, sisfb_hwcursor_size/1024);
3426 sisfb_heap.poha_chain = NULL;
3427 sisfb_heap.poh_freelist = NULL;
3429 poh = sisfb_poh_new_node();
3431 if(poh == NULL) return 1;
3433 poh->poh_next = &sisfb_heap.oh_free;
3434 poh->poh_prev = &sisfb_heap.oh_free;
3435 poh->size = sisfb_heap_end - sisfb_heap_start + 1;
3436 poh->offset = sisfb_heap_start - (unsigned long) ivideo.video_vbase;
3438 DPRINTK("sisfb: Heap start:0x%p, end:0x%p, len=%dk\n",
3439 (char *) sisfb_heap_start, (char *) sisfb_heap_end,
3440 (unsigned int) poh->size / 1024);
3442 DPRINTK("sisfb: First Node offset:0x%x, size:%dk\n",
3443 (unsigned int) poh->offset, (unsigned int) poh->size / 1024);
3445 sisfb_heap.oh_free.poh_next = poh;
3446 sisfb_heap.oh_free.poh_prev = poh;
3447 sisfb_heap.oh_free.size = 0;
3448 sisfb_heap.max_freesize = poh->size;
3450 sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
3451 sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
3452 sisfb_heap.oh_used.size = SENTINEL;
3457 static SIS_OH *sisfb_poh_new_node(void)
3464 if (sisfb_heap.poh_freelist == NULL) {
3465 poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
3466 if(!poha) return NULL;
3468 poha->poha_next = sisfb_heap.poha_chain;
3469 sisfb_heap.poha_chain = poha;
3471 cOhs = (OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
3473 poh = &poha->aoh[0];
3474 for (i = cOhs - 1; i != 0; i--) {
3475 poh->poh_next = poh + 1;
3479 poh->poh_next = NULL;
3480 sisfb_heap.poh_freelist = &poha->aoh[0];
3483 poh = sisfb_heap.poh_freelist;
3484 sisfb_heap.poh_freelist = poh->poh_next;
3489 static SIS_OH *sisfb_poh_allocate(unsigned long size)
3495 if (size > sisfb_heap.max_freesize) {
3496 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
3497 (unsigned int) size / 1024);
3501 pohThis = sisfb_heap.oh_free.poh_next;
3503 while (pohThis != &sisfb_heap.oh_free) {
3504 if (size <= pohThis->size) {
3508 pohThis = pohThis->poh_next;
3512 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
3513 (unsigned int) size / 1024);
3517 if (size == pohThis->size) {
3519 sisfb_delete_node(pohThis);
3521 pohRoot = sisfb_poh_new_node();
3523 if (pohRoot == NULL) {
3527 pohRoot->offset = pohThis->offset;
3528 pohRoot->size = size;
3530 pohThis->offset += size;
3531 pohThis->size -= size;
3534 sisfb_heap.max_freesize -= size;
3536 pohThis = &sisfb_heap.oh_used;
3537 sisfb_insert_node(pohThis, pohRoot);
3542 static void sisfb_delete_node(SIS_OH *poh)
3547 poh_prev = poh->poh_prev;
3548 poh_next = poh->poh_next;
3550 poh_prev->poh_next = poh_next;
3551 poh_next->poh_prev = poh_prev;
3555 static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
3559 pohTemp = pohList->poh_next;
3561 pohList->poh_next = poh;
3562 pohTemp->poh_prev = poh;
3564 poh->poh_prev = pohList;
3565 poh->poh_next = pohTemp;
3568 static SIS_OH *sisfb_poh_free(unsigned long base)
3574 unsigned long ulUpper;
3575 unsigned long ulLower;
3578 poh_freed = sisfb_heap.oh_used.poh_next;
3580 while(poh_freed != &sisfb_heap.oh_used) {
3581 if(poh_freed->offset == base) {
3586 poh_freed = poh_freed->poh_next;
3589 if (!foundNode) return (NULL);
3591 sisfb_heap.max_freesize += poh_freed->size;
3593 poh_prev = poh_next = NULL;
3594 ulUpper = poh_freed->offset + poh_freed->size;
3595 ulLower = poh_freed->offset;
3597 pohThis = sisfb_heap.oh_free.poh_next;
3599 while (pohThis != &sisfb_heap.oh_free) {
3600 if (pohThis->offset == ulUpper) {
3603 else if ((pohThis->offset + pohThis->size) ==
3607 pohThis = pohThis->poh_next;
3610 sisfb_delete_node(poh_freed);
3612 if (poh_prev && poh_next) {
3613 poh_prev->size += (poh_freed->size + poh_next->size);
3614 sisfb_delete_node(poh_next);
3615 sisfb_free_node(poh_freed);
3616 sisfb_free_node(poh_next);
3621 poh_prev->size += poh_freed->size;
3622 sisfb_free_node(poh_freed);
3627 poh_next->size += poh_freed->size;
3628 poh_next->offset = poh_freed->offset;
3629 sisfb_free_node(poh_freed);
3633 sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
3638 static void sisfb_free_node(SIS_OH *poh)
3640 if(poh == NULL) return;
3642 poh->poh_next = sisfb_heap.poh_freelist;
3643 sisfb_heap.poh_freelist = poh;
3647 void sis_malloc(struct sis_memreq *req)
3651 poh = sisfb_poh_allocate(req->size);
3656 DPRINTK("sisfb: Video RAM allocation failed\n");
3658 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%p\n",
3659 (char *) (poh->offset + (unsigned long) ivideo.video_vbase));
3661 req->offset = poh->offset;
3662 req->size = poh->size;
3666 void sis_free(unsigned long base)
3670 poh = sisfb_poh_free(base);
3673 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3674 (unsigned int) base);
3678 /* --------------------- SetMode routines ------------------------- */
3680 static void sisfb_pre_setmode(void)
3682 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0;
3684 ivideo.currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3686 inSISIDXREG(SISCR, 0x31, cr31);
3690 cr33 = sisfb_rate_idx & 0x0F;
3692 SiS_SetEnableDstn(&SiS_Pr, FALSE);
3693 SiS_SetEnableFstn(&SiS_Pr, FALSE);
3695 switch (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
3697 ivideo.disp_state = DISPTYPE_TV;
3698 if (ivideo.vbflags & TV_SVIDEO) {
3699 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3700 ivideo.currentvbflags |= TV_SVIDEO;
3701 ivideo.TV_plug = TVPLUG_SVIDEO;
3702 } else if (ivideo.vbflags & TV_AVIDEO) {
3703 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3704 ivideo.currentvbflags |= TV_AVIDEO;
3705 ivideo.TV_plug = TVPLUG_COMPOSITE;
3706 } else if (ivideo.vbflags & TV_SCART) {
3707 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3708 ivideo.currentvbflags |= TV_SCART;
3709 ivideo.TV_plug = TVPLUG_SCART;
3711 cr31 |= SIS_DRIVER_MODE;
3713 if(!(ivideo.vbflags & TV_HIVISION)) {
3714 if (ivideo.vbflags & TV_PAL) {
3717 ivideo.currentvbflags |= TV_PAL;
3718 ivideo.TV_type = TVMODE_PAL;
3722 ivideo.currentvbflags |= TV_NTSC;
3723 ivideo.TV_type = TVMODE_NTSC;
3728 ivideo.disp_state = DISPTYPE_LCD;
3729 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3730 cr31 |= SIS_DRIVER_MODE;
3731 SiS_SetEnableDstn(&SiS_Pr, sisfb_dstn);
3732 SiS_SetEnableFstn(&SiS_Pr, sisfb_fstn);
3735 ivideo.disp_state = DISPTYPE_CRT2;
3736 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3737 cr31 |= SIS_DRIVER_MODE;
3738 if(sisfb_nocrt2rate) {
3739 cr33 |= (sisbios_mode[sisfb_mode_idx].rate_idx << 4);
3741 cr33 |= ((sisfb_rate_idx & 0x0F) << 4);
3744 default: /* disable CRT2 */
3746 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3749 if(ivideo.chip >= SIS_661) {
3751 /* Leave overscan bit alone */
3752 setSISIDXREG(SISCR, 0x35, ~0x10, cr35);
3754 outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR30, cr30);
3755 outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR31, cr31);
3756 outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR33, cr33);
3758 #ifdef CONFIG_FB_SIS_315
3759 if(sisvga_engine == SIS_315_VGA) {
3760 /* Clear LCDA and PAL-N/M bits */
3761 andSISIDXREG(SISCR,0x38,~0x03);
3762 if(ivideo.chip < SIS_661) {
3763 andSISIDXREG(SISCR,0x38,~0xc0);
3768 if(ivideo.accel) sisfb_syncaccel();
3770 SiS_Pr.SiS_UseOEM = sisfb_useoem;
3773 static void sisfb_post_setmode(void)
3776 BOOLEAN crt1isoff = FALSE;
3777 #ifdef CONFIG_FB_SIS_315
3780 #ifdef CONFIG_FB_SIS_300
3781 BOOLEAN doit = TRUE;
3783 /* We can't switch off CRT1 if bridge is in slave mode */
3784 if(ivideo.vbflags & VB_VIDEOBRIDGE) {
3785 #ifdef CONFIG_FB_SIS_300
3786 if(sisvga_engine == SIS_300_VGA) {
3787 inSISIDXREG(SISPART1, 0x00, reg);
3788 if((reg & 0xa0) == 0x20) {
3793 } else sisfb_crt1off = 0;
3795 if(sisvga_engine == SIS_300_VGA) {
3797 #ifdef CONFIG_FB_SIS_300
3798 if((sisfb_crt1off) && (doit)) {
3805 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3810 #ifdef CONFIG_FB_SIS_315
3821 setSISIDXREG(SISCR, SiS_Pr.SiS_MyCR63, ~0x40, reg);
3822 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3828 ivideo.currentvbflags &= ~VB_DISPTYPE_CRT1;
3829 ivideo.currentvbflags |= VB_SINGLE_MODE;
3830 ivideo.disp_state |= DISPMODE_SINGLE;
3832 ivideo.currentvbflags |= VB_DISPTYPE_CRT1;
3833 ivideo.disp_state |= DISPTYPE_CRT1;
3834 if(ivideo.currentvbflags & VB_DISPTYPE_CRT2) {
3835 ivideo.currentvbflags |= VB_MIRROR_MODE;
3836 ivideo.disp_state |= DISPMODE_MIRROR;
3838 ivideo.currentvbflags |= VB_SINGLE_MODE;
3839 ivideo.disp_state |= DISPMODE_SINGLE;
3843 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3845 if((ivideo.currentvbflags & CRT2_TV) && (ivideo.vbflags & VB_301)) { /* Set filter for SiS301 */
3847 switch (ivideo.video_width) {
3849 filter_tb = (ivideo.vbflags & TV_NTSC) ? 4 : 12;
3852 filter_tb = (ivideo.vbflags & TV_NTSC) ? 5 : 13;
3855 filter_tb = (ivideo.vbflags & TV_NTSC) ? 6 : 14;
3859 filter_tb = (ivideo.vbflags & TV_NTSC) ? 7 : 15;
3866 orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
3868 if(ivideo.vbflags & TV_NTSC) {
3870 andSISIDXREG(SISPART2, 0x3a, 0x1f);
3872 if (ivideo.vbflags & TV_SVIDEO) {
3874 andSISIDXREG(SISPART2, 0x30, 0xdf);
3876 } else if (ivideo.vbflags & TV_AVIDEO) {
3878 orSISIDXREG(SISPART2, 0x30, 0x20);
3880 switch (ivideo.video_width) {
3882 outSISIDXREG(SISPART2, 0x35, 0xEB);
3883 outSISIDXREG(SISPART2, 0x36, 0x04);
3884 outSISIDXREG(SISPART2, 0x37, 0x25);
3885 outSISIDXREG(SISPART2, 0x38, 0x18);
3888 outSISIDXREG(SISPART2, 0x35, 0xEE);
3889 outSISIDXREG(SISPART2, 0x36, 0x0C);
3890 outSISIDXREG(SISPART2, 0x37, 0x22);
3891 outSISIDXREG(SISPART2, 0x38, 0x08);
3895 outSISIDXREG(SISPART2, 0x35, 0xEB);
3896 outSISIDXREG(SISPART2, 0x36, 0x15);
3897 outSISIDXREG(SISPART2, 0x37, 0x25);
3898 outSISIDXREG(SISPART2, 0x38, 0xF6);
3903 } else if(ivideo.vbflags & TV_PAL) {
3905 andSISIDXREG(SISPART2, 0x3A, 0x1F);
3907 if (ivideo.vbflags & TV_SVIDEO) {
3909 andSISIDXREG(SISPART2, 0x30, 0xDF);
3911 } else if (ivideo.vbflags & TV_AVIDEO) {
3913 orSISIDXREG(SISPART2, 0x30, 0x20);
3915 switch (ivideo.video_width) {
3917 outSISIDXREG(SISPART2, 0x35, 0xF1);
3918 outSISIDXREG(SISPART2, 0x36, 0xF7);
3919 outSISIDXREG(SISPART2, 0x37, 0x1F);
3920 outSISIDXREG(SISPART2, 0x38, 0x32);
3923 outSISIDXREG(SISPART2, 0x35, 0xF3);
3924 outSISIDXREG(SISPART2, 0x36, 0x00);
3925 outSISIDXREG(SISPART2, 0x37, 0x1D);
3926 outSISIDXREG(SISPART2, 0x38, 0x20);
3930 outSISIDXREG(SISPART2, 0x35, 0xFC);
3931 outSISIDXREG(SISPART2, 0x36, 0xFB);
3932 outSISIDXREG(SISPART2, 0x37, 0x14);
3933 outSISIDXREG(SISPART2, 0x38, 0x2A);
3939 if ((filter >= 0) && (filter <= 7)) {
3940 DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter,
3941 sis_TV_filter[filter_tb].filter[filter][0],
3942 sis_TV_filter[filter_tb].filter[filter][1],
3943 sis_TV_filter[filter_tb].filter[filter][2],
3944 sis_TV_filter[filter_tb].filter[filter][3]
3946 outSISIDXREG(SISPART2, 0x35, (sis_TV_filter[filter_tb].filter[filter][0]));
3947 outSISIDXREG(SISPART2, 0x36, (sis_TV_filter[filter_tb].filter[filter][1]));
3948 outSISIDXREG(SISPART2, 0x37, (sis_TV_filter[filter_tb].filter[filter][2]));
3949 outSISIDXREG(SISPART2, 0x38, (sis_TV_filter[filter_tb].filter[filter][3]));
3957 int sisfb_setup(char *options)
3961 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
3962 sisfb_fontname[0] = '\0';
3965 ivideo.refresh_rate = 0;
3966 SiS_Pr.SiS_CustomT = CUT_NONE;
3967 SiS_Pr.UsePanelScaler = -1;
3970 printk(KERN_DEBUG "sisfb: Options %s\n", options);
3972 if (!options || !*options)
3975 while((this_opt = strsep(&options, ",")) != NULL) {
3977 if (!*this_opt) continue;
3979 if (!strnicmp(this_opt, "mode:", 5)) {
3980 sisfb_search_mode(this_opt + 5, FALSE);
3981 } else if (!strnicmp(this_opt, "vesa:", 5)) {
3982 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
3983 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
3984 } else if (!strnicmp(this_opt, "inverse", 7)) {
3986 /* fb_invert_cmaps(); */
3987 } else if (!strnicmp(this_opt, "font:", 5)) {
3988 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
3989 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
3991 } else if (!strnicmp(this_opt, "vrate:", 6)) {
3992 ivideo.refresh_rate = simple_strtoul(this_opt + 6, NULL, 0);
3993 sisfb_parm_rate = ivideo.refresh_rate;
3994 } else if (!strnicmp(this_opt, "rate:", 5)) {
3995 ivideo.refresh_rate = simple_strtoul(this_opt + 5, NULL, 0);
3996 sisfb_parm_rate = ivideo.refresh_rate;
3997 } else if (!strnicmp(this_opt, "off", 3)) {
3999 } else if (!strnicmp(this_opt, "crt1off", 7)) {
4001 } else if (!strnicmp(this_opt, "filter:", 7)) {
4002 filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
4003 } else if (!strnicmp(this_opt, "forcecrt2type:", 14)) {
4004 sisfb_search_crt2type(this_opt + 14);
4005 } else if (!strnicmp(this_opt, "forcecrt1:", 10)) {
4006 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4007 } else if (!strnicmp(this_opt, "tvmode:",7)) {
4008 sisfb_search_tvstd(this_opt + 7);
4009 } else if (!strnicmp(this_opt, "tvstandard:",11)) {
4010 sisfb_search_tvstd(this_opt + 7);
4011 } else if (!strnicmp(this_opt, "mem:",4)) {
4012 sisfb_mem = simple_strtoul(this_opt + 4, NULL, 0);
4013 } else if (!strnicmp(this_opt, "queuemode:", 10)) {
4014 sisfb_search_queuemode(this_opt + 10);
4015 } else if (!strnicmp(this_opt, "pdc:", 4)) {
4016 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4017 } else if (!strnicmp(this_opt, "noaccel", 7)) {
4019 } else if (!strnicmp(this_opt, "noypan", 6)) {
4021 } else if (!strnicmp(this_opt, "nomax", 5)) {
4023 } else if (!strnicmp(this_opt, "userom:", 7)) {
4024 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4025 } else if (!strnicmp(this_opt, "useoem:", 7)) {
4026 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4027 } else if (!strnicmp(this_opt, "nocrt2rate", 10)) {
4028 sisfb_nocrt2rate = 1;
4029 } else if (!strnicmp(this_opt, "scalelcd:", 9)) {
4030 unsigned long temp = 2;
4031 temp = simple_strtoul(this_opt + 9, NULL, 0);
4032 if((temp == 0) || (temp == 1)) {
4033 SiS_Pr.UsePanelScaler = temp ^ 1;
4035 } else if (!strnicmp(this_opt, "specialtiming:", 14)) {
4036 sisfb_search_specialtiming(this_opt + 14);
4037 } else if (!strnicmp(this_opt, "lvdshl:", 7)) {
4038 unsigned long temp = 4;
4039 temp = simple_strtoul(this_opt + 7, NULL, 0);
4040 if((temp >= 0) && (temp <= 3)) {
4041 SiS_Pr.LVDSHL = temp;
4043 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4044 sisfb_search_mode(this_opt, TRUE);
4046 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4049 /* TW: Acceleration only with MMIO mode */
4050 if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
4059 static char *sis_find_rom(void)
4061 #if defined(__i386__)
4063 unsigned char *rom_base, *rom;
4065 unsigned short pciid;
4067 for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
4069 rom_base = (char *)ioremap(segstart, 0x10000);
4070 if(!rom_base) continue;
4072 if((*rom_base != 0x55) || (*(rom_base + 1) != 0xaa)) {
4077 romptr = (unsigned short)(*(rom_base + 0x18) | (*(rom_base + 0x19) << 8));
4078 if(romptr > (0x10000 - 8)) {
4083 rom = rom_base + romptr;
4085 if((*rom != 'P') || (*(rom + 1) != 'C') || (*(rom + 2) != 'I') || (*(rom + 3) != 'R')) {
4090 pciid = (*(rom + 4)) | ((*(rom + 5)) << 8);
4091 if(pciid != 0x1039) {
4096 pciid = (*(rom + 6)) | ((*(rom + 7)) << 8);
4097 if(pciid == ivideo.chip_id) return rom_base;
4107 int __init sisfb_init(void)
4109 struct pci_dev *pdev = NULL;
4118 sisfb_set_reg4(0xcf8,0x800000e0);
4119 reg32 = sisfb_get_reg3(0xcfc);
4120 reg32 = reg32 | 0x00001000;
4121 sisfb_set_reg4(0xcfc,reg32);
4128 sisfb_registered = 0;
4129 sisfb_thismonitor.datavalid = FALSE;
4131 memset(&sishw_ext, 0, sizeof(sishw_ext));
4133 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
4134 memset(&sisfb_lastrates[0], 0, 128);
4137 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4138 memset(&sis_disp, 0, sizeof(sis_disp));
4141 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
4142 pci_for_each_dev(pdev) {
4144 while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
4146 for (b = sisdev_list; b->vendor; b++) {
4147 if ((b->vendor == pdev->vendor)
4148 && (b->device == pdev->device)) {
4150 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && defined(NEWFBDEV)
4151 sis_fb_info = framebuffer_alloc(0, &pdev->dev);
4153 sis_fb_info = kmalloc(sizeof(*sis_fb_info), GFP_KERNEL);
4155 if(!sis_fb_info) return -ENOMEM;
4156 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) || (!(defined(NEWFBDEV)))
4157 memset(sis_fb_info, 0, sizeof(*sis_fb_info));
4159 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4160 strcpy(sis_fb_info->modename, b->name);
4162 strcpy(myid, b->name);
4164 ivideo.chip_id = pdev->device;
4165 pci_read_config_byte(pdev, PCI_REVISION_ID,
4166 &ivideo.revision_id);
4167 pci_read_config_word(pdev, PCI_COMMAND, ®16);
4168 sishw_ext.jChipRevision = ivideo.revision_id;
4169 sisvga_enabled = reg16 & 0x01;
4170 ivideo.pcibus = pdev->bus->number;
4171 ivideo.pcislot = PCI_SLOT(pdev->devfn);
4172 ivideo.pcifunc = PCI_FUNC(pdev->devfn);
4173 ivideo.subsysvendor = pdev->subsystem_vendor;
4174 ivideo.subsysdevice = pdev->subsystem_device;
4186 switch (ivideo.chip_id) {
4187 #ifdef CONFIG_FB_SIS_300
4188 case PCI_DEVICE_ID_SI_300:
4189 ivideo.chip = SIS_300;
4190 sisvga_engine = SIS_300_VGA;
4191 sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2; /* New X driver uses 2 buffers */
4192 sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300;
4194 case PCI_DEVICE_ID_SI_630_VGA:
4196 ivideo.chip = SIS_630;
4197 sisfb_set_reg4(0xCF8, 0x80000000);
4198 reg32 = sisfb_get_reg3(0xCFC);
4199 if(reg32 == 0x07301039) {
4200 ivideo.chip = SIS_730;
4201 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4202 strcpy(sis_fb_info->modename, "SIS 730");
4204 strcpy(myid, "SIS 730");
4207 sisvga_engine = SIS_300_VGA;
4208 sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2;
4209 sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300;
4212 case PCI_DEVICE_ID_SI_540_VGA:
4213 ivideo.chip = SIS_540;
4214 sisvga_engine = SIS_300_VGA;
4215 sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2;
4216 sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300;
4219 #ifdef CONFIG_FB_SIS_315
4220 case PCI_DEVICE_ID_SI_315H:
4221 ivideo.chip = SIS_315H;
4222 sisvga_engine = SIS_315_VGA;
4223 sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
4224 sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
4226 case PCI_DEVICE_ID_SI_315:
4227 ivideo.chip = SIS_315;
4228 sisvga_engine = SIS_315_VGA;
4229 sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
4230 sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
4232 case PCI_DEVICE_ID_SI_315PRO:
4233 ivideo.chip = SIS_315PRO;
4234 sisvga_engine = SIS_315_VGA;
4235 sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
4236 sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
4238 case PCI_DEVICE_ID_SI_550_VGA:
4239 ivideo.chip = SIS_550;
4240 sisvga_engine = SIS_315_VGA;
4241 sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
4242 sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
4244 case PCI_DEVICE_ID_SI_650_VGA:
4246 ivideo.chip = SIS_650;
4247 sisfb_set_reg4(0xCF8, 0x80000000);
4248 reg32 = sisfb_get_reg3(0xCFC);
4249 if(reg32 == 0x07401039) {
4250 ivideo.chip = SIS_740;
4251 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4252 strcpy(sis_fb_info->modename, "SIS 740");
4254 strcpy(myid, "SIS 740");
4257 sisvga_engine = SIS_315_VGA;
4258 sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
4259 sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
4262 case PCI_DEVICE_ID_SI_330:
4263 ivideo.chip = SIS_330;
4264 sisvga_engine = SIS_315_VGA;
4265 sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
4266 sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
4268 case PCI_DEVICE_ID_SI_660_VGA:
4270 sisfb_set_reg4(0xCF8, 0x80000000);
4271 reg32 = sisfb_get_reg3(0xCFC);
4272 if(reg32 == 0x07601039) {
4273 ivideo.chip = SIS_760;
4274 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4275 strcpy(sis_fb_info->modename, "SIS 760");
4277 strcpy(myid, "SIS 760");
4279 } else if(reg32 == 0x06601039) {
4280 ivideo.chip = SIS_660;
4281 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4282 strcpy(sis_fb_info->modename, "SIS 660");
4284 strcpy(myid, "SIS 660");
4286 } else if(reg32 == 0x07411039) {
4287 ivideo.chip = SIS_741;
4288 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4289 strcpy(sis_fb_info->modename, "SIS 741");
4291 strcpy(myid, "SIS 741");
4294 ivideo.chip = SIS_661;
4295 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4296 strcpy(sis_fb_info->modename, "SIS 661");
4298 strcpy(myid, "SIS 661");
4301 sisvga_engine = SIS_315_VGA;
4302 sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
4303 sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
4311 sishw_ext.jChipType = ivideo.chip;
4314 if( (sishw_ext.jChipType == SIS_315PRO) ||
4315 (sishw_ext.jChipType == SIS_315) )
4316 sishw_ext.jChipType = SIS_315H;
4318 ivideo.video_base = pci_resource_start(pdev, 0);
4319 ivideo.mmio_base = pci_resource_start(pdev, 1);
4320 sishw_ext.ulIOAddress = SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
4321 ivideo.vga_base = (unsigned short) sishw_ext.ulIOAddress;
4323 sisfb_mmio_size = pci_resource_len(pdev, 1);
4325 if(!sisvga_enabled) {
4326 if(pci_enable_device(pdev)) {
4332 SiS_Pr.SiS_Backup70xx = 0xff;
4333 SiS_Pr.SiS_CHOverScan = -1;
4334 SiS_Pr.SiS_ChSW = FALSE;
4335 SiS_Pr.SiS_UseLCDA = FALSE;
4336 SiS_Pr.HaveEMI = FALSE;
4337 SiS_Pr.HaveEMILCD = FALSE;
4338 SiS_Pr.OverruleEMI = FALSE;
4339 SiS_Pr.SiS_SensibleSR11 = FALSE;
4340 SiS_Pr.SiS_MyCR63 = 0x63;
4341 if(ivideo.chip >= SIS_661) {
4342 SiS_Pr.SiS_SensibleSR11 = TRUE;
4343 SiS_Pr.SiS_MyCR63 = 0x53;
4345 SiSRegInit(&SiS_Pr, sishw_ext.ulIOAddress);
4347 #ifdef CONFIG_FB_SIS_300
4348 /* TW: Find PCI systems for Chrontel/GPIO communication setup */
4349 if(ivideo.chip == SIS_630) {
4352 if(mychswtable[i].subsysVendor == ivideo.subsysvendor &&
4353 mychswtable[i].subsysCard == ivideo.subsysdevice) {
4354 SiS_Pr.SiS_ChSW = TRUE;
4355 printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
4356 mychswtable[i].vendorName, mychswtable[i].cardName);
4360 } while(mychswtable[i].subsysVendor != 0);
4364 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
4366 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4368 inSISIDXREG(SISCR,0x34,reg);
4369 if((reg & 0x80) && (reg != 0xff)) {
4370 if((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {
4371 printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
4379 if (sisvga_engine == SIS_315_VGA) {
4380 switch (ivideo.chip) {
4384 sishw_ext.bIntegratedMMEnabled = TRUE;
4393 sishw_ext.bIntegratedMMEnabled = TRUE;
4398 } else if (sisvga_engine == SIS_300_VGA) {
4399 if (ivideo.chip == SIS_300) {
4400 sishw_ext.bIntegratedMMEnabled = TRUE;
4402 inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_1A, reg);
4403 if (reg & SIS_SCRATCH_REG_1A_MASK)
4404 sishw_ext.bIntegratedMMEnabled = TRUE;
4406 sishw_ext.bIntegratedMMEnabled = FALSE;
4411 sishw_ext.pjVirtualRomBase = sis_find_rom();
4412 if(sishw_ext.pjVirtualRomBase) {
4413 printk(KERN_INFO "sisfb: Video ROM found and mapped to %p\n",
4414 sishw_ext.pjVirtualRomBase);
4415 sishw_ext.UseROM = TRUE;
4417 sishw_ext.UseROM = FALSE;
4418 printk(KERN_INFO "sisfb: Video ROM not found\n");
4421 sishw_ext.pjVirtualRomBase = NULL;
4422 sishw_ext.UseROM = FALSE;
4423 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
4425 sishw_ext.bSkipDramSizing = 0;
4426 sishw_ext.pQueryVGAConfigSpace = &sisfb_query_VGA_config_space;
4427 sishw_ext.pQueryNorthBridgeSpace = &sisfb_query_north_bridge_space;
4429 /* Find systems for special custom timing */
4430 if(SiS_Pr.SiS_CustomT == CUT_NONE) {
4432 unsigned char *biosver = NULL;
4433 unsigned char *biosdate = NULL;
4435 unsigned long chksum = 0;
4437 if(sishw_ext.UseROM) {
4438 biosver = sishw_ext.pjVirtualRomBase + 0x06;
4439 biosdate = sishw_ext.pjVirtualRomBase + 0x2c;
4440 for(i=0; i<32768; i++) chksum += sishw_ext.pjVirtualRomBase[i];
4445 if( (mycustomttable[i].chipID == ivideo.chip) &&
4446 ((!strlen(mycustomttable[i].biosversion)) ||
4447 (sishw_ext.UseROM &&
4448 (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
4449 ((!strlen(mycustomttable[i].biosdate)) ||
4450 (sishw_ext.UseROM &&
4451 (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
4452 ((!mycustomttable[i].bioschksum) ||
4453 (sishw_ext.UseROM &&
4454 (mycustomttable[i].bioschksum == chksum))) &&
4455 (mycustomttable[i].pcisubsysvendor == ivideo.subsysvendor) &&
4456 (mycustomttable[i].pcisubsyscard == ivideo.subsysdevice) ) {
4458 for(j=0; j<5; j++) {
4459 if(mycustomttable[i].biosFootprintAddr[j]) {
4460 if(sishw_ext.UseROM) {
4461 if(sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
4462 mycustomttable[i].biosFootprintData[j])
4464 } else footprint = FALSE;
4468 SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
4469 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
4470 mycustomttable[i].vendorName,
4471 mycustomttable[i].cardName);
4472 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
4473 mycustomttable[i].optionName);
4478 } while(mycustomttable[i].chipID);
4481 #ifdef CONFIG_FB_SIS_300
4482 /* Mode numbers for 1280x768 are different for 300 and 315 series */
4483 if(sisvga_engine == SIS_300_VGA) {
4484 sisbios_mode[MODEINDEX_1280x768].mode_no = 0x55;
4485 sisbios_mode[MODEINDEX_1280x768+1].mode_no = 0x5a;
4486 sisbios_mode[MODEINDEX_1280x768+2].mode_no = 0x5b;
4487 sisbios_mode[MODEINDEX_1280x768+3].mode_no = 0x5b;
4491 sishw_ext.pSR = vmalloc(sizeof(SIS_DSReg) * SR_BUFFER_SIZE);
4492 if (sishw_ext.pSR == NULL) {
4493 printk(KERN_ERR "sisfb: Fatal error: Allocating SRReg space failed.\n");
4497 sishw_ext.pSR[0].jIdx = sishw_ext.pSR[0].jVal = 0xFF;
4499 sishw_ext.pCR = vmalloc(sizeof(SIS_DSReg) * CR_BUFFER_SIZE);
4500 if (sishw_ext.pCR == NULL) {
4501 vfree(sishw_ext.pSR);
4502 printk(KERN_ERR "sisfb: Fatal error: Allocating CRReg space failed.\n");
4506 sishw_ext.pCR[0].jIdx = sishw_ext.pCR[0].jVal = 0xFF;
4508 #ifdef CONFIG_FB_SIS_300
4509 if(sisvga_engine == SIS_300_VGA) {
4510 if(!sisvga_enabled) {
4511 /* Mapping Max FB Size for 300 Init */
4512 sishw_ext.pjVideoMemoryAddress = ioremap(ivideo.video_base, 0x4000000);
4513 if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) {
4514 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
4517 if(sisfb_get_dram_size_300()) {
4518 vfree(sishw_ext.pSR);
4519 vfree(sishw_ext.pCR);
4520 printk(KERN_ERR "sisfb: Fatal error: Unable to determine RAM size\n");
4527 #ifdef CONFIG_FB_SIS_315
4528 if (sisvga_engine == SIS_315_VGA) {
4529 if (!sisvga_enabled) {
4530 /* Mapping Max FB Size for 315 Init */
4531 sishw_ext.pjVideoMemoryAddress = ioremap(ivideo.video_base, 0x8000000);
4532 if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) {
4533 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
4534 sishw_ext.bSkipDramSizing = TRUE;
4535 sishw_ext.pSR[0].jIdx = 0x13;
4536 sishw_ext.pSR[1].jIdx = 0x14;
4537 sishw_ext.pSR[2].jIdx = 0xFF;
4538 inSISIDXREG(SISSR, 0x13, sishw_ext.pSR[0].jVal);
4539 inSISIDXREG(SISSR, 0x14, sishw_ext.pSR[1].jVal);
4540 sishw_ext.pSR[2].jVal = 0xFF;
4543 if(sisfb_get_dram_size_315()) {
4544 vfree(sishw_ext.pSR);
4545 vfree(sishw_ext.pCR);
4546 printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
4553 if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) {
4555 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
4556 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
4558 /* Enable 2D accelerator engine */
4559 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
4563 sishw_ext.ulVideoMemorySize = ivideo.video_size;
4565 if(sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
4567 SiS_Pr.PDC = sisfb_pdc;
4572 if(!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) {
4573 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
4574 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
4575 vfree(sishw_ext.pSR);
4576 vfree(sishw_ext.pCR);
4581 if(!request_mem_region(ivideo.mmio_base, sisfb_mmio_size, "sisfb MMIO")) {
4582 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
4583 release_mem_region(ivideo.video_base, ivideo.video_size);
4584 vfree(sishw_ext.pSR);
4585 vfree(sishw_ext.pCR);
4590 ivideo.video_vbase = sishw_ext.pjVideoMemoryAddress = ioremap(ivideo.video_base, ivideo.video_size);
4591 if(!ivideo.video_vbase) {
4592 printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
4593 release_mem_region(ivideo.video_base, ivideo.video_size);
4594 release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
4595 vfree(sishw_ext.pSR);
4596 vfree(sishw_ext.pCR);
4601 ivideo.mmio_vbase = ioremap(ivideo.mmio_base, sisfb_mmio_size);
4602 if(!ivideo.mmio_vbase) {
4603 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
4604 iounmap(ivideo.video_vbase);
4605 release_mem_region(ivideo.video_base, ivideo.video_size);
4606 release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
4607 vfree(sishw_ext.pSR);
4608 vfree(sishw_ext.pCR);
4613 printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
4614 ivideo.video_base, ivideo.video_vbase, ivideo.video_size / 1024);
4616 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
4617 ivideo.mmio_base, ivideo.mmio_vbase, sisfb_mmio_size / 1024);
4619 if(sisfb_heap_init()) {
4620 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
4623 ivideo.mtrr = (unsigned int) 0;
4627 if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) {
4629 sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN;
4630 sishw_ext.Is301BDH = FALSE;
4631 sishw_ext.usExternalChip = 0;
4635 sisfb_get_VB_type();
4637 if(ivideo.vbflags & VB_VIDEOBRIDGE) {
4638 sisfb_detect_VB_connect();
4641 ivideo.currentvbflags = ivideo.vbflags & VB_VIDEOBRIDGE;
4643 if(ivideo.vbflags & VB_VIDEOBRIDGE) {
4644 if(sisfb_crt2type != -1) {
4645 if((sisfb_crt2type == CRT2_LCD) && (ivideo.vbflags & CRT2_LCD)) {
4646 ivideo.currentvbflags |= CRT2_LCD;
4647 } else if(sisfb_crt2type != CRT2_LCD) {
4648 ivideo.currentvbflags |= sisfb_crt2type;
4651 /* Chrontel 700x TV detection often unreliable, therefore use a
4652 * different default order on such machines
4654 if((sisvga_engine == SIS_300_VGA) && (ivideo.vbflags & VB_CHRONTEL)) {
4655 if(ivideo.vbflags & CRT2_LCD) ivideo.currentvbflags |= CRT2_LCD;
4656 else if(ivideo.vbflags & CRT2_TV) ivideo.currentvbflags |= CRT2_TV;
4657 else if(ivideo.vbflags & CRT2_VGA) ivideo.currentvbflags |= CRT2_VGA;
4659 if(ivideo.vbflags & CRT2_TV) ivideo.currentvbflags |= CRT2_TV;
4660 else if(ivideo.vbflags & CRT2_LCD) ivideo.currentvbflags |= CRT2_LCD;
4661 else if(ivideo.vbflags & CRT2_VGA) ivideo.currentvbflags |= CRT2_VGA;
4666 if(ivideo.vbflags & CRT2_LCD) {
4667 inSISIDXREG(SISCR, IND_SIS_LCD_PANEL, reg);
4669 if(sisvga_engine == SIS_300_VGA) {
4670 sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
4672 sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
4676 sisfb_detectedpdc = 0;
4678 #ifdef CONFIG_FB_SIS_300
4679 /* Save the current PanelDelayCompensation if the LCD is currently used */
4680 if(sisvga_engine == SIS_300_VGA) {
4681 if(ivideo.vbflags & (VB_LVDS | VB_30xBDH)) {
4683 inSISIDXREG(SISCR,0x30,tmp);
4685 /* Currently on LCD? If yes, read current pdc */
4686 inSISIDXREG(SISPART1,0x13,sisfb_detectedpdc);
4687 sisfb_detectedpdc &= 0x3c;
4688 if(SiS_Pr.PDC == 0) {
4689 /* Let option override detection */
4690 SiS_Pr.PDC = sisfb_detectedpdc;
4693 "sisfb: Detected LCD PanelDelayCompensation %d\n",
4696 if((SiS_Pr.PDC) && (SiS_Pr.PDC != sisfb_detectedpdc)) {
4698 "sisfb: Using LCD PanelDelayCompensation %d\n",
4705 sisfb_detectedlcda = 0xff;
4707 #ifdef CONFIG_FB_SIS_315
4709 if(sisvga_engine == SIS_315_VGA) {
4711 if(ivideo.vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
4713 inSISIDXREG(SISCR,0x30,tmp);
4715 /* Currently on LCD? If yes, read current pdc */
4716 inSISIDXREG(SISPART1,0x2D,sisfb_detectedpdc);
4717 if(SiS_Pr.PDC == 0) {
4718 /* Let option override detection */
4719 SiS_Pr.PDC = sisfb_detectedpdc;
4722 "sisfb: Detected LCD PanelDelayCompensation %d\n",
4725 if((SiS_Pr.PDC) && (SiS_Pr.PDC != sisfb_detectedpdc)) {
4727 "sisfb: Using LCD PanelDelayCompensation %d\n",
4731 if(ivideo.vbflags & (VB_302LV | VB_302ELV)) {
4732 inSISIDXREG(SISPART4,0x30,SiS_Pr.EMI_30);
4733 inSISIDXREG(SISPART4,0x31,SiS_Pr.EMI_31);
4734 inSISIDXREG(SISPART4,0x32,SiS_Pr.EMI_32);
4735 inSISIDXREG(SISPART4,0x33,SiS_Pr.EMI_33);
4736 SiS_Pr.HaveEMI = TRUE;
4737 if(tmp & 0x20) SiS_Pr.HaveEMILCD = TRUE;
4741 /* Try to find about LCDA */
4742 if(ivideo.vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
4744 inSISIDXREG(SISCR,0x34,tmp);
4745 if((tmp <= 0x13) || (tmp == 0xff)) {
4746 /* Currently on LCDA? (Some BIOSes leave CR38) */
4747 inSISIDXREG(SISCR,0x38,tmp);
4748 if((tmp & 0x03) == 0x03) SiS_Pr.SiS_UseLCDA = TRUE;
4750 /* Currently on LCDA? (Some newer BIOSes set D0 in CR35) */
4751 inSISIDXREG(SISCR,0x35,tmp);
4752 if(tmp & 0x01) SiS_Pr.SiS_UseLCDA = TRUE;
4754 /* Currently on LCD? If so, we can find out
4755 * by peeking the mode register
4757 inSISIDXREG(SISCR,0x30,tmp);
4759 inSISIDXREG(SISPART1,0x13,tmp);
4760 if(tmp & 0x04) SiS_Pr.SiS_UseLCDA = TRUE;
4765 if(SiS_Pr.SiS_UseLCDA) {
4766 sisfb_detectedlcda = 0x03;
4768 "sisfb: Bridge uses LCDA for low resolution and text modes\n");
4774 if (!sisfb_crt1off) {
4775 sisfb_handle_ddc(&sisfb_thismonitor, 0);
4777 if ((ivideo.vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
4778 (ivideo.vbflags & (CRT2_VGA | CRT2_LCD))) {
4779 sisfb_handle_ddc(&sisfb_thismonitor, 1);
4783 if (sisfb_mode_idx >= 0)
4784 sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx, ivideo.currentvbflags);
4786 if (sisfb_mode_idx < 0) {
4787 switch (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
4789 sisfb_mode_idx = DEFAULT_LCDMODE;
4792 sisfb_mode_idx = DEFAULT_TVMODE;
4795 sisfb_mode_idx = DEFAULT_MODE;
4800 sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no;
4802 if (ivideo.refresh_rate != 0)
4803 sisfb_search_refresh_rate(ivideo.refresh_rate, sisfb_mode_idx);
4805 if (sisfb_rate_idx == 0) {
4806 sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
4807 ivideo.refresh_rate = 60;
4810 if (sisfb_thismonitor.datavalid) {
4811 if(!sisfb_verify_rate(&sisfb_thismonitor, sisfb_mode_idx,
4812 sisfb_rate_idx, ivideo.refresh_rate)) {
4813 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
4817 ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp;
4818 ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres;
4819 ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres;
4820 ivideo.org_x = ivideo.org_y = 0;
4821 ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
4825 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4827 /* ---------------- For 2.4: Now switch the mode ------------------ */
4829 printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
4830 ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
4831 ivideo.refresh_rate);
4833 sisfb_pre_setmode();
4835 if (SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
4836 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
4838 vfree(sishw_ext.pSR);
4839 vfree(sishw_ext.pCR);
4840 release_mem_region(ivideo.video_base, ivideo.video_size);
4841 release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
4846 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
4848 sisfb_post_setmode();
4853 default_var.accel_flags |= FB_ACCELF_TEXT;
4857 /* Maximize regardless of sisfb_max at startup */
4858 default_var.yres_virtual = 32767;
4859 sisfb_crtc_to_var(&default_var);
4861 sis_fb_info->node = -1;
4862 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
4863 sis_fb_info->blank = &sisfb_blank;
4864 sis_fb_info->fbops = &sisfb_ops;
4865 sis_fb_info->switch_con = &sisfb_switch;
4866 sis_fb_info->updatevar = &sisfb_update_var;
4867 sis_fb_info->changevar = NULL;
4868 sis_fb_info->disp = &sis_disp;
4869 strcpy(sis_fb_info->fontname, sisfb_fontname);
4871 sisfb_set_disp(-1, &default_var, sis_fb_info);
4873 #else /* --------- For 2.5: Setup a somewhat sane default var ------------ */
4875 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
4876 ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
4877 ivideo.refresh_rate);
4879 default_var.xres = default_var.xres_virtual = ivideo.video_width;
4880 default_var.yres = default_var.yres_virtual = ivideo.video_height;
4881 default_var.bits_per_pixel = ivideo.video_bpp;
4883 sisfb_bpp_to_var(&default_var);
4885 default_var.pixclock = (u32) (1000000000 /
4886 sisfb_mode_rate_to_dclock(&SiS_Pr, &sishw_ext,
4887 sisfb_mode_no, sisfb_rate_idx));
4889 if(sisfb_mode_rate_to_ddata(&SiS_Pr, &sishw_ext,
4890 sisfb_mode_no, sisfb_rate_idx,
4891 &default_var.left_margin, &default_var.right_margin,
4892 &default_var.upper_margin, &default_var.lower_margin,
4893 &default_var.hsync_len, &default_var.vsync_len,
4894 &default_var.sync, &default_var.vmode)) {
4895 if((default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
4896 default_var.pixclock <<= 1;
4903 default_var.accel_flags |= FB_ACCELF_TEXT;
4908 /* Maximize regardless of sisfb_max at startup */
4909 default_var.yres_virtual =
4910 ivideo.heapstart / (default_var.xres * (default_var.bits_per_pixel >> 3));
4911 if(default_var.yres_virtual > 32767) default_var.yres_virtual = 32767;
4912 if(default_var.yres_virtual <= default_var.yres) {
4913 default_var.yres_virtual = default_var.yres;
4917 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
4918 sis_fb_info->var = default_var;
4919 sis_fb_info->fix = sisfb_fix;
4920 sis_fb_info->par = &ivideo;
4921 sis_fb_info->screen_base = ivideo.video_vbase;
4922 sis_fb_info->fbops = &sisfb_ops;
4924 sis_fb_info->class_dev.dev = &pdev->dev;
4926 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
4927 sis_fb_info->pseudo_palette = pseudo_palette;
4929 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
4932 printk(KERN_INFO "sisfb: Initial vbflags 0x%lx\n", ivideo.vbflags);
4935 ivideo.mtrr = mtrr_add((unsigned int) ivideo.video_base,
4936 (unsigned int) ivideo.video_size,
4937 MTRR_TYPE_WRCOMB, 1);
4939 printk(KERN_INFO "sisfb: Added MTRRs\n");
4944 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4945 vc_resize_con(1, 1, 0);
4948 if(register_framebuffer(sis_fb_info) < 0) {
4949 vfree(sishw_ext.pSR);
4950 vfree(sishw_ext.pCR);
4951 release_mem_region(ivideo.video_base, ivideo.video_size);
4952 release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
4953 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
4958 sisfb_registered = 1;
4960 printk(KERN_DEBUG "sisfb: Installed SISFB_GET_INFO ioctl (%x)\n", SISFB_GET_INFO);
4961 printk(KERN_DEBUG "sisfb: Installed SISFB_GET_VBRSTATUS ioctl (%x)\n", SISFB_GET_VBRSTATUS);
4963 printk(KERN_INFO "sisfb: 2D acceleration is %s, scrolling mode %s\n",
4964 sisfb_accel ? "enabled" : "disabled",
4965 sisfb_ypan ? (sisfb_max ? "ypan (auto-max)" : "ypan (no auto-max)") : "redraw");
4967 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4968 printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n",
4969 GET_FB_IDX(sis_fb_info->node), sis_fb_info->modename, VER_MAJOR, VER_MINOR,
4972 printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n",
4973 sis_fb_info->node, myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
4976 printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
4978 } /* if mode = "none" */
4985 static char *mode = NULL;
4986 static int vesa = -1;
4987 static unsigned int rate = 0;
4988 static unsigned int crt1off = 1;
4989 static unsigned int mem = 0;
4990 static char *forcecrt2type = NULL;
4991 static int forcecrt1 = -1;
4992 static char *queuemode = NULL;
4994 static int noaccel = -1;
4995 static int noypan = -1;
4996 static int nomax = -1;
4997 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4998 static int inverse = 0;
5000 static int userom = 1;
5001 static int useoem = -1;
5002 static char *tvstandard = NULL;
5003 static int nocrt2rate = 0;
5004 static int scalelcd = -1;
5005 static char *specialtiming = NULL;
5006 static int lvdshl = -1;
5008 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/650/651/661/740/741/330/760 framebuffer driver");
5009 MODULE_LICENSE("GPL");
5010 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>; SiS; Various others");
5012 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5013 MODULE_PARM(mode, "s");
5014 MODULE_PARM_DESC(mode,
5015 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
5016 "1024x768x16. Other formats supported include XxY-Depth and\n"
5017 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5018 "number, it will be interpreted as a VESA mode number. (default: none if\n"
5019 "sisfb is a module; this leaves the console untouched and the driver will\n"
5020 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
5021 "is in the kernel)");
5023 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5024 MODULE_PARM(mode, "s");
5025 MODULE_PARM_DESC(mode,
5026 "\nSelects the desired default display mode in the format XxYxDepth,\n"
5027 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
5028 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5029 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)");
5032 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5033 MODULE_PARM(vesa, "i");
5034 MODULE_PARM_DESC(vesa,
5035 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
5036 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
5037 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
5038 "0x0103 if sisfb is in the kernel)");
5040 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5041 MODULE_PARM(vesa, "i");
5042 MODULE_PARM_DESC(vesa,
5043 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
5044 "0x117 (default: 0x0103)");
5047 MODULE_PARM(rate, "i");
5048 MODULE_PARM_DESC(rate,
5049 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
5050 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
5051 "will be ignored (default: 60)");
5053 MODULE_PARM(crt1off, "i");
5054 MODULE_PARM_DESC(crt1off,
5055 "(Deprecated, please use forcecrt1)");
5057 MODULE_PARM(filter, "i");
5058 MODULE_PARM_DESC(filter,
5059 "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
5060 "(Possible values 0-7, default: [no filter])");
5062 MODULE_PARM(queuemode, "s");
5063 MODULE_PARM_DESC(queuemode,
5064 "\nSelects the queue mode on 315/550/65x/74x/330/760. Possible choices are AGP, VRAM,\n"
5065 "MMIO. AGP is only available if the kernel has AGP support. The queue mode is\n"
5066 "important to programs using the 2D/3D accelerator of the SiS chip. The modes\n"
5067 "require a totally different way of programming the engines. If any mode than\n"
5068 "MMIO is selected, sisfb will disable its own 2D acceleration. On\n"
5069 "300/540/630/730, this option is ignored. (default: MMIO)");
5071 /* TW: "Import" the options from the X driver */
5072 MODULE_PARM(mem, "i");
5073 MODULE_PARM_DESC(mem,
5074 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
5075 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
5076 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
5077 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
5078 "otherwise at 12288KB. On 315 and Xabre series, the heap is 1MB by default. The\n"
5079 "value is to be specified without 'KB' and should match the MaxXFBMem setting for\n"
5080 "XFree 4.x (x>=2).");
5082 MODULE_PARM(forcecrt2type, "s");
5083 MODULE_PARM_DESC(forcecrt2type,
5084 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
5085 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
5086 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
5087 "On systems with a 301(B/LV) bridge, parameters SVIDEO, COMPOSITE or SCART can be\n"
5088 "used instead of TV to override the TV detection. (default: [autodetected])");
5090 MODULE_PARM(forcecrt1, "i");
5091 MODULE_PARM_DESC(forcecrt1,
5092 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
5093 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
5094 " 0=CRT1 off) (default: [autodetected])");
5096 MODULE_PARM(pdc, "i");
5097 MODULE_PARM_DESC(pdc,
5098 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
5099 "should detect this correctly in most cases; however, sometimes this is not\n"
5100 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
5101 "on a 300 series chipset; 3 or 51 on a 315 series chipset. If the problem persists,\n"
5102 "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
5103 "and value from 0 to 255). (default: [autodetected])");
5105 MODULE_PARM(noaccel, "i");
5106 MODULE_PARM_DESC(noaccel,
5107 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
5110 MODULE_PARM(noypan, "i");
5111 MODULE_PARM_DESC(noypan,
5112 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
5113 "will be performed by redrawing the screen. (default: 0)");
5115 MODULE_PARM(nomax, "i");
5116 MODULE_PARM_DESC(nomax,
5117 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
5118 "memory for the virtual screen in order to optimize scrolling performance. If this\n"
5119 "is set to anything other than 0, sisfb will not do this and thereby enable the user\n"
5120 "to positively specify a virtual Y size of the screen using fbset. (default: 0)\n");
5122 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5123 MODULE_PARM(inverse, "i");
5124 MODULE_PARM_DESC(inverse,
5125 "\nSetting this to anything but 0 should invert the display colors, but this\n"
5126 "does not seem to work. (default: 0)");
5129 MODULE_PARM(userom, "i");
5130 MODULE_PARM_DESC(userom,
5131 "\nSetting this to 0 keeps sisfb from using the video BIOS data which is needed\n"
5132 "for some LCD and TV setup. (default: 1)");
5134 MODULE_PARM(useoem, "i");
5135 MODULE_PARM_DESC(useoem,
5136 "\nSetting this to 0 keeps sisfb from using its internel OEM data for some LCD\n"
5137 "panels and TV connector types. (default: [auto])");
5139 MODULE_PARM(tvstandard, "s");
5140 MODULE_PARM_DESC(tvstandard,
5141 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
5142 "pal and ntsc. (default: [auto])");
5144 MODULE_PARM(nocrt2rate, "i");
5145 MODULE_PARM_DESC(nocrt2rate,
5146 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
5147 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)");
5149 MODULE_PARM(scalelcd, "i");
5150 MODULE_PARM_DESC(scalelcd,
5151 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
5152 "native resolution. Setting it to 0 will disable scaling; if the panel can scale\n"
5153 "by itself, it will probably do this, otherwise you will see a black bar around\n"
5154 "the screen image. Default: [autodetect if panel can scale]");
5156 MODULE_PARM(specialtiming, "s");
5158 MODULE_PARM(lvdshl, "i");
5161 int init_module(void)
5165 SiS_Pr.UsePanelScaler = -1;
5166 SiS_Pr.SiS_CustomT = CUT_NONE;
5169 ivideo.refresh_rate = sisfb_parm_rate = rate;
5171 if((scalelcd == 0) || (scalelcd == 1)) {
5172 SiS_Pr.UsePanelScaler = scalelcd ^ 1;
5176 sisfb_search_mode(mode, FALSE);
5178 sisfb_search_vesamode(vesa, FALSE);
5180 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5181 /* For 2.4, set mode=none if no mode is given */
5182 sisfb_mode_idx = MODE_INDEX_NONE;
5184 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5185 /* For 2.5, we don't need this "mode=none" stuff anymore */
5186 sisfb_mode_idx = DEFAULT_MODE;
5190 sisfb_search_crt2type(forcecrt2type);
5193 sisfb_search_tvstd(tvstandard);
5200 sisfb_forcecrt1 = forcecrt1;
5203 else if(forcecrt1 == 0)
5206 if(noaccel == 1) sisfb_accel = 0;
5207 else if(noaccel == 0) sisfb_accel = 1;
5209 if(noypan == 1) sisfb_ypan = 0;
5210 else if(noypan == 0) sisfb_ypan = 1;
5212 if(nomax == 1) sisfb_max = 0;
5213 else if(nomax == 0) sisfb_max = 1;
5215 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5216 if(inverse) sisfb_inverse = 1;
5217 sisfb_fontname[0] = '\0';
5220 if(mem) sisfb_mem = mem;
5222 sisfb_userom = userom;
5224 sisfb_useoem = useoem;
5226 if (queuemode) sisfb_search_queuemode(queuemode);
5228 /* If other queuemode than MMIO, disable 2D accel and ypan */
5229 if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
5233 if(pdc) sisfb_pdc = pdc & 0x3c;
5235 sisfb_nocrt2rate = nocrt2rate;
5238 sisfb_search_specialtiming(specialtiming);
5240 if((lvdshl >= 0) && (lvdshl <= 3)) SiS_Pr.LVDSHL = lvdshl;
5242 if((err = sisfb_init()) < 0) return err;
5247 void cleanup_module(void)
5250 iounmap(ivideo.video_vbase);
5251 iounmap(ivideo.mmio_vbase);
5253 /* Release mem regions */
5254 release_mem_region(ivideo.video_base, ivideo.video_size);
5255 release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
5258 /* Release MTRR region */
5260 mtrr_del(ivideo.mtrr,
5261 (unsigned int)ivideo.video_base,
5262 (unsigned int)ivideo.video_size);
5266 /* Unregister the framebuffer */
5267 if(sisfb_registered) {
5268 unregister_framebuffer(sis_fb_info);
5269 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (defined(NEWFBDEV))
5270 framebuffer_release(sis_fb_info);
5276 if(sishw_ext.pSR) vfree(sishw_ext.pSR);
5277 if(sishw_ext.pCR) vfree(sishw_ext.pCR);
5279 /* TODO: Restore the initial mode
5280 * This sounds easy but is as good as impossible
5281 * on many machines with SiS chip and video bridge
5282 * since text modes are always set up differently
5283 * from machine to machine. Depends on the type
5284 * of integration between chipset and bridge.
5287 printk(KERN_INFO "sisfb: Module unloaded\n");
5292 EXPORT_SYMBOL(sis_malloc);
5293 EXPORT_SYMBOL(sis_free);
5294 EXPORT_SYMBOL(sis_dispinfo);
5296 EXPORT_SYMBOL(ivideo);