2 * SiS 300/540/630[S]/730[S],
3 * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
5 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
7 * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the named License,
12 * or any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
23 * Author: Thomas Winischhofer <thomas@winischhofer.net>
25 * Author of (practically wiped) code base:
27 * Copyright (C) 1999 Silicon Integrated Systems, Inc.
29 * See http://www.winischhofer.net/ for more information and updates
31 * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
32 * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
36 #include <linux/version.h>
37 #include <linux/module.h>
38 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
39 #include <linux/moduleparam.h>
41 #include <linux/kernel.h>
42 #include <linux/smp_lock.h>
43 #include <linux/spinlock.h>
44 #include <linux/errno.h>
45 #include <linux/string.h>
48 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
49 #include <linux/tty.h>
51 #include <linux/screen_info.h>
54 #include <linux/slab.h>
56 #include <linux/selection.h>
57 #include <linux/ioport.h>
58 #include <linux/init.h>
59 #include <linux/pci.h>
60 #include <linux/vmalloc.h>
61 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
62 #include <linux/vt_kern.h>
64 #include <linux/capability.h>
66 #include <linux/types.h>
67 #include <asm/uaccess.h>
73 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
74 #include <video/fbcon.h>
75 #include <video/fbcon-cfb8.h>
76 #include <video/fbcon-cfb16.h>
77 #include <video/fbcon-cfb24.h>
78 #include <video/fbcon-cfb32.h>
84 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
85 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
86 #error "This version of sisfb requires at least 2.6.3"
90 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
92 extern struct display_switch fbcon_sis8;
94 #ifdef FBCON_HAS_CFB16
95 extern struct display_switch fbcon_sis16;
97 #ifdef FBCON_HAS_CFB32
98 extern struct display_switch fbcon_sis32;
102 static void sisfb_handle_command(struct sis_video_info *ivideo,
103 struct sisfb_cmd *sisfb_command);
105 /* ------------------ Internal helper routines ----------------- */
108 sisfb_setdefaultparms(void)
118 /* Module: "None" for 2.4, default mode for 2.5+ */
119 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
122 sisfb_mode_idx = MODE_INDEX_NONE;
125 /* Static: Default mode */
128 sisfb_parm_rate = -1;
130 sisfb_forcecrt1 = -1;
136 sisfb_specialtiming = CUT_NONE;
142 sisfb_tvxposoffset = 0;
143 sisfb_tvyposoffset = 0;
144 sisfb_nocrt2rate = 0;
145 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
147 sisfb_fontname[0] = 0;
149 #if !defined(__i386__) && !defined(__x86_64__)
155 /* ------------- Parameter parsing -------------- */
157 static void __devinit
158 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
162 /* We don't know the hardware specs yet and there is no ivideo */
165 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
166 sisfb_mode_idx = MODE_INDEX_NONE;
169 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
171 sisfb_mode_idx = DEFAULT_MODE;
176 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
178 while(sisbios_mode[i++].mode_no[0] != 0) {
179 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
180 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
182 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
183 sisbios_mode[i-1].mode_no[1] == 0x56 ||
184 sisbios_mode[i-1].mode_no[1] == 0x53)
187 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
188 sisbios_mode[i-1].mode_no[1] == 0x5b)
191 sisfb_mode_idx = i - 1;
197 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
200 static void __devinit
201 sisfb_search_mode(char *name, BOOLEAN quiet)
203 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
205 char strbuf[16], strbuf1[20];
206 char *nameptr = name;
208 /* We don't know the hardware specs yet and there is no ivideo */
212 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
214 sisfb_mode_idx = DEFAULT_MODE;
218 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
219 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
221 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
223 sisfb_mode_idx = DEFAULT_MODE;
227 if(strlen(name) <= 19) {
228 strcpy(strbuf1, name);
229 for(i = 0; i < strlen(strbuf1); i++) {
230 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
233 /* This does some fuzzy mode naming detection */
234 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
235 if((rate <= 32) || (depth > 32)) {
236 j = rate; rate = depth; depth = j;
238 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
240 sisfb_parm_rate = rate;
241 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
242 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
246 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
247 sprintf(strbuf, "%ux%ux8", xres, yres);
250 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
257 while(sisbios_mode[i].mode_no[0] != 0) {
258 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
260 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
261 sisbios_mode[i-1].mode_no[1] == 0x56 ||
262 sisbios_mode[i-1].mode_no[1] == 0x53)
265 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
266 sisbios_mode[i-1].mode_no[1] == 0x5b)
269 sisfb_mode_idx = i - 1;
276 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
280 static void __devinit
281 sisfb_get_vga_mode_from_kernel(void)
285 int mydepth = screen_info.lfb_depth;
287 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
289 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
290 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
291 (mydepth >= 8) && (mydepth <= 32) ) {
293 if(mydepth == 24) mydepth = 32;
295 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
296 screen_info.lfb_height,
300 "sisfb: Using vga mode %s pre-set by kernel as default\n",
303 sisfb_search_mode(mymode, TRUE);
311 sisfb_search_crt2type(const char *name)
315 /* We don't know the hardware specs yet and there is no ivideo */
317 if(name == NULL) return;
319 while(sis_crt2type[i].type_no != -1) {
320 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
321 sisfb_crt2type = sis_crt2type[i].type_no;
322 sisfb_tvplug = sis_crt2type[i].tvplug_no;
323 sisfb_crt2flags = sis_crt2type[i].flags;
329 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
330 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
332 if(sisfb_crt2type < 0)
333 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
337 sisfb_search_tvstd(const char *name)
341 /* We don't know the hardware specs yet and there is no ivideo */
346 while(sis_tvtype[i].type_no != -1) {
347 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
348 sisfb_tvstd = sis_tvtype[i].type_no;
356 sisfb_search_specialtiming(const char *name)
359 BOOLEAN found = FALSE;
361 /* We don't know the hardware specs yet and there is no ivideo */
366 if(!strnicmp(name, "none", 4)) {
367 sisfb_specialtiming = CUT_FORCENONE;
368 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
370 while(mycustomttable[i].chipID != 0) {
371 if(!strnicmp(name,mycustomttable[i].optionName,
372 strlen(mycustomttable[i].optionName))) {
373 sisfb_specialtiming = mycustomttable[i].SpecialID;
375 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
376 mycustomttable[i].vendorName,
377 mycustomttable[i].cardName,
378 mycustomttable[i].optionName);
384 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
385 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
387 while(mycustomttable[i].chipID != 0) {
388 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
389 mycustomttable[i].optionName,
390 mycustomttable[i].vendorName,
391 mycustomttable[i].cardName);
398 /* ----------- Various detection routines ----------- */
400 static void __devinit
401 sisfb_detect_custom_timing(struct sis_video_info *ivideo)
403 unsigned char *biosver = NULL;
404 unsigned char *biosdate = NULL;
409 if(ivideo->SiS_Pr.UseROM) {
410 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
411 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
412 for(i = 0; i < 32768; i++)
413 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
418 if( (mycustomttable[i].chipID == ivideo->chip) &&
419 ((!strlen(mycustomttable[i].biosversion)) ||
420 (ivideo->SiS_Pr.UseROM &&
421 (!strncmp(mycustomttable[i].biosversion, biosver,
422 strlen(mycustomttable[i].biosversion))))) &&
423 ((!strlen(mycustomttable[i].biosdate)) ||
424 (ivideo->SiS_Pr.UseROM &&
425 (!strncmp(mycustomttable[i].biosdate, biosdate,
426 strlen(mycustomttable[i].biosdate))))) &&
427 ((!mycustomttable[i].bioschksum) ||
428 (ivideo->SiS_Pr.UseROM &&
429 (mycustomttable[i].bioschksum == chksum))) &&
430 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
431 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
433 for(j = 0; j < 5; j++) {
434 if(mycustomttable[i].biosFootprintAddr[j]) {
435 if(ivideo->SiS_Pr.UseROM) {
436 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
437 mycustomttable[i].biosFootprintData[j]) {
445 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
446 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
447 mycustomttable[i].vendorName,
448 mycustomttable[i].cardName);
449 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
450 mycustomttable[i].optionName);
455 } while(mycustomttable[i].chipID);
458 static BOOLEAN __devinit
459 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
461 int i, j, xres, yres, refresh, index;
464 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
465 buffer[2] != 0xff || buffer[3] != 0xff ||
466 buffer[4] != 0xff || buffer[5] != 0xff ||
467 buffer[6] != 0xff || buffer[7] != 0x00) {
468 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
472 if(buffer[0x12] != 0x01) {
473 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
478 monitor->feature = buffer[0x18];
480 if(!buffer[0x14] & 0x80) {
481 if(!(buffer[0x14] & 0x08)) {
483 "sisfb: WARNING: Monitor does not support separate syncs\n");
487 if(buffer[0x13] >= 0x01) {
488 /* EDID V1 rev 1 and 2: Search for monitor descriptor
493 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
494 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
495 buffer[j + 4] == 0x00) {
496 monitor->hmin = buffer[j + 7];
497 monitor->hmax = buffer[j + 8];
498 monitor->vmin = buffer[j + 5];
499 monitor->vmax = buffer[j + 6];
500 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
501 monitor->datavalid = TRUE;
508 if(!monitor->datavalid) {
509 /* Otherwise: Get a range from the list of supported
510 * Estabished Timings. This is not entirely accurate,
511 * because fixed frequency monitors are not supported
514 monitor->hmin = 65535; monitor->hmax = 0;
515 monitor->vmin = 65535; monitor->vmax = 0;
516 monitor->dclockmax = 0;
517 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
518 for(i = 0; i < 13; i++) {
519 if(emodes & sisfb_ddcsmodes[i].mask) {
520 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
521 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
522 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
523 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
524 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
528 for(i = 0; i < 8; i++) {
529 xres = (buffer[index] + 31) * 8;
530 switch(buffer[index + 1] & 0xc0) {
531 case 0xc0: yres = (xres * 9) / 16; break;
532 case 0x80: yres = (xres * 4) / 5; break;
533 case 0x40: yres = (xres * 3) / 4; break;
534 default: yres = xres; break;
536 refresh = (buffer[index + 1] & 0x3f) + 60;
537 if((xres >= 640) && (yres >= 480)) {
538 for(j = 0; j < 8; j++) {
539 if((xres == sisfb_ddcfmodes[j].x) &&
540 (yres == sisfb_ddcfmodes[j].y) &&
541 (refresh == sisfb_ddcfmodes[j].v)) {
542 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
543 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
544 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
545 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
546 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
552 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
553 monitor->datavalid = TRUE;
557 return monitor->datavalid;
560 static void __devinit
561 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
563 unsigned short temp, i, realcrtno = crtno;
564 unsigned char buffer[256];
566 monitor->datavalid = FALSE;
569 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
570 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
574 if((ivideo->sisfb_crt1off) && (!crtno))
577 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
578 realcrtno, 0, &buffer[0], ivideo->vbflags2);
579 if((!temp) || (temp == 0xffff)) {
580 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
583 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
584 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
586 (temp & 0x1a) ? "" : "[none of the supported]",
587 (temp & 0x02) ? "2 " : "",
588 (temp & 0x08) ? "D&P" : "",
589 (temp & 0x10) ? "FPDI-2" : "");
591 i = 3; /* Number of retrys */
593 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
594 realcrtno, 1, &buffer[0], ivideo->vbflags2);
595 } while((temp) && i--);
597 if(sisfb_interpret_edid(monitor, &buffer[0])) {
598 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
599 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
600 monitor->dclockmax / 1000);
602 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
605 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
608 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
613 /* -------------- Mode validation --------------- */
616 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
617 int mode_idx, int rate_idx, int rate)
620 unsigned int dclock, hsync;
622 if(!monitor->datavalid)
628 /* Skip for 320x200, 320x240, 640x400 */
629 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
640 #ifdef CONFIG_FB_SIS_315
643 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
647 if(rate < (monitor->vmin - 1))
649 if(rate > (monitor->vmax + 1))
652 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
653 sisbios_mode[mode_idx].mode_no[ivideo->mni],
654 &htotal, &vtotal, rate_idx)) {
655 dclock = (htotal * vtotal * rate) / 1000;
656 if(dclock > (monitor->dclockmax + 1000))
658 hsync = dclock / htotal;
659 if(hsync < (monitor->hmin - 1))
661 if(hsync > (monitor->hmax + 1))
670 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
672 u16 xres=0, yres, myres;
674 #ifdef CONFIG_FB_SIS_300
675 if(ivideo->sisvga_engine == SIS_300_VGA) {
676 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
680 #ifdef CONFIG_FB_SIS_315
681 if(ivideo->sisvga_engine == SIS_315_VGA) {
682 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
687 myres = sisbios_mode[myindex].yres;
689 switch(vbflags & VB_DISPTYPE_DISP2) {
692 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
694 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
695 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
696 if(sisbios_mode[myindex].xres > xres)
702 if(ivideo->sisfb_fstn) {
703 if(sisbios_mode[myindex].xres == 320) {
705 switch(sisbios_mode[myindex].mode_no[1]) {
706 case 0x50: myindex = MODE_FSTN_8; break;
707 case 0x56: myindex = MODE_FSTN_16; break;
708 case 0x53: return -1;
714 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
715 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
716 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
722 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
723 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
729 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
730 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
740 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
743 u16 xres = sisbios_mode[mode_idx].xres;
744 u16 yres = sisbios_mode[mode_idx].yres;
746 ivideo->rate_idx = 0;
747 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
748 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
749 if(sisfb_vrate[i].refresh == rate) {
750 ivideo->rate_idx = sisfb_vrate[i].idx;
752 } else if(sisfb_vrate[i].refresh > rate) {
753 if((sisfb_vrate[i].refresh - rate) <= 3) {
754 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
755 rate, sisfb_vrate[i].refresh);
756 ivideo->rate_idx = sisfb_vrate[i].idx;
757 ivideo->refresh_rate = sisfb_vrate[i].refresh;
758 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
759 && (sisfb_vrate[i].idx != 1)) {
760 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
761 rate, sisfb_vrate[i-1].refresh);
762 ivideo->rate_idx = sisfb_vrate[i-1].idx;
763 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
766 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
767 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
768 rate, sisfb_vrate[i].refresh);
769 ivideo->rate_idx = sisfb_vrate[i].idx;
775 if(ivideo->rate_idx > 0) {
776 return ivideo->rate_idx;
778 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
785 sisfb_bridgeisslave(struct sis_video_info *ivideo)
789 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
792 inSISIDXREG(SISPART1,0x00,P1_00);
793 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
794 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
802 sisfballowretracecrt1(struct sis_video_info *ivideo)
806 inSISIDXREG(SISCR,0x17,temp);
810 inSISIDXREG(SISSR,0x1f,temp);
818 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
820 if(!sisfballowretracecrt1(ivideo))
823 if(inSISREG(SISINPSTAT) & 0x08)
830 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
834 if(!sisfballowretracecrt1(ivideo))
838 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
840 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
844 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
846 unsigned char temp, reg;
848 switch(ivideo->sisvga_engine) {
849 case SIS_300_VGA: reg = 0x25; break;
850 case SIS_315_VGA: reg = 0x30; break;
851 default: return FALSE;
854 inSISIDXREG(SISPART1, reg, temp);
862 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
864 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
865 if(!sisfb_bridgeisslave(ivideo)) {
866 return sisfbcheckvretracecrt2(ivideo);
869 return sisfbcheckvretracecrt1(ivideo);
873 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
875 u8 idx, reg1, reg2, reg3, reg4;
878 (*vcount) = (*hcount) = 0;
880 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
882 ret |= (FB_VBLANK_HAVE_VSYNC |
883 FB_VBLANK_HAVE_HBLANK |
884 FB_VBLANK_HAVE_VBLANK |
885 FB_VBLANK_HAVE_VCOUNT |
886 FB_VBLANK_HAVE_HCOUNT);
887 switch(ivideo->sisvga_engine) {
888 case SIS_300_VGA: idx = 0x25; break;
890 case SIS_315_VGA: idx = 0x30; break;
892 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
893 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
894 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
895 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
896 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
897 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
898 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
899 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
900 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
902 } else if(sisfballowretracecrt1(ivideo)) {
904 ret |= (FB_VBLANK_HAVE_VSYNC |
905 FB_VBLANK_HAVE_VBLANK |
906 FB_VBLANK_HAVE_VCOUNT |
907 FB_VBLANK_HAVE_HCOUNT);
908 reg1 = inSISREG(SISINPSTAT);
909 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
910 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
911 inSISIDXREG(SISCR,0x20,reg1);
912 inSISIDXREG(SISCR,0x1b,reg1);
913 inSISIDXREG(SISCR,0x1c,reg2);
914 inSISIDXREG(SISCR,0x1d,reg3);
915 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
916 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
923 sisfb_myblank(struct sis_video_info *ivideo, int blank)
925 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
926 BOOLEAN backlight = TRUE;
929 case FB_BLANK_UNBLANK: /* on */
938 case FB_BLANK_NORMAL: /* blank */
947 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
956 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
965 case FB_BLANK_POWERDOWN: /* off */
978 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
980 if( (!ivideo->sisfb_thismonitor.datavalid) ||
981 ((ivideo->sisfb_thismonitor.datavalid) &&
982 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
984 if(ivideo->sisvga_engine == SIS_315_VGA) {
985 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
988 if(!(sisfb_bridgeisslave(ivideo))) {
989 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
990 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
996 if(ivideo->currentvbflags & CRT2_LCD) {
998 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
1000 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
1002 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
1004 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1005 #ifdef CONFIG_FB_SIS_315
1006 if(ivideo->vbflags2 & VB2_CHRONTEL) {
1008 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
1010 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
1016 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
1017 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
1018 ((ivideo->sisvga_engine == SIS_315_VGA) &&
1019 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
1020 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
1023 if(ivideo->sisvga_engine == SIS_300_VGA) {
1024 if((ivideo->vbflags2 & VB2_30xB) &&
1025 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1026 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
1028 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1029 if((ivideo->vbflags2 & VB2_30xB) &&
1030 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1031 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1035 } else if(ivideo->currentvbflags & CRT2_VGA) {
1037 if(ivideo->vbflags2 & VB2_30xB) {
1038 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1046 /* ------------- Callbacks from init.c/init301.c -------------- */
1048 #ifdef CONFIG_FB_SIS_300
1050 sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1052 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1055 pci_read_config_dword(ivideo->nbridge, reg, &val);
1056 return (unsigned int)val;
1060 sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1062 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1064 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1068 sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1070 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1073 if(!ivideo->lpcdev) return 0;
1075 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1076 return (unsigned int)val;
1080 #ifdef CONFIG_FB_SIS_315
1082 sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1084 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1086 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1090 sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1092 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1095 if(!ivideo->lpcdev) return 0;
1097 pci_read_config_word(ivideo->lpcdev, reg, &val);
1098 return (unsigned int)val;
1102 /* ----------- FBDev related routines for all series ----------- */
1105 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1107 return (var->bits_per_pixel == 8) ? 256 : 16;
1111 sisfb_set_vparms(struct sis_video_info *ivideo)
1113 switch(ivideo->video_bpp) {
1115 ivideo->DstColor = 0x0000;
1116 ivideo->SiS310_AccelDepth = 0x00000000;
1117 ivideo->video_cmap_len = 256;
1120 ivideo->DstColor = 0x8000;
1121 ivideo->SiS310_AccelDepth = 0x00010000;
1122 ivideo->video_cmap_len = 16;
1125 ivideo->DstColor = 0xC000;
1126 ivideo->SiS310_AccelDepth = 0x00020000;
1127 ivideo->video_cmap_len = 16;
1130 ivideo->video_cmap_len = 16;
1131 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1137 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1139 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1141 if(maxyres > 32767) maxyres = 32767;
1147 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1149 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1150 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1151 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1152 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1153 ivideo->scrnpitchCRT1 <<= 1;
1159 sisfb_set_pitch(struct sis_video_info *ivideo)
1161 BOOLEAN isslavemode = FALSE;
1162 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1163 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1165 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
1167 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1168 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1169 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1170 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1173 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1174 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1175 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1176 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1177 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1182 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1184 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1186 switch(var->bits_per_pixel) {
1188 var->red.offset = var->green.offset = var->blue.offset = 0;
1189 var->red.length = var->green.length = var->blue.length = 6;
1192 var->red.offset = 11;
1193 var->red.length = 5;
1194 var->green.offset = 5;
1195 var->green.length = 6;
1196 var->blue.offset = 0;
1197 var->blue.length = 5;
1198 var->transp.offset = 0;
1199 var->transp.length = 0;
1202 var->red.offset = 16;
1203 var->red.length = 8;
1204 var->green.offset = 8;
1205 var->green.length = 8;
1206 var->blue.offset = 0;
1207 var->blue.length = 8;
1208 var->transp.offset = 24;
1209 var->transp.length = 8;
1215 sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1217 unsigned short modeno = ivideo->mode_no;
1219 /* >=2.6.12's fbcon clears the screen anyway */
1220 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
1221 if(!clrscrn) modeno |= 0x80;
1226 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1228 sisfb_pre_setmode(ivideo);
1230 if(SiSSetMode(&ivideo->SiS_Pr, modeno) == 0) {
1231 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1235 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1237 sisfb_post_setmode(ivideo);
1244 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1246 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1247 unsigned int htotal = 0, vtotal = 0;
1248 unsigned int drate = 0, hrate = 0;
1249 int found_mode = 0, ret;
1253 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1255 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1257 pixclock = var->pixclock;
1259 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1260 vtotal += var->yres;
1262 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1263 vtotal += var->yres;
1265 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1266 vtotal += var->yres;
1268 } else vtotal += var->yres;
1270 if(!(htotal) || !(vtotal)) {
1271 DPRINTK("sisfb: Invalid 'var' information\n");
1275 if(pixclock && htotal && vtotal) {
1276 drate = 1000000000 / pixclock;
1277 hrate = (drate * 1000) / htotal;
1278 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1280 ivideo->refresh_rate = 60;
1283 old_mode = ivideo->sisfb_mode_idx;
1284 ivideo->sisfb_mode_idx = 0;
1286 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1287 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1288 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1289 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1290 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1291 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1295 ivideo->sisfb_mode_idx++;
1299 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1300 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1301 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1303 ivideo->sisfb_mode_idx = -1;
1306 if(ivideo->sisfb_mode_idx < 0) {
1307 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1308 var->yres, var->bits_per_pixel);
1309 ivideo->sisfb_mode_idx = old_mode;
1313 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1314 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1315 ivideo->refresh_rate = 60;
1318 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1319 if(ivideo->sisfb_thismonitor.datavalid) {
1320 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
1321 ivideo->rate_idx, ivideo->refresh_rate)) {
1322 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1327 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1328 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1332 /* If acceleration to be used? Need to know
1333 * before pre/post_set_mode()
1336 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1337 #ifdef STUPID_ACCELF_TEXT_SHIT
1338 if(var->accel_flags & FB_ACCELF_TEXT) {
1339 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1341 info->flags |= FBINFO_HWACCEL_DISABLED;
1344 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1346 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1349 if((ret = sisfb_set_mode(ivideo, 1))) {
1353 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1354 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1355 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1357 sisfb_calc_pitch(ivideo, var);
1358 sisfb_set_pitch(ivideo);
1360 sisfb_set_vparms(ivideo);
1362 ivideo->current_width = ivideo->video_width;
1363 ivideo->current_height = ivideo->video_height;
1364 ivideo->current_bpp = ivideo->video_bpp;
1365 ivideo->current_htotal = htotal;
1366 ivideo->current_vtotal = vtotal;
1367 ivideo->current_linelength = ivideo->video_linelength;
1368 ivideo->current_pixclock = var->pixclock;
1369 ivideo->current_refresh_rate = ivideo->refresh_rate;
1370 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1371 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1379 sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1381 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1383 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1384 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1385 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1386 if(ivideo->sisvga_engine == SIS_315_VGA) {
1387 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1392 sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1394 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1395 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1396 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1397 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1398 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1399 if(ivideo->sisvga_engine == SIS_315_VGA) {
1400 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1406 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1408 if(var->xoffset > (var->xres_virtual - var->xres)) {
1411 if(var->yoffset > (var->yres_virtual - var->yres)) {
1415 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
1417 /* calculate base bpp dep. */
1418 switch(var->bits_per_pixel) {
1422 ivideo->current_base >>= 1;
1426 ivideo->current_base >>= 2;
1430 ivideo->current_base += (ivideo->video_offset >> 2);
1432 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1433 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1438 /* ------------ FBDev related routines for 2.4 series ----------- */
1440 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1442 #include "sisfb_fbdev_2_4.h"
1446 /* ------------ FBDev related routines for 2.6 series ----------- */
1448 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1451 sisfb_open(struct fb_info *info, int user)
1457 sisfb_release(struct fb_info *info, int user)
1463 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1464 unsigned transp, struct fb_info *info)
1466 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1468 if(regno >= sisfb_get_cmap_len(&info->var))
1471 switch(info->var.bits_per_pixel) {
1473 outSISREG(SISDACA, regno);
1474 outSISREG(SISDACD, (red >> 10));
1475 outSISREG(SISDACD, (green >> 10));
1476 outSISREG(SISDACD, (blue >> 10));
1477 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1478 outSISREG(SISDAC2A, regno);
1479 outSISREG(SISDAC2D, (red >> 8));
1480 outSISREG(SISDAC2D, (green >> 8));
1481 outSISREG(SISDAC2D, (blue >> 8));
1485 ((u32 *)(info->pseudo_palette))[regno] =
1487 ((green & 0xfc00) >> 5) |
1488 ((blue & 0xf800) >> 11);
1494 ((u32 *)(info->pseudo_palette))[regno] =
1495 (red << 16) | (green << 8) | (blue);
1502 sisfb_set_par(struct fb_info *info)
1506 if((err = sisfb_do_set_var(&info->var, 1, info)))
1509 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1510 sisfb_get_fix(&info->fix, info->currcon, info);
1512 sisfb_get_fix(&info->fix, -1, info);
1518 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1520 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1521 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1522 unsigned int drate = 0, hrate = 0, maxyres;
1524 int refresh_rate, search_idx, tidx;
1525 BOOLEAN recalc_clock = FALSE;
1528 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1530 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1532 pixclock = var->pixclock;
1534 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1535 vtotal += var->yres;
1537 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1538 vtotal += var->yres;
1540 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1541 vtotal += var->yres;
1544 vtotal += var->yres;
1546 if(!(htotal) || !(vtotal)) {
1547 SISFAIL("sisfb: no valid timing data");
1551 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1552 (sisbios_mode[search_idx].xres <= var->xres) ) {
1553 if( (sisbios_mode[search_idx].xres == var->xres) &&
1554 (sisbios_mode[search_idx].yres == var->yres) &&
1555 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1556 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1557 ivideo->currentvbflags)) > 0) {
1568 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1569 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1570 (var->yres <= sisbios_mode[search_idx].yres) &&
1571 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1572 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1573 ivideo->currentvbflags)) > 0) {
1583 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1584 var->xres, var->yres, var->bits_per_pixel,
1585 sisbios_mode[search_idx].xres,
1586 sisbios_mode[search_idx].yres,
1587 var->bits_per_pixel);
1588 var->xres = sisbios_mode[search_idx].xres;
1589 var->yres = sisbios_mode[search_idx].yres;
1592 "sisfb: Failed to find supported mode near %dx%dx%d\n",
1593 var->xres, var->yres, var->bits_per_pixel);
1598 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1599 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1600 (var->bits_per_pixel == 8) ) {
1601 /* Slave modes on LVDS and 301B-DH */
1603 recalc_clock = TRUE;
1604 } else if( (ivideo->current_htotal == htotal) &&
1605 (ivideo->current_vtotal == vtotal) &&
1606 (ivideo->current_pixclock == pixclock) ) {
1607 /* x=x & y=y & c=c -> assume depth change */
1608 drate = 1000000000 / pixclock;
1609 hrate = (drate * 1000) / htotal;
1610 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1611 } else if( ( (ivideo->current_htotal != htotal) ||
1612 (ivideo->current_vtotal != vtotal) ) &&
1613 (ivideo->current_pixclock == var->pixclock) ) {
1614 /* x!=x | y!=y & c=c -> invalid pixclock */
1615 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1617 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1618 } else if(ivideo->sisfb_parm_rate != -1) {
1619 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1620 refresh_rate = ivideo->sisfb_parm_rate;
1624 recalc_clock = TRUE;
1625 } else if((pixclock) && (htotal) && (vtotal)) {
1626 drate = 1000000000 / pixclock;
1627 hrate = (drate * 1000) / htotal;
1628 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1629 } else if(ivideo->current_refresh_rate) {
1630 refresh_rate = ivideo->current_refresh_rate;
1631 recalc_clock = TRUE;
1634 recalc_clock = TRUE;
1637 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1639 /* Eventually recalculate timing and clock */
1641 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1642 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1643 sisbios_mode[search_idx].mode_no[ivideo->mni],
1645 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1646 sisbios_mode[search_idx].mode_no[ivideo->mni],
1648 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1649 var->pixclock <<= 1;
1653 if(ivideo->sisfb_thismonitor.datavalid) {
1654 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1655 myrateindex, refresh_rate)) {
1657 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1661 /* Adapt RGB settings */
1662 sisfb_bpp_to_var(ivideo, var);
1664 /* Sanity check for offsets */
1665 if(var->xoffset < 0) var->xoffset = 0;
1666 if(var->yoffset < 0) var->yoffset = 0;
1668 if(var->xres > var->xres_virtual)
1669 var->xres_virtual = var->xres;
1671 if(ivideo->sisfb_ypan) {
1672 maxyres = sisfb_calc_maxyres(ivideo, var);
1673 if(ivideo->sisfb_max) {
1674 var->yres_virtual = maxyres;
1676 if(var->yres_virtual > maxyres) {
1677 var->yres_virtual = maxyres;
1680 if(var->yres_virtual <= var->yres) {
1681 var->yres_virtual = var->yres;
1684 if(var->yres != var->yres_virtual) {
1685 var->yres_virtual = var->yres;
1691 /* Truncate offsets to maximum if too high */
1692 if(var->xoffset > var->xres_virtual - var->xres) {
1693 var->xoffset = var->xres_virtual - var->xres - 1;
1696 if(var->yoffset > var->yres_virtual - var->yres) {
1697 var->yoffset = var->yres_virtual - var->yres - 1;
1700 /* Set everything else to 0 */
1701 var->red.msb_right =
1702 var->green.msb_right =
1703 var->blue.msb_right =
1704 var->transp.offset =
1705 var->transp.length =
1706 var->transp.msb_right = 0;
1712 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1714 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1717 if(var->xoffset > (var->xres_virtual - var->xres))
1720 if(var->yoffset > (var->yres_virtual - var->yres))
1723 if(var->vmode & FB_VMODE_YWRAP)
1726 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
1727 var->yoffset + info->var.yres > info->var.yres_virtual)
1730 if((err = sisfb_pan_var(ivideo, var)) < 0)
1733 info->var.xoffset = var->xoffset;
1734 info->var.yoffset = var->yoffset;
1740 sisfb_blank(int blank, struct fb_info *info)
1742 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1744 return sisfb_myblank(ivideo, blank);
1749 /* ----------- FBDev related routines for all series ---------- */
1751 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1752 static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1755 static int sisfb_ioctl(struct inode *inode, struct file *file,
1756 unsigned int cmd, unsigned long arg,
1757 struct fb_info *info)
1760 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1761 struct sis_memreq sismemreq;
1762 struct fb_vblank sisvbblank;
1767 u32 __user *argp = (u32 __user *)arg;
1771 if(!capable(CAP_SYS_RAWIO))
1774 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1777 sis_malloc(&sismemreq);
1779 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1780 sis_free((u32)sismemreq.offset);
1786 if(!capable(CAP_SYS_RAWIO))
1789 if(get_user(gpu32, argp))
1795 case FBIOGET_VBLANK:
1796 sisvbblank.count = 0;
1797 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1799 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1804 case SISFB_GET_INFO_SIZE:
1805 return put_user(sizeof(struct sisfb_info), argp);
1807 case SISFB_GET_INFO_OLD:
1808 if(ivideo->warncount++ < 10)
1810 "sisfb: Deprecated ioctl call received - update your application!\n");
1811 case SISFB_GET_INFO: /* For communication with X driver */
1812 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1813 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1814 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1815 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1816 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1817 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1818 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1819 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1820 if(ivideo->modechanged) {
1821 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1823 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1825 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1826 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1827 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1828 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1829 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1830 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1831 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1832 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1833 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1834 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1835 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1836 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1837 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1838 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1839 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1840 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1841 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1842 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1843 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1844 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1845 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1846 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1847 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1848 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1849 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1850 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1851 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1852 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1854 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1855 sizeof(ivideo->sisfb_infoblock)))
1860 case SISFB_GET_VBRSTATUS_OLD:
1861 if(ivideo->warncount++ < 10)
1863 "sisfb: Deprecated ioctl call received - update your application!\n");
1864 case SISFB_GET_VBRSTATUS:
1865 if(sisfb_CheckVBRetrace(ivideo))
1866 return put_user((u32)1, argp);
1868 return put_user((u32)0, argp);
1870 case SISFB_GET_AUTOMAXIMIZE_OLD:
1871 if(ivideo->warncount++ < 10)
1873 "sisfb: Deprecated ioctl call received - update your application!\n");
1874 case SISFB_GET_AUTOMAXIMIZE:
1875 if(ivideo->sisfb_max)
1876 return put_user((u32)1, argp);
1878 return put_user((u32)0, argp);
1880 case SISFB_SET_AUTOMAXIMIZE_OLD:
1881 if(ivideo->warncount++ < 10)
1883 "sisfb: Deprecated ioctl call received - update your application!\n");
1884 case SISFB_SET_AUTOMAXIMIZE:
1885 if(get_user(gpu32, argp))
1888 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1891 case SISFB_SET_TVPOSOFFSET:
1892 if(get_user(gpu32, argp))
1895 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1896 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1899 case SISFB_GET_TVPOSOFFSET:
1900 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1904 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1905 sizeof(struct sisfb_cmd)))
1908 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1910 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1911 sizeof(struct sisfb_cmd)))
1916 case SISFB_SET_LOCK:
1917 if(get_user(gpu32, argp))
1920 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1924 #ifdef SIS_NEW_CONFIG_COMPAT
1925 return -ENOIOCTLCMD;
1934 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1936 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1938 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1940 strcpy(fix->id, ivideo->myid);
1942 fix->smem_start = ivideo->video_base + ivideo->video_offset;
1943 fix->smem_len = ivideo->sisfb_mem;
1944 fix->type = FB_TYPE_PACKED_PIXELS;
1946 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1948 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1950 fix->line_length = ivideo->video_linelength;
1951 fix->mmio_start = ivideo->mmio_base;
1952 fix->mmio_len = ivideo->mmio_size;
1953 if(ivideo->sisvga_engine == SIS_300_VGA) {
1954 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1955 } else if((ivideo->chip == SIS_330) ||
1956 (ivideo->chip == SIS_760) ||
1957 (ivideo->chip == SIS_761)) {
1958 fix->accel = FB_ACCEL_SIS_XABRE;
1959 } else if(ivideo->chip == XGI_20) {
1960 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1961 } else if(ivideo->chip >= XGI_40) {
1962 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1964 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1970 /* ---------------- fb_ops structures ----------------- */
1972 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1973 static struct fb_ops sisfb_ops = {
1974 .owner = THIS_MODULE,
1975 .fb_get_fix = sisfb_get_fix,
1976 .fb_get_var = sisfb_get_var,
1977 .fb_set_var = sisfb_set_var,
1978 .fb_get_cmap = sisfb_get_cmap,
1979 .fb_set_cmap = sisfb_set_cmap,
1980 .fb_pan_display = sisfb_pan_display,
1981 .fb_ioctl = sisfb_ioctl
1985 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1986 static struct fb_ops sisfb_ops = {
1987 .owner = THIS_MODULE,
1988 .fb_open = sisfb_open,
1989 .fb_release = sisfb_release,
1990 .fb_check_var = sisfb_check_var,
1991 .fb_set_par = sisfb_set_par,
1992 .fb_setcolreg = sisfb_setcolreg,
1993 .fb_pan_display = sisfb_pan_display,
1994 .fb_blank = sisfb_blank,
1995 .fb_fillrect = fbcon_sis_fillrect,
1996 .fb_copyarea = fbcon_sis_copyarea,
1997 .fb_imageblit = cfb_imageblit,
1998 #ifdef CONFIG_FB_SOFT_CURSOR
1999 .fb_cursor = soft_cursor,
2001 .fb_sync = fbcon_sis_sync,
2002 #ifdef SIS_NEW_CONFIG_COMPAT
2003 .fb_compat_ioctl= sisfb_ioctl,
2005 .fb_ioctl = sisfb_ioctl
2009 /* ---------------- Chip generation dependent routines ---------------- */
2011 static struct pci_dev * __devinit
2012 sisfb_get_northbridge(int basechipid)
2014 struct pci_dev *pdev = NULL;
2015 int nbridgenum, nbridgeidx, i;
2016 static const unsigned short nbridgeids[] = {
2017 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2018 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2019 PCI_DEVICE_ID_SI_730,
2020 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2021 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2022 PCI_DEVICE_ID_SI_651,
2023 PCI_DEVICE_ID_SI_740,
2024 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
2025 PCI_DEVICE_ID_SI_741,
2026 PCI_DEVICE_ID_SI_660,
2027 PCI_DEVICE_ID_SI_760,
2028 PCI_DEVICE_ID_SI_761
2031 switch(basechipid) {
2032 #ifdef CONFIG_FB_SIS_300
2033 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2034 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2036 #ifdef CONFIG_FB_SIS_315
2037 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2038 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
2039 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
2041 default: return NULL;
2043 for(i = 0; i < nbridgenum; i++) {
2044 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2045 nbridgeids[nbridgeidx+i], NULL)))
2051 static int __devinit
2052 sisfb_get_dram_size(struct sis_video_info *ivideo)
2054 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2058 ivideo->video_size = 0;
2059 ivideo->UMAsize = ivideo->LFBsize = 0;
2061 switch(ivideo->chip) {
2062 #ifdef CONFIG_FB_SIS_300
2064 inSISIDXREG(SISSR, 0x14, reg);
2065 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2070 if(!ivideo->nbridge)
2072 pci_read_config_byte(ivideo->nbridge, 0x63, ®);
2073 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2076 #ifdef CONFIG_FB_SIS_315
2080 inSISIDXREG(SISSR, 0x14, reg);
2081 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2082 switch((reg >> 2) & 0x03) {
2085 ivideo->video_size <<= 1;
2088 ivideo->video_size += (ivideo->video_size/2);
2092 inSISIDXREG(SISSR, 0x14, reg);
2093 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2094 if(reg & 0x0c) ivideo->video_size <<= 1;
2099 inSISIDXREG(SISSR, 0x14, reg);
2100 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2104 inSISIDXREG(SISCR, 0x79, reg);
2105 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2110 inSISIDXREG(SISCR, 0x79, reg);
2111 reg = (reg & 0xf0) >> 4;
2113 ivideo->video_size = (1 << reg) << 20;
2114 ivideo->UMAsize = ivideo->video_size;
2116 inSISIDXREG(SISCR, 0x78, reg);
2120 ivideo->LFBsize = (32 << 20);
2122 ivideo->LFBsize = (64 << 20);
2124 ivideo->video_size += ivideo->LFBsize;
2130 inSISIDXREG(SISSR, 0x14, reg);
2131 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2132 if(ivideo->chip != XGI_20) {
2133 reg = (reg & 0x0c) >> 2;
2134 if(ivideo->revision_id == 2) {
2135 if(reg & 0x01) reg = 0x02;
2138 if(reg == 0x02) ivideo->video_size <<= 1;
2139 else if(reg == 0x03) ivideo->video_size <<= 2;
2149 /* -------------- video bridge device detection --------------- */
2151 static void __devinit
2152 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2156 /* No CRT2 on XGI Z7 */
2157 if(ivideo->chip == XGI_20) {
2158 ivideo->sisfb_crt1off = 0;
2162 #ifdef CONFIG_FB_SIS_300
2163 if(ivideo->sisvga_engine == SIS_300_VGA) {
2164 inSISIDXREG(SISSR, 0x17, temp);
2165 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2166 /* PAL/NTSC is stored on SR16 on such machines */
2167 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2168 inSISIDXREG(SISSR, 0x16, temp);
2170 ivideo->vbflags |= TV_PAL;
2172 ivideo->vbflags |= TV_NTSC;
2178 inSISIDXREG(SISCR, 0x32, cr32);
2180 if(cr32 & SIS_CRT1) {
2181 ivideo->sisfb_crt1off = 0;
2183 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2186 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2188 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2189 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2190 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2192 /* Check given parms for hardware compatibility.
2193 * (Cannot do this in the search_xx routines since we don't
2194 * know what hardware we are running on then)
2197 if(ivideo->chip != SIS_550) {
2198 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2201 if(ivideo->sisfb_tvplug != -1) {
2202 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2203 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2204 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2205 ivideo->sisfb_tvplug = -1;
2206 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2210 if(ivideo->sisfb_tvplug != -1) {
2211 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2212 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2213 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2214 ivideo->sisfb_tvplug = -1;
2215 printk(KERN_ERR "sisfb: HiVision not supported\n");
2219 if(ivideo->sisfb_tvstd != -1) {
2220 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2221 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2222 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2223 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2224 ivideo->sisfb_tvstd = -1;
2225 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2230 /* Detect/set TV plug & type */
2231 if(ivideo->sisfb_tvplug != -1) {
2232 ivideo->vbflags |= ivideo->sisfb_tvplug;
2234 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2235 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2236 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2238 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2239 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2243 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2244 if(ivideo->sisfb_tvstd != -1) {
2245 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2246 ivideo->vbflags |= ivideo->sisfb_tvstd;
2248 if(ivideo->vbflags & TV_SCART) {
2249 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2250 ivideo->vbflags |= TV_PAL;
2252 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2253 if(ivideo->sisvga_engine == SIS_300_VGA) {
2254 inSISIDXREG(SISSR, 0x38, temp);
2255 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2256 else ivideo->vbflags |= TV_NTSC;
2257 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2258 inSISIDXREG(SISSR, 0x38, temp);
2259 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2260 else ivideo->vbflags |= TV_NTSC;
2262 inSISIDXREG(SISCR, 0x79, temp);
2263 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2264 else ivideo->vbflags |= TV_NTSC;
2269 /* Copy forceCRT1 option to CRT1off if option is given */
2270 if(ivideo->sisfb_forcecrt1 != -1) {
2271 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2275 /* ------------------ Sensing routines ------------------ */
2277 static BOOLEAN __devinit
2278 sisfb_test_DDC1(struct sis_video_info *ivideo)
2283 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2285 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2287 return (count == -1) ? FALSE : TRUE;
2290 static void __devinit
2291 sisfb_sense_crt1(struct sis_video_info *ivideo)
2293 BOOLEAN mustwait = FALSE;
2295 #ifdef CONFIG_FB_SIS_315
2301 inSISIDXREG(SISSR,0x1F,sr1F);
2302 orSISIDXREG(SISSR,0x1F,0x04);
2303 andSISIDXREG(SISSR,0x1F,0x3F);
2304 if(sr1F & 0xc0) mustwait = TRUE;
2306 #ifdef CONFIG_FB_SIS_315
2307 if(ivideo->sisvga_engine == SIS_315_VGA) {
2308 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2310 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2314 inSISIDXREG(SISCR,0x17,cr17);
2317 orSISIDXREG(SISCR,0x17,0x80);
2319 outSISIDXREG(SISSR, 0x00, 0x01);
2320 outSISIDXREG(SISSR, 0x00, 0x03);
2324 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2327 #ifdef CONFIG_FB_SIS_315
2328 if(ivideo->chip >= SIS_330) {
2329 andSISIDXREG(SISCR,0x32,~0x20);
2330 if(ivideo->chip >= SIS_340) {
2331 outSISIDXREG(SISCR, 0x57, 0x4a);
2333 outSISIDXREG(SISCR, 0x57, 0x5f);
2335 orSISIDXREG(SISCR, 0x53, 0x02);
2336 while((inSISREG(SISINPSTAT)) & 0x01) break;
2337 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2338 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2339 andSISIDXREG(SISCR, 0x53, 0xfd);
2340 andSISIDXREG(SISCR, 0x57, 0x00);
2344 if(temp == 0xffff) {
2347 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2348 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2349 } while(((temp == 0) || (temp == 0xffff)) && i--);
2351 if((temp == 0) || (temp == 0xffff)) {
2352 if(sisfb_test_DDC1(ivideo)) temp = 1;
2356 if((temp) && (temp != 0xffff)) {
2357 orSISIDXREG(SISCR,0x32,0x20);
2360 #ifdef CONFIG_FB_SIS_315
2361 if(ivideo->sisvga_engine == SIS_315_VGA) {
2362 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2366 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2368 outSISIDXREG(SISSR,0x1F,sr1F);
2371 /* Determine and detect attached devices on SiS30x */
2372 static void __devinit
2373 SiS_SenseLCD(struct sis_video_info *ivideo)
2375 unsigned char buffer[256];
2376 unsigned short temp, realcrtno, i;
2377 u8 reg, cr37 = 0, paneltype = 0;
2380 ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2382 /* LCD detection only for TMDS bridges */
2383 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2385 if(ivideo->vbflags2 & VB2_30xBDH)
2388 /* If LCD already set up by BIOS, skip it */
2389 inSISIDXREG(SISCR, 0x32, reg);
2394 if(ivideo->SiS_Pr.DDCPortMixup)
2397 /* Check DDC capabilities */
2398 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2399 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2401 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2405 i = 3; /* Number of retrys */
2407 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2408 ivideo->sisvga_engine, realcrtno, 1,
2409 &buffer[0], ivideo->vbflags2);
2410 } while((temp) && i--);
2415 /* No digital device */
2416 if(!(buffer[0x14] & 0x80))
2419 /* First detailed timing preferred timing? */
2420 if(!(buffer[0x18] & 0x02))
2423 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2424 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2436 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2447 if((buffer[0x47] & 0x18) == 0x18)
2448 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2452 outSISIDXREG(SISCR, 0x36, paneltype);
2454 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2455 orSISIDXREG(SISCR, 0x32, 0x08);
2457 ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2460 static int __devinit
2461 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2463 int temp, mytest, result, i, j;
2465 for(j = 0; j < 10; j++) {
2467 for(i = 0; i < 3; i++) {
2469 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2470 temp = (type >> 8) | (mytest & 0x00ff);
2471 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2472 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2475 inSISIDXREG(SISPART4,0x03,temp);
2478 if(temp == mytest) result++;
2480 outSISIDXREG(SISPART4,0x11,0x00);
2481 andSISIDXREG(SISPART4,0x10,0xe0);
2482 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2485 if((result == 0) || (result >= 2)) break;
2490 static void __devinit
2491 SiS_Sense30x(struct sis_video_info *ivideo)
2493 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2494 u16 svhs=0, svhs_c=0;
2495 u16 cvbs=0, cvbs_c=0;
2496 u16 vga2=0, vga2_c=0;
2498 char stdstr[] = "sisfb: Detected";
2499 char tvstr[] = "TV connected to";
2501 if(ivideo->vbflags2 & VB2_301) {
2502 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2503 inSISIDXREG(SISPART4,0x01,myflag);
2505 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2507 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2508 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2509 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2510 svhs = 0x0200; cvbs = 0x0100;
2511 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2512 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2516 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2517 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2518 svhs_c = 0x0408; cvbs_c = 0x0808;
2522 if(ivideo->haveXGIROM) {
2523 biosflag = ivideo->bios_abase[0x58] & 0x03;
2524 } else if(ivideo->newrom) {
2525 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2526 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2527 if(ivideo->bios_abase) {
2528 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2532 if(ivideo->chip == SIS_300) {
2533 inSISIDXREG(SISSR,0x3b,myflag);
2534 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2537 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2541 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2542 orSISIDXREG(SISSR,0x1e,0x20);
2544 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2545 if(ivideo->vbflags2 & VB2_30xC) {
2546 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2548 orSISIDXREG(SISPART4,0x0d,0x04);
2550 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2552 inSISIDXREG(SISPART2,0x00,backupP2_00);
2553 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2555 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2556 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2557 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2560 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2561 SISDoSense(ivideo, 0, 0);
2564 andSISIDXREG(SISCR, 0x32, ~0x14);
2566 if(vga2_c || vga2) {
2567 if(SISDoSense(ivideo, vga2, vga2_c)) {
2568 if(biosflag & 0x01) {
2569 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2570 orSISIDXREG(SISCR, 0x32, 0x04);
2572 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2573 orSISIDXREG(SISCR, 0x32, 0x10);
2578 andSISIDXREG(SISCR, 0x32, 0x3f);
2580 if(ivideo->vbflags2 & VB2_30xCLV) {
2581 orSISIDXREG(SISPART4,0x0d,0x04);
2584 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2585 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2586 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2587 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2588 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2589 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2590 orSISIDXREG(SISCR,0x32,0x80);
2593 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2596 andSISIDXREG(SISCR, 0x32, ~0x03);
2598 if(!(ivideo->vbflags & TV_YPBPR)) {
2599 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2600 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2601 orSISIDXREG(SISCR, 0x32, 0x02);
2603 if((biosflag & 0x02) || (!result)) {
2604 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2605 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2606 orSISIDXREG(SISCR, 0x32, 0x01);
2611 SISDoSense(ivideo, 0, 0);
2613 outSISIDXREG(SISPART2,0x00,backupP2_00);
2614 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2615 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2617 if(ivideo->vbflags2 & VB2_30xCLV) {
2618 inSISIDXREG(SISPART2,0x00,biosflag);
2619 if(biosflag & 0x20) {
2620 for(myflag = 2; myflag > 0; myflag--) {
2622 outSISIDXREG(SISPART2,0x00,biosflag);
2627 outSISIDXREG(SISPART2,0x00,backupP2_00);
2630 /* Determine and detect attached TV's on Chrontel */
2631 static void __devinit
2632 SiS_SenseCh(struct sis_video_info *ivideo)
2634 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2636 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2638 #ifdef CONFIG_FB_SIS_300
2639 unsigned char test[3];
2643 if(ivideo->chip < SIS_315H) {
2645 #ifdef CONFIG_FB_SIS_300
2646 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2647 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2648 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2649 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2650 /* See Chrontel TB31 for explanation */
2651 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2652 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2653 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2654 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2656 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2657 if(temp2 != temp1) temp1 = temp2;
2659 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2660 /* Read power status */
2661 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2662 if((temp1 & 0x03) != 0x03) {
2663 /* Power all outputs */
2664 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2665 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2667 /* Sense connected TV devices */
2668 for(i = 0; i < 3; i++) {
2669 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2670 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2671 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2672 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2673 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2674 if(!(temp1 & 0x08)) test[i] = 0x02;
2675 else if(!(temp1 & 0x02)) test[i] = 0x01;
2677 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2680 if(test[0] == test[1]) temp1 = test[0];
2681 else if(test[0] == test[2]) temp1 = test[0];
2682 else if(test[1] == test[2]) temp1 = test[1];
2685 "sisfb: TV detection unreliable - test results varied\n");
2689 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2690 ivideo->vbflags |= TV_SVIDEO;
2691 orSISIDXREG(SISCR, 0x32, 0x02);
2692 andSISIDXREG(SISCR, 0x32, ~0x05);
2693 } else if (temp1 == 0x01) {
2694 printk(KERN_INFO "%s CVBS output\n", stdstr);
2695 ivideo->vbflags |= TV_AVIDEO;
2696 orSISIDXREG(SISCR, 0x32, 0x01);
2697 andSISIDXREG(SISCR, 0x32, ~0x06);
2699 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2700 andSISIDXREG(SISCR, 0x32, ~0x07);
2702 } else if(temp1 == 0) {
2703 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2704 andSISIDXREG(SISCR, 0x32, ~0x07);
2706 /* Set general purpose IO for Chrontel communication */
2707 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2712 #ifdef CONFIG_FB_SIS_315
2713 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2714 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2715 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2716 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2717 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2719 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2720 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2722 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2723 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2724 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2725 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2727 if(temp2 & 0x02) temp1 |= 0x01;
2728 if(temp2 & 0x10) temp1 |= 0x01;
2729 if(temp2 & 0x04) temp1 |= 0x02;
2730 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2733 printk(KERN_INFO "%s CVBS output\n", stdstr);
2734 ivideo->vbflags |= TV_AVIDEO;
2735 orSISIDXREG(SISCR, 0x32, 0x01);
2736 andSISIDXREG(SISCR, 0x32, ~0x06);
2739 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2740 ivideo->vbflags |= TV_SVIDEO;
2741 orSISIDXREG(SISCR, 0x32, 0x02);
2742 andSISIDXREG(SISCR, 0x32, ~0x05);
2745 printk(KERN_INFO "%s SCART output\n", stdstr);
2746 orSISIDXREG(SISCR, 0x32, 0x04);
2747 andSISIDXREG(SISCR, 0x32, ~0x03);
2750 andSISIDXREG(SISCR, 0x32, ~0x07);
2756 static void __devinit
2757 sisfb_get_VB_type(struct sis_video_info *ivideo)
2759 char stdstr[] = "sisfb: Detected";
2760 char bridgestr[] = "video bridge";
2764 /* No CRT2 on XGI Z7 */
2765 if(ivideo->chip == XGI_20)
2768 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2771 inSISIDXREG(SISPART4, 0x01, reg);
2773 ivideo->vbflags |= VB_301; /* Deprecated */
2774 ivideo->vbflags2 |= VB2_301;
2775 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2776 } else if(reg < 0xc0) {
2777 ivideo->vbflags |= VB_301B; /* Deprecated */
2778 ivideo->vbflags2 |= VB2_301B;
2779 inSISIDXREG(SISPART4,0x23,reg);
2781 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2782 ivideo->vbflags2 |= VB2_30xBDH;
2783 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2785 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2787 } else if(reg < 0xd0) {
2788 ivideo->vbflags |= VB_301C; /* Deprecated */
2789 ivideo->vbflags2 |= VB2_301C;
2790 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2791 } else if(reg < 0xe0) {
2792 ivideo->vbflags |= VB_301LV; /* Deprecated */
2793 ivideo->vbflags2 |= VB2_301LV;
2794 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2795 } else if(reg <= 0xe1) {
2796 inSISIDXREG(SISPART4,0x39,reg);
2798 ivideo->vbflags |= VB_302LV; /* Deprecated */
2799 ivideo->vbflags2 |= VB2_302LV;
2800 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2802 ivideo->vbflags |= VB_301C; /* Deprecated */
2803 ivideo->vbflags2 |= VB2_301C;
2804 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2806 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2807 ivideo->vbflags2 |= VB2_302ELV;
2808 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2814 ivideo->vbflags |= VB_302B; /* Deprecated */
2815 ivideo->vbflags2 |= VB2_302B;
2816 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2820 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2821 inSISIDXREG(SISCR, 0x37, reg);
2822 reg &= SIS_EXTERNAL_CHIP_MASK;
2824 if(ivideo->sisvga_engine == SIS_300_VGA) {
2825 #ifdef CONFIG_FB_SIS_300
2827 case SIS_EXTERNAL_CHIP_LVDS:
2828 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2829 ivideo->vbflags2 |= VB2_LVDS;
2831 case SIS_EXTERNAL_CHIP_TRUMPION:
2832 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2833 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2835 case SIS_EXTERNAL_CHIP_CHRONTEL:
2836 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2837 ivideo->vbflags2 |= VB2_CHRONTEL;
2839 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2840 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2841 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2844 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2846 } else if(ivideo->chip < SIS_661) {
2847 #ifdef CONFIG_FB_SIS_315
2849 case SIS310_EXTERNAL_CHIP_LVDS:
2850 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2851 ivideo->vbflags2 |= VB2_LVDS;
2853 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2854 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2855 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2858 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2860 } else if(ivideo->chip >= SIS_661) {
2861 #ifdef CONFIG_FB_SIS_315
2862 inSISIDXREG(SISCR, 0x38, reg);
2866 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2867 ivideo->vbflags2 |= VB2_LVDS;
2870 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2871 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2874 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2875 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2878 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2881 if(ivideo->vbflags2 & VB2_LVDS) {
2882 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2884 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2885 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2887 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2888 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2890 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2891 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2895 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2896 SiS_SenseLCD(ivideo);
2897 SiS_Sense30x(ivideo);
2898 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2899 SiS_SenseCh(ivideo);
2903 /* ---------- Engine initialization routines ------------ */
2906 sisfb_engine_init(struct sis_video_info *ivideo)
2909 /* Initialize command queue (we use MMIO only) */
2911 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2913 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2914 MMIO_CMD_QUEUE_CAP |
2918 #ifdef CONFIG_FB_SIS_300
2919 if(ivideo->sisvga_engine == SIS_300_VGA) {
2923 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2925 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2928 tq_state |= (u8)(tqueue_pos >> 8);
2929 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2931 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2933 ivideo->caps |= TURBO_QUEUE_CAP;
2937 #ifdef CONFIG_FB_SIS_315
2938 if(ivideo->sisvga_engine == SIS_315_VGA) {
2939 u32 tempq = 0, templ;
2942 if(ivideo->chip == XGI_20) {
2943 switch(ivideo->cmdQueueSize) {
2945 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2949 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2952 switch(ivideo->cmdQueueSize) {
2953 case (4 * 1024 * 1024):
2954 temp = SIS_CMD_QUEUE_SIZE_4M;
2956 case (2 * 1024 * 1024):
2957 temp = SIS_CMD_QUEUE_SIZE_2M;
2959 case (1 * 1024 * 1024):
2960 temp = SIS_CMD_QUEUE_SIZE_1M;
2964 temp = SIS_CMD_QUEUE_SIZE_512k;
2968 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2969 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2971 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2972 /* Must disable dual pipe on XGI_40. Can't do
2973 * this in MMIO mode, because it requires
2974 * setting/clearing a bit in the MMIO fire trigger
2977 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2979 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2981 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2983 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2984 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2986 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2987 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2989 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2990 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2991 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2992 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2994 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2996 sisfb_syncaccel(ivideo);
2998 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3003 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3004 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3006 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3007 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3009 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3010 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3012 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3016 ivideo->engineok = 1;
3019 static void __devinit
3020 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3025 inSISIDXREG(SISCR, 0x36, reg);
3027 if(ivideo->sisvga_engine == SIS_300_VGA) {
3028 ivideo->CRT2LCDType = sis300paneltype[reg];
3029 } else if(ivideo->chip >= SIS_661) {
3030 ivideo->CRT2LCDType = sis661paneltype[reg];
3032 ivideo->CRT2LCDType = sis310paneltype[reg];
3033 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3034 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3035 (ivideo->CRT2LCDType != LCD_320x240_3)) {
3036 ivideo->CRT2LCDType = LCD_320x240;
3041 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3042 /* For broken BIOSes: Assume 1024x768, RGB18 */
3043 ivideo->CRT2LCDType = LCD_1024x768;
3044 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3045 setSISIDXREG(SISCR,0x37,0xee,0x01);
3046 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3049 for(i = 0; i < SIS_LCD_NUMBER; i++) {
3050 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3051 ivideo->lcdxres = sis_lcd_data[i].xres;
3052 ivideo->lcdyres = sis_lcd_data[i].yres;
3053 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3058 #ifdef CONFIG_FB_SIS_300
3059 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3060 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3061 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3062 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3063 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
3064 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3065 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3066 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
3067 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3071 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3072 ivideo->lcdxres, ivideo->lcdyres);
3075 static void __devinit
3076 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3078 #ifdef CONFIG_FB_SIS_300
3079 /* Save the current PanelDelayCompensation if the LCD is currently used */
3080 if(ivideo->sisvga_engine == SIS_300_VGA) {
3081 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3083 inSISIDXREG(SISCR,0x30,tmp);
3085 /* Currently on LCD? If yes, read current pdc */
3086 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3087 ivideo->detectedpdc &= 0x3c;
3088 if(ivideo->SiS_Pr.PDC == -1) {
3089 /* Let option override detection */
3090 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3092 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3093 ivideo->detectedpdc);
3095 if((ivideo->SiS_Pr.PDC != -1) &&
3096 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3097 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3098 ivideo->SiS_Pr.PDC);
3104 #ifdef CONFIG_FB_SIS_315
3105 if(ivideo->sisvga_engine == SIS_315_VGA) {
3107 /* Try to find about LCDA */
3108 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3110 inSISIDXREG(SISPART1,0x13,tmp);
3112 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3113 ivideo->detectedlcda = 0x03;
3118 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3120 inSISIDXREG(SISCR,0x30,tmp);
3121 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3122 /* Currently on LCD? If yes, read current pdc */
3124 inSISIDXREG(SISPART1,0x2D,pdc);
3125 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3126 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3127 inSISIDXREG(SISPART1,0x35,pdc);
3128 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3129 inSISIDXREG(SISPART1,0x20,pdc);
3130 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3131 if(ivideo->newrom) {
3132 /* New ROM invalidates other PDC resp. */
3133 if(ivideo->detectedlcda != 0xff) {
3134 ivideo->detectedpdc = 0xff;
3136 ivideo->detectedpdca = 0xff;
3139 if(ivideo->SiS_Pr.PDC == -1) {
3140 if(ivideo->detectedpdc != 0xff) {
3141 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3144 if(ivideo->SiS_Pr.PDCA == -1) {
3145 if(ivideo->detectedpdca != 0xff) {
3146 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3149 if(ivideo->detectedpdc != 0xff) {
3151 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3152 ivideo->detectedpdc);
3154 if(ivideo->detectedpdca != 0xff) {
3156 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3157 ivideo->detectedpdca);
3162 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3163 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3164 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3165 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3166 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3167 ivideo->SiS_Pr.HaveEMI = TRUE;
3168 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3169 ivideo->SiS_Pr.HaveEMILCD = TRUE;
3174 /* Let user override detected PDCs (all bridges) */
3175 if(ivideo->vbflags2 & VB2_30xBLV) {
3176 if((ivideo->SiS_Pr.PDC != -1) &&
3177 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3178 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3179 ivideo->SiS_Pr.PDC);
3181 if((ivideo->SiS_Pr.PDCA != -1) &&
3182 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3183 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3184 ivideo->SiS_Pr.PDCA);
3192 /* -------------------- Memory manager routines ---------------------- */
3194 static u32 __devinit
3195 sisfb_getheapstart(struct sis_video_info *ivideo)
3197 u32 ret = ivideo->sisfb_parm_mem * 1024;
3198 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3201 /* Calculate heap start = end of memory for console
3203 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3204 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3206 * On 76x in UMA+LFB mode, the layout is as follows:
3207 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3208 * where the heap is the entire UMA area, eventually
3209 * into the LFB area if the given mem parameter is
3210 * higher than the size of the UMA memory.
3212 * Basically given by "mem" parameter
3214 * maximum = videosize - cmd_queue - hwcursor
3215 * (results in a heap of size 0)
3216 * default = SiS 300: depends on videosize
3217 * SiS 315/330/340/XGI: 32k below max
3220 if(ivideo->sisvga_engine == SIS_300_VGA) {
3221 if(ivideo->video_size > 0x1000000) {
3223 } else if(ivideo->video_size > 0x800000) {
3228 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3231 def = maxoffs - 0x8000;
3234 /* Use default for secondary card for now (FIXME) */
3235 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3241 static u32 __devinit
3242 sisfb_getheapsize(struct sis_video_info *ivideo)
3244 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3247 if(ivideo->UMAsize && ivideo->LFBsize) {
3248 if( (!ivideo->sisfb_parm_mem) ||
3249 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3250 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3251 ret = ivideo->UMAsize;
3252 max -= ivideo->UMAsize;
3254 ret = max - (ivideo->sisfb_parm_mem * 1024);
3255 max = ivideo->sisfb_parm_mem * 1024;
3257 ivideo->video_offset = ret;
3258 ivideo->sisfb_mem = max;
3260 ret = max - ivideo->heapstart;
3261 ivideo->sisfb_mem = ivideo->heapstart;
3267 static int __devinit
3268 sisfb_heap_init(struct sis_video_info *ivideo)
3272 ivideo->video_offset = 0;
3273 if(ivideo->sisfb_parm_mem) {
3274 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3275 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3276 ivideo->sisfb_parm_mem = 0;
3280 ivideo->heapstart = sisfb_getheapstart(ivideo);
3281 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3283 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3284 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3286 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3287 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3289 ivideo->sisfb_heap.vinfo = ivideo;
3291 ivideo->sisfb_heap.poha_chain = NULL;
3292 ivideo->sisfb_heap.poh_freelist = NULL;
3294 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3298 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3299 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3300 poh->size = ivideo->sisfb_heap_size;
3301 poh->offset = ivideo->heapstart;
3303 ivideo->sisfb_heap.oh_free.poh_next = poh;
3304 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3305 ivideo->sisfb_heap.oh_free.size = 0;
3306 ivideo->sisfb_heap.max_freesize = poh->size;
3308 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3309 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3310 ivideo->sisfb_heap.oh_used.size = SENTINEL;
3312 if(ivideo->cardnumber == 0) {
3313 /* For the first card, make this heap the "global" one
3314 * for old DRM (which could handle only one card)
3316 sisfb_heap = &ivideo->sisfb_heap;
3322 static struct SIS_OH *
3323 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3325 struct SIS_OHALLOC *poha;
3330 if(memheap->poh_freelist == NULL) {
3331 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3335 poha->poha_next = memheap->poha_chain;
3336 memheap->poha_chain = poha;
3338 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3340 poh = &poha->aoh[0];
3341 for(i = cOhs - 1; i != 0; i--) {
3342 poh->poh_next = poh + 1;
3346 poh->poh_next = NULL;
3347 memheap->poh_freelist = &poha->aoh[0];
3350 poh = memheap->poh_freelist;
3351 memheap->poh_freelist = poh->poh_next;
3356 static struct SIS_OH *
3357 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3359 struct SIS_OH *pohThis;
3360 struct SIS_OH *pohRoot;
3363 if(size > memheap->max_freesize) {
3364 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3365 (unsigned int) size / 1024);
3369 pohThis = memheap->oh_free.poh_next;
3371 while(pohThis != &memheap->oh_free) {
3372 if(size <= pohThis->size) {
3376 pohThis = pohThis->poh_next;
3380 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3381 (unsigned int) size / 1024);
3385 if(size == pohThis->size) {
3387 sisfb_delete_node(pohThis);
3389 pohRoot = sisfb_poh_new_node(memheap);
3393 pohRoot->offset = pohThis->offset;
3394 pohRoot->size = size;
3396 pohThis->offset += size;
3397 pohThis->size -= size;
3400 memheap->max_freesize -= size;
3402 pohThis = &memheap->oh_used;
3403 sisfb_insert_node(pohThis, pohRoot);
3409 sisfb_delete_node(struct SIS_OH *poh)
3411 poh->poh_prev->poh_next = poh->poh_next;
3412 poh->poh_next->poh_prev = poh->poh_prev;
3416 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3418 struct SIS_OH *pohTemp = pohList->poh_next;
3420 pohList->poh_next = poh;
3421 pohTemp->poh_prev = poh;
3423 poh->poh_prev = pohList;
3424 poh->poh_next = pohTemp;
3427 static struct SIS_OH *
3428 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3430 struct SIS_OH *pohThis;
3431 struct SIS_OH *poh_freed;
3432 struct SIS_OH *poh_prev;
3433 struct SIS_OH *poh_next;
3438 poh_freed = memheap->oh_used.poh_next;
3440 while(poh_freed != &memheap->oh_used) {
3441 if(poh_freed->offset == base) {
3446 poh_freed = poh_freed->poh_next;
3452 memheap->max_freesize += poh_freed->size;
3454 poh_prev = poh_next = NULL;
3455 ulUpper = poh_freed->offset + poh_freed->size;
3456 ulLower = poh_freed->offset;
3458 pohThis = memheap->oh_free.poh_next;
3460 while(pohThis != &memheap->oh_free) {
3461 if(pohThis->offset == ulUpper) {
3463 } else if((pohThis->offset + pohThis->size) == ulLower) {
3466 pohThis = pohThis->poh_next;
3469 sisfb_delete_node(poh_freed);
3471 if(poh_prev && poh_next) {
3472 poh_prev->size += (poh_freed->size + poh_next->size);
3473 sisfb_delete_node(poh_next);
3474 sisfb_free_node(memheap, poh_freed);
3475 sisfb_free_node(memheap, poh_next);
3480 poh_prev->size += poh_freed->size;
3481 sisfb_free_node(memheap, poh_freed);
3486 poh_next->size += poh_freed->size;
3487 poh_next->offset = poh_freed->offset;
3488 sisfb_free_node(memheap, poh_freed);
3492 sisfb_insert_node(&memheap->oh_free, poh_freed);
3498 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3503 poh->poh_next = memheap->poh_freelist;
3504 memheap->poh_freelist = poh;
3508 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3510 struct SIS_OH *poh = NULL;
3512 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3513 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3516 req->offset = req->size = 0;
3517 DPRINTK("sisfb: Video RAM allocation failed\n");
3519 req->offset = poh->offset;
3520 req->size = poh->size;
3521 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3522 (poh->offset + ivideo->video_vbase));
3527 sis_malloc(struct sis_memreq *req)
3529 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3531 if(&ivideo->sisfb_heap == sisfb_heap)
3532 sis_int_malloc(ivideo, req);
3534 req->offset = req->size = 0;
3538 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3540 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3542 sis_int_malloc(ivideo, req);
3545 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3548 sis_int_free(struct sis_video_info *ivideo, u32 base)
3552 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3555 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3558 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3559 (unsigned int) base);
3566 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3568 sis_int_free(ivideo, base);
3572 sis_free_new(struct pci_dev *pdev, u32 base)
3574 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3576 sis_int_free(ivideo, base);
3579 /* --------------------- SetMode routines ------------------------- */
3582 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3586 /* Check if MMIO and engines are enabled,
3587 * and sync in case they are. Can't use
3588 * ivideo->accel here, as this might have
3589 * been changed before this is called.
3591 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3592 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3593 /* MMIO and 2D/3D engine enabled? */
3594 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3595 #ifdef CONFIG_FB_SIS_300
3596 if(ivideo->sisvga_engine == SIS_300_VGA) {
3597 /* Don't care about TurboQueue. It's
3598 * enough to know that the engines
3601 sisfb_syncaccel(ivideo);
3604 #ifdef CONFIG_FB_SIS_315
3605 if(ivideo->sisvga_engine == SIS_315_VGA) {
3606 /* Check that any queue mode is
3607 * enabled, and that the queue
3608 * is not in the state of "reset"
3610 inSISIDXREG(SISSR, 0x26, cr30);
3611 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3612 sisfb_syncaccel(ivideo);
3620 sisfb_pre_setmode(struct sis_video_info *ivideo)
3622 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3625 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3627 outSISIDXREG(SISSR, 0x05, 0x86);
3629 inSISIDXREG(SISCR, 0x31, cr31);
3633 cr33 = ivideo->rate_idx & 0x0F;
3635 #ifdef CONFIG_FB_SIS_315
3636 if(ivideo->sisvga_engine == SIS_315_VGA) {
3637 if(ivideo->chip >= SIS_661) {
3638 inSISIDXREG(SISCR, 0x38, cr38);
3639 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3642 inSISIDXREG(SISCR, tvregnum, cr38);
3643 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3647 #ifdef CONFIG_FB_SIS_300
3648 if(ivideo->sisvga_engine == SIS_300_VGA) {
3650 inSISIDXREG(SISCR, tvregnum, cr38);
3654 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3655 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3656 ivideo->curFSTN = ivideo->curDSTN = 0;
3658 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3661 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3662 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3663 #ifdef CONFIG_FB_SIS_315
3664 if(ivideo->chip >= SIS_661) {
3666 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3667 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3668 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3669 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3671 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3672 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3673 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3675 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3676 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3677 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3679 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3682 } else if((ivideo->vbflags & TV_HIVISION) &&
3683 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3684 if(ivideo->chip >= SIS_661) {
3690 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3693 ivideo->currentvbflags |= TV_HIVISION;
3694 } else if(ivideo->vbflags & TV_SCART) {
3695 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3698 ivideo->currentvbflags |= TV_SCART;
3700 if(ivideo->vbflags & TV_SVIDEO) {
3701 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3702 ivideo->currentvbflags |= TV_SVIDEO;
3704 if(ivideo->vbflags & TV_AVIDEO) {
3705 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3706 ivideo->currentvbflags |= TV_AVIDEO;
3709 cr31 |= SIS_DRIVER_MODE;
3711 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3712 if(ivideo->vbflags & TV_PAL) {
3713 cr31 |= 0x01; cr35 |= 0x01;
3714 ivideo->currentvbflags |= TV_PAL;
3715 if(ivideo->vbflags & TV_PALM) {
3716 cr38 |= 0x40; cr35 |= 0x04;
3717 ivideo->currentvbflags |= TV_PALM;
3718 } else if(ivideo->vbflags & TV_PALN) {
3719 cr38 |= 0x80; cr35 |= 0x08;
3720 ivideo->currentvbflags |= TV_PALN;
3723 cr31 &= ~0x01; cr35 &= ~0x01;
3724 ivideo->currentvbflags |= TV_NTSC;
3725 if(ivideo->vbflags & TV_NTSCJ) {
3726 cr38 |= 0x40; cr35 |= 0x02;
3727 ivideo->currentvbflags |= TV_NTSCJ;
3734 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3735 cr31 |= SIS_DRIVER_MODE;
3736 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3737 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3738 ivideo->curFSTN = ivideo->sisfb_fstn;
3739 ivideo->curDSTN = ivideo->sisfb_dstn;
3743 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3744 cr31 |= SIS_DRIVER_MODE;
3745 if(ivideo->sisfb_nocrt2rate) {
3746 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3748 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3752 default: /* disable CRT2 */
3754 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3757 outSISIDXREG(SISCR, 0x30, cr30);
3758 outSISIDXREG(SISCR, 0x33, cr33);
3760 if(ivideo->chip >= SIS_661) {
3761 #ifdef CONFIG_FB_SIS_315
3762 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3763 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3764 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3765 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3767 } else if(ivideo->chip != SIS_300) {
3768 outSISIDXREG(SISCR, tvregnum, cr38);
3770 outSISIDXREG(SISCR, 0x31, cr31);
3772 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3774 sisfb_check_engine_and_sync(ivideo);
3777 /* Fix SR11 for 661 and later */
3778 #ifdef CONFIG_FB_SIS_315
3780 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3784 if(ivideo->chip >= SIS_661) {
3785 inSISIDXREG(SISSR,0x11,tmpreg);
3787 inSISIDXREG(SISSR,0x3e,tmpreg);
3788 tmpreg = (tmpreg + 1) & 0xff;
3789 outSISIDXREG(SISSR,0x3e,tmpreg);
3790 inSISIDXREG(SISSR,0x11,tmpreg);
3793 andSISIDXREG(SISSR,0x11,0x0f);
3800 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3802 if(val > 32) val = 32;
3803 if(val < -32) val = -32;
3804 ivideo->tvxpos = val;
3806 if(ivideo->sisfblocked) return;
3807 if(!ivideo->modechanged) return;
3809 if(ivideo->currentvbflags & CRT2_TV) {
3811 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3813 int x = ivideo->tvx;
3815 switch(ivideo->chronteltype) {
3819 outSISIDXREG(SISSR,0x05,0x86);
3820 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3821 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3824 /* Not supported by hardware */
3828 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3830 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3831 unsigned short temp;
3833 p2_1f = ivideo->p2_1f;
3834 p2_20 = ivideo->p2_20;
3835 p2_2b = ivideo->p2_2b;
3836 p2_42 = ivideo->p2_42;
3837 p2_43 = ivideo->p2_43;
3839 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3841 p2_1f = temp & 0xff;
3842 p2_20 = (temp & 0xf00) >> 4;
3843 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3844 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3846 p2_43 = temp & 0xff;
3847 p2_42 = (temp & 0xf00) >> 4;
3848 outSISIDXREG(SISPART2,0x1f,p2_1f);
3849 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3850 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3851 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3852 outSISIDXREG(SISPART2,0x43,p2_43);
3858 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3860 if(val > 32) val = 32;
3861 if(val < -32) val = -32;
3862 ivideo->tvypos = val;
3864 if(ivideo->sisfblocked) return;
3865 if(!ivideo->modechanged) return;
3867 if(ivideo->currentvbflags & CRT2_TV) {
3869 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3871 int y = ivideo->tvy;
3873 switch(ivideo->chronteltype) {
3877 outSISIDXREG(SISSR,0x05,0x86);
3878 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3879 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3882 /* Not supported by hardware */
3886 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3890 p2_01 = ivideo->p2_01;
3891 p2_02 = ivideo->p2_02;
3895 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3896 while((p2_01 <= 0) || (p2_02 <= 0)) {
3901 outSISIDXREG(SISPART2,0x01,p2_01);
3902 outSISIDXREG(SISPART2,0x02,p2_02);
3908 sisfb_post_setmode(struct sis_video_info *ivideo)
3910 BOOLEAN crt1isoff = FALSE;
3911 BOOLEAN doit = TRUE;
3912 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3915 #ifdef CONFIG_FB_SIS_315
3919 outSISIDXREG(SISSR, 0x05, 0x86);
3921 #ifdef CONFIG_FB_SIS_315
3922 sisfb_fixup_SR11(ivideo);
3925 /* Now we actually HAVE changed the display mode */
3926 ivideo->modechanged = 1;
3928 /* We can't switch off CRT1 if bridge is in slave mode */
3929 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3930 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3932 ivideo->sisfb_crt1off = 0;
3934 #ifdef CONFIG_FB_SIS_300
3935 if(ivideo->sisvga_engine == SIS_300_VGA) {
3936 if((ivideo->sisfb_crt1off) && (doit)) {
3943 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3946 #ifdef CONFIG_FB_SIS_315
3947 if(ivideo->sisvga_engine == SIS_315_VGA) {
3948 if((ivideo->sisfb_crt1off) && (doit)) {
3957 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3958 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3963 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3964 ivideo->currentvbflags |= VB_SINGLE_MODE;
3966 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3967 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3968 ivideo->currentvbflags |= VB_MIRROR_MODE;
3970 ivideo->currentvbflags |= VB_SINGLE_MODE;
3974 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3976 if(ivideo->currentvbflags & CRT2_TV) {
3977 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3978 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3979 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3980 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3981 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3982 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3983 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3984 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3985 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3986 if(ivideo->chronteltype == 1) {
3987 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3988 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3989 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3990 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3995 if(ivideo->tvxpos) {
3996 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3998 if(ivideo->tvypos) {
3999 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
4002 /* Eventually sync engines */
4003 sisfb_check_engine_and_sync(ivideo);
4005 /* (Re-)Initialize chip engines */
4007 sisfb_engine_init(ivideo);
4009 ivideo->engineok = 0;
4014 sisfb_reset_mode(struct sis_video_info *ivideo)
4016 if(sisfb_set_mode(ivideo, 0))
4019 sisfb_set_pitch(ivideo);
4020 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4021 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
4027 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4031 switch(sisfb_command->sisfb_cmd) {
4032 case SISFB_CMD_GETVBFLAGS:
4033 if(!ivideo->modechanged) {
4034 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4036 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4037 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4038 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
4041 case SISFB_CMD_SWITCHCRT1:
4042 /* arg[0]: 0 = off, 1 = on, 99 = query */
4043 if(!ivideo->modechanged) {
4044 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4045 } else if(sisfb_command->sisfb_arg[0] == 99) {
4047 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4048 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4049 } else if(ivideo->sisfblocked) {
4050 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4051 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4052 (sisfb_command->sisfb_arg[0] == 0)) {
4053 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4055 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4056 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4057 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4058 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4059 ivideo->sisfb_crt1off = mycrt1off;
4060 if(sisfb_reset_mode(ivideo)) {
4061 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
4064 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4069 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4070 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4071 sisfb_command->sisfb_cmd);
4076 SISINITSTATIC int __init
4077 sisfb_setup(char *options)
4081 sisfb_setdefaultparms();
4083 if(!options || !(*options))
4086 while((this_opt = strsep(&options, ",")) != NULL) {
4088 if(!(*this_opt)) continue;
4090 if(!strnicmp(this_opt, "off", 3)) {
4092 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4093 /* Need to check crt2 type first for fstn/dstn */
4094 sisfb_search_crt2type(this_opt + 14);
4095 } else if(!strnicmp(this_opt, "tvmode:",7)) {
4096 sisfb_search_tvstd(this_opt + 7);
4097 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4098 sisfb_search_tvstd(this_opt + 11);
4099 } else if(!strnicmp(this_opt, "mode:", 5)) {
4100 sisfb_search_mode(this_opt + 5, FALSE);
4101 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4102 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4103 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4104 } else if(!strnicmp(this_opt, "inverse", 7)) {
4106 /* fb_invert_cmaps(); */
4107 } else if(!strnicmp(this_opt, "font:", 5)) {
4108 if(strlen(this_opt + 5) < 40) {
4109 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4110 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4113 } else if(!strnicmp(this_opt, "rate:", 5)) {
4114 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4115 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4116 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4117 } else if(!strnicmp(this_opt, "mem:",4)) {
4118 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4119 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4120 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4121 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4122 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4123 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4125 } else if(!strnicmp(this_opt, "accel", 5)) {
4127 } else if(!strnicmp(this_opt, "noypan", 6)) {
4129 } else if(!strnicmp(this_opt, "ypan", 4)) {
4131 } else if(!strnicmp(this_opt, "nomax", 5)) {
4133 } else if(!strnicmp(this_opt, "max", 3)) {
4135 } else if(!strnicmp(this_opt, "userom:", 7)) {
4136 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4137 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4138 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4139 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4140 sisfb_nocrt2rate = 1;
4141 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4142 unsigned long temp = 2;
4143 temp = simple_strtoul(this_opt + 9, NULL, 0);
4144 if((temp == 0) || (temp == 1)) {
4145 sisfb_scalelcd = temp ^ 1;
4147 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4149 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4150 if((temp >= -32) && (temp <= 32)) {
4151 sisfb_tvxposoffset = temp;
4153 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4155 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4156 if((temp >= -32) && (temp <= 32)) {
4157 sisfb_tvyposoffset = temp;
4159 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4160 sisfb_search_specialtiming(this_opt + 14);
4161 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4163 temp = simple_strtoul(this_opt + 7, NULL, 0);
4164 if((temp >= 0) && (temp <= 3)) {
4165 sisfb_lvdshl = temp;
4167 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4168 sisfb_search_mode(this_opt, TRUE);
4169 #if !defined(__i386__) && !defined(__x86_64__)
4170 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4171 sisfb_resetcard = 1;
4172 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4173 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4176 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4185 static int __devinit
4186 sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4191 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4194 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4195 if(romptr > (0x10000 - 8))
4198 rom = rom_base + romptr;
4200 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4201 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4204 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4207 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4213 static unsigned char * __devinit
4214 sisfb_find_rom(struct pci_dev *pdev)
4216 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4217 SIS_IOTYPE1 *rom_base;
4218 unsigned char *myrombase = NULL;
4220 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4223 /* First, try the official pci ROM functions (except
4224 * on integrated chipsets which have no ROM).
4227 if(!ivideo->nbridge) {
4229 if((rom_base = pci_map_rom(pdev, &romsize))) {
4231 if(sisfb_check_rom(rom_base, ivideo)) {
4233 if((myrombase = vmalloc(65536))) {
4235 /* Work around bug in pci/rom.c: Folks forgot to check
4236 * whether the size retrieved from the BIOS image eventually
4237 * is larger than the mapped size
4239 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4240 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4242 memcpy_fromio(myrombase, rom_base,
4243 (romsize > 65536) ? 65536 : romsize);
4246 pci_unmap_rom(pdev, rom_base);
4250 if(myrombase) return myrombase;
4253 /* Otherwise do it the conventional way. */
4255 #if defined(__i386__) || defined(__x86_64__)
4257 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4259 rom_base = ioremap(temp, 65536);
4263 if(!sisfb_check_rom(rom_base, ivideo)) {
4268 if((myrombase = vmalloc(65536)))
4269 memcpy_fromio(myrombase, rom_base, 65536);
4278 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4279 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4280 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4282 rom_base = ioremap(ivideo->video_base, 65536);
4284 if(sisfb_check_rom(rom_base, ivideo)) {
4285 if((myrombase = vmalloc(65536)))
4286 memcpy_fromio(myrombase, rom_base, 65536);
4291 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4298 static void __devinit
4299 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4302 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4304 if(!ivideo->video_vbase) {
4306 "sisfb: Unable to map maximum video RAM for size detection\n");
4308 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4310 if((*mapsize) < (min << 20))
4313 if(ivideo->video_vbase) {
4315 "sisfb: Video RAM size detection limited to %dMB\n",
4316 (int)((*mapsize) >> 20));
4321 #ifdef CONFIG_FB_SIS_300
4322 static int __devinit
4323 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4325 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4326 unsigned short temp;
4330 andSISIDXREG(SISSR, 0x15, 0xFB);
4331 orSISIDXREG(SISSR, 0x15, 0x04);
4332 outSISIDXREG(SISSR, 0x13, 0x00);
4333 outSISIDXREG(SISSR, 0x14, 0xBF);
4335 for(i = 0; i < 2; i++) {
4337 for(j = 0; j < 4; j++) {
4338 writew(temp, FBAddress);
4339 if(readw(FBAddress) == temp)
4341 orSISIDXREG(SISSR, 0x3c, 0x01);
4342 inSISIDXREG(SISSR, 0x05, reg);
4343 inSISIDXREG(SISSR, 0x05, reg);
4344 andSISIDXREG(SISSR, 0x3c, 0xfe);
4345 inSISIDXREG(SISSR, 0x05, reg);
4346 inSISIDXREG(SISSR, 0x05, reg);
4351 writel(0x01234567L, FBAddress);
4352 writel(0x456789ABL, (FBAddress + 4));
4353 writel(0x89ABCDEFL, (FBAddress + 8));
4354 writel(0xCDEF0123L, (FBAddress + 12));
4356 inSISIDXREG(SISSR, 0x3b, reg);
4358 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4359 return 4; /* Channel A 128bit */
4362 if(readl((FBAddress + 4)) == 0x456789ABL)
4363 return 2; /* Channel B 64bit */
4365 return 1; /* 32bit */
4368 static int __devinit
4369 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4370 int PseudoRankCapacity, int PseudoAdrPinCount,
4371 unsigned int mapsize)
4373 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4374 unsigned short sr14;
4375 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4376 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4377 static const unsigned short SiS_DRAMType[17][5] = {
4378 {0x0C,0x0A,0x02,0x40,0x39},
4379 {0x0D,0x0A,0x01,0x40,0x48},
4380 {0x0C,0x09,0x02,0x20,0x35},
4381 {0x0D,0x09,0x01,0x20,0x44},
4382 {0x0C,0x08,0x02,0x10,0x31},
4383 {0x0D,0x08,0x01,0x10,0x40},
4384 {0x0C,0x0A,0x01,0x20,0x34},
4385 {0x0C,0x09,0x01,0x08,0x32},
4386 {0x0B,0x08,0x02,0x08,0x21},
4387 {0x0C,0x08,0x01,0x08,0x30},
4388 {0x0A,0x08,0x02,0x04,0x11},
4389 {0x0B,0x0A,0x01,0x10,0x28},
4390 {0x09,0x08,0x02,0x02,0x01},
4391 {0x0B,0x09,0x01,0x08,0x24},
4392 {0x0B,0x08,0x01,0x04,0x20},
4393 {0x0A,0x08,0x01,0x02,0x10},
4394 {0x09,0x08,0x01,0x01,0x00}
4397 for(k = 0; k <= 16; k++) {
4399 RankCapacity = buswidth * SiS_DRAMType[k][3];
4401 if(RankCapacity != PseudoRankCapacity)
4404 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4407 BankNumHigh = RankCapacity * 16 * iteration - 1;
4408 if(iteration == 3) { /* Rank No */
4409 BankNumMid = RankCapacity * 16 - 1;
4411 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4414 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4415 PhysicalAdrHigh = BankNumHigh;
4416 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4417 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4419 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4420 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4421 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4422 if(buswidth == 4) sr14 |= 0x80;
4423 else if(buswidth == 2) sr14 |= 0x40;
4424 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4425 outSISIDXREG(SISSR, 0x14, sr14);
4430 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4431 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4432 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4433 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4437 writew(((unsigned short)PhysicalAdrHigh),
4438 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4439 writew(((unsigned short)BankNumMid),
4440 (FBAddr + BankNumMid + PhysicalAdrHigh));
4441 writew(((unsigned short)PhysicalAdrHalfPage),
4442 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4443 writew(((unsigned short)PhysicalAdrOtherPage),
4444 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4447 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4454 static void __devinit
4455 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4457 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4459 int PseudoRankCapacity, PseudoAdrPinCount;
4461 buswidth = sisfb_post_300_buswidth(ivideo);
4463 for(i = 6; i >= 0; i--) {
4464 PseudoRankCapacity = 1 << i;
4465 for(j = 4; j >= 1; j--) {
4466 PseudoAdrPinCount = 15 - j;
4467 if((PseudoRankCapacity * j) <= 64) {
4468 if(sisfb_post_300_rwtest(ivideo,
4480 static void __devinit
4481 sisfb_post_sis300(struct pci_dev *pdev)
4483 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4484 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4485 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4486 u16 index, rindex, memtype = 0;
4487 unsigned int mapsize;
4489 if(!ivideo->SiS_Pr.UseROM)
4492 outSISIDXREG(SISSR, 0x05, 0x86);
4495 if(bios[0x52] & 0x80) {
4496 memtype = bios[0x52];
4498 inSISIDXREG(SISSR, 0x3a, memtype);
4503 v3 = 0x80; v6 = 0x80;
4504 if(ivideo->revision_id <= 0x13) {
4505 v1 = 0x44; v2 = 0x42;
4506 v4 = 0x44; v5 = 0x42;
4508 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4509 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4511 index = memtype * 5;
4512 rindex = index + 0x54;
4513 v1 = bios[rindex++];
4514 v2 = bios[rindex++];
4515 v3 = bios[rindex++];
4516 rindex = index + 0x7c;
4517 v4 = bios[rindex++];
4518 v5 = bios[rindex++];
4519 v6 = bios[rindex++];
4522 outSISIDXREG(SISSR, 0x28, v1);
4523 outSISIDXREG(SISSR, 0x29, v2);
4524 outSISIDXREG(SISSR, 0x2a, v3);
4525 outSISIDXREG(SISSR, 0x2e, v4);
4526 outSISIDXREG(SISSR, 0x2f, v5);
4527 outSISIDXREG(SISSR, 0x30, v6);
4532 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4534 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4536 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4537 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4541 v2 = bios[memtype + 8];
4542 v3 = bios[memtype + 16];
4543 v4 = bios[memtype + 24];
4544 v5 = bios[memtype + 32];
4545 v6 = bios[memtype + 40];
4546 v7 = bios[memtype + 48];
4547 v8 = bios[memtype + 56];
4549 if(ivideo->revision_id >= 0x80)
4551 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4552 outSISIDXREG(SISSR, 0x16, v2);
4553 outSISIDXREG(SISSR, 0x17, v3);
4554 outSISIDXREG(SISSR, 0x18, v4);
4555 outSISIDXREG(SISSR, 0x19, v5);
4556 outSISIDXREG(SISSR, 0x1a, v6);
4557 outSISIDXREG(SISSR, 0x1b, v7);
4558 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4559 andSISIDXREG(SISSR, 0x15 ,0xfb);
4560 orSISIDXREG(SISSR, 0x15, 0x04);
4562 if(bios[0x53] & 0x02) {
4563 orSISIDXREG(SISSR, 0x19, 0x20);
4566 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4567 if(ivideo->revision_id >= 0x80)
4569 outSISIDXREG(SISSR, 0x1f, v1);
4570 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4571 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4577 outSISIDXREG(SISSR, 0x23, v1);
4578 outSISIDXREG(SISSR, 0x24, v2);
4579 outSISIDXREG(SISSR, 0x25, v3);
4580 outSISIDXREG(SISSR, 0x21, 0x84);
4581 outSISIDXREG(SISSR, 0x22, 0x00);
4582 outSISIDXREG(SISCR, 0x37, 0x00);
4583 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4584 outSISIDXREG(SISPART1, 0x00, 0x00);
4585 v1 = 0x40; v2 = 0x11;
4590 outSISIDXREG(SISPART1, 0x02, v1);
4592 if(ivideo->revision_id >= 0x80)
4595 inSISIDXREG(SISPART4, 0x00, reg);
4596 if((reg == 1) || (reg == 2)) {
4597 outSISIDXREG(SISCR, 0x37, 0x02);
4598 outSISIDXREG(SISPART2, 0x00, 0x1c);
4599 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4600 if(ivideo->SiS_Pr.UseROM) {
4605 outSISIDXREG(SISPART4, 0x0d, v4);
4606 outSISIDXREG(SISPART4, 0x0e, v5);
4607 outSISIDXREG(SISPART4, 0x10, v6);
4608 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4609 inSISIDXREG(SISPART4, 0x01, reg);
4611 inSISIDXREG(SISPART4, 0x23, reg);
4614 outSISIDXREG(SISPART4, 0x23, reg);
4619 outSISIDXREG(SISSR, 0x32, v2);
4621 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4623 inSISIDXREG(SISSR, 0x16, reg);
4625 outSISIDXREG(SISCR, 0x35, reg);
4626 outSISIDXREG(SISCR, 0x83, 0x00);
4627 #if !defined(__i386__) && !defined(__x86_64__)
4628 if(sisfb_videoram) {
4629 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4630 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4631 outSISIDXREG(SISSR, 0x14, reg);
4634 /* Need to map max FB size for finding out about RAM size */
4636 sisfb_post_map_vram(ivideo, &mapsize, 4);
4638 if(ivideo->video_vbase) {
4639 sisfb_post_300_ramsize(pdev, mapsize);
4640 iounmap(ivideo->video_vbase);
4643 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4644 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4645 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4647 #if !defined(__i386__) && !defined(__x86_64__)
4654 inSISIDXREG(SISSR, 0x3a, reg);
4655 if((reg & 0x30) == 0x30) {
4656 v1 = 0x04; /* PCI */
4659 v1 = 0x14; /* AGP */
4663 outSISIDXREG(SISSR, 0x21, v1);
4664 outSISIDXREG(SISSR, 0x22, v2);
4667 sisfb_sense_crt1(ivideo);
4669 /* Set default mode, don't clear screen */
4670 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4671 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4672 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4673 ivideo->curFSTN = ivideo->curDSTN = 0;
4674 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4675 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4677 outSISIDXREG(SISSR, 0x05, 0x86);
4680 orSISIDXREG(SISSR, 0x01, 0x20);
4682 /* Save mode number in CR34 */
4683 outSISIDXREG(SISCR, 0x34, 0x2e);
4685 /* Let everyone know what the current mode is */
4686 ivideo->modeprechange = 0x2e;
4690 #ifdef CONFIG_FB_SIS_315
4692 static void __devinit
4693 sisfb_post_sis315330(struct pci_dev *pdev)
4699 static void __devinit
4700 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4705 for(i = 0; i <= (delay * 10 * 36); i++) {
4706 inSISIDXREG(SISSR, 0x05, reg);
4711 static int __devinit
4712 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4713 unsigned short pcivendor)
4715 struct pci_dev *pdev = NULL;
4716 unsigned short temp;
4719 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4720 temp = pdev->vendor;
4721 SIS_PCI_PUT_DEVICE(pdev);
4722 if(temp == pcivendor) {
4731 static int __devinit
4732 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4733 unsigned int enda, unsigned int mapsize)
4738 writel(0, ivideo->video_vbase);
4740 for(i = starta; i <= enda; i++) {
4743 writel(pos, ivideo->video_vbase + pos);
4746 sisfb_post_xgi_delay(ivideo, 150);
4748 if(readl(ivideo->video_vbase) != 0)
4751 for(i = starta; i <= enda; i++) {
4754 if(readl(ivideo->video_vbase + pos) != pos)
4763 static void __devinit
4764 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4766 unsigned int buswidth, ranksize, channelab, mapsize;
4769 static const u8 dramsr13[12 * 5] = {
4770 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4771 0x02, 0x0e, 0x0a, 0x40, 0x59,
4772 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4773 0x02, 0x0e, 0x09, 0x20, 0x55,
4774 0x02, 0x0d, 0x0a, 0x20, 0x49,
4775 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4776 0x02, 0x0e, 0x08, 0x10, 0x51,
4777 0x02, 0x0d, 0x09, 0x10, 0x45,
4778 0x02, 0x0c, 0x0a, 0x10, 0x39,
4779 0x02, 0x0d, 0x08, 0x08, 0x41,
4780 0x02, 0x0c, 0x09, 0x08, 0x35,
4781 0x02, 0x0c, 0x08, 0x04, 0x31
4783 static const u8 dramsr13_4[4 * 5] = {
4784 0x02, 0x0d, 0x09, 0x40, 0x45,
4785 0x02, 0x0c, 0x09, 0x20, 0x35,
4786 0x02, 0x0c, 0x08, 0x10, 0x31,
4787 0x02, 0x0b, 0x08, 0x08, 0x21
4790 /* Enable linear mode, disable 0xa0000 address decoding */
4791 /* We disable a0000 address decoding, because
4792 * - if running on x86, if the card is disabled, it means
4793 * that another card is in the system. We don't want
4794 * to interphere with that primary card's textmode.
4795 * - if running on non-x86, there usually is no VGA window
4798 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4800 /* Need to map max FB size for finding out about RAM size */
4801 mapsize = 256 << 20;
4802 sisfb_post_map_vram(ivideo, &mapsize, 32);
4804 if(!ivideo->video_vbase) {
4805 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4806 outSISIDXREG(SISSR, 0x13, 0x35);
4807 outSISIDXREG(SISSR, 0x14, 0x41);
4812 /* Non-interleaving */
4813 outSISIDXREG(SISSR, 0x15, 0x00);
4815 outSISIDXREG(SISSR, 0x1c, 0x00);
4817 if(ivideo->chip == XGI_20) {
4820 inSISIDXREG(SISCR, 0x97, reg);
4821 if(!(reg & 0x01)) { /* Single 32/16 */
4823 outSISIDXREG(SISSR, 0x13, 0xb1);
4824 outSISIDXREG(SISSR, 0x14, 0x52);
4825 sisfb_post_xgi_delay(ivideo, 1);
4827 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4830 outSISIDXREG(SISSR, 0x13, 0x31);
4831 outSISIDXREG(SISSR, 0x14, 0x42);
4832 sisfb_post_xgi_delay(ivideo, 1);
4833 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4837 outSISIDXREG(SISSR, 0x13, 0xb1);
4838 outSISIDXREG(SISSR, 0x14, 0x41);
4839 sisfb_post_xgi_delay(ivideo, 1);
4841 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4844 outSISIDXREG(SISSR, 0x13, 0x31);
4845 } else { /* Dual 16/8 */
4847 outSISIDXREG(SISSR, 0x13, 0xb1);
4848 outSISIDXREG(SISSR, 0x14, 0x41);
4849 sisfb_post_xgi_delay(ivideo, 1);
4851 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4854 outSISIDXREG(SISSR, 0x13, 0x31);
4855 outSISIDXREG(SISSR, 0x14, 0x31);
4856 sisfb_post_xgi_delay(ivideo, 1);
4857 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4861 outSISIDXREG(SISSR, 0x13, 0xb1);
4862 outSISIDXREG(SISSR, 0x14, 0x30);
4863 sisfb_post_xgi_delay(ivideo, 1);
4865 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4868 outSISIDXREG(SISSR, 0x13, 0x31);
4871 } else { /* XGI_40 */
4873 inSISIDXREG(SISCR, 0x97, reg);
4875 inSISIDXREG(SISSR, 0x39, reg);
4879 if(reg & 0x01) { /* DDRII */
4881 if(ivideo->revision_id == 2) {
4883 outSISIDXREG(SISSR, 0x13, 0xa1);
4884 outSISIDXREG(SISSR, 0x14, 0x44);
4886 sisfb_post_xgi_delay(ivideo, 1);
4887 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4890 outSISIDXREG(SISSR, 0x13, 0x21);
4891 outSISIDXREG(SISSR, 0x14, 0x34);
4892 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4896 outSISIDXREG(SISSR, 0x13, 0xa1);
4897 outSISIDXREG(SISSR, 0x14, 0x40);
4899 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4902 outSISIDXREG(SISSR, 0x13, 0x21);
4903 outSISIDXREG(SISSR, 0x14, 0x30);
4906 outSISIDXREG(SISSR, 0x13, 0xa1);
4907 outSISIDXREG(SISSR, 0x14, 0x4c);
4909 sisfb_post_xgi_delay(ivideo, 1);
4910 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4914 outSISIDXREG(SISSR, 0x14, 0x48);
4915 sisfb_post_xgi_delay(ivideo, 1);
4917 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4920 outSISIDXREG(SISSR, 0x13, 0x21);
4921 outSISIDXREG(SISSR, 0x14, 0x3c);
4924 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4928 outSISIDXREG(SISSR, 0x14, 0x38);
4932 sisfb_post_xgi_delay(ivideo, 1);
4937 if(ivideo->revision_id == 2) {
4939 outSISIDXREG(SISSR, 0x13, 0xa1);
4940 outSISIDXREG(SISSR, 0x14, 0x52);
4941 sisfb_post_xgi_delay(ivideo, 1);
4943 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4946 outSISIDXREG(SISSR, 0x13, 0x21);
4947 outSISIDXREG(SISSR, 0x14, 0x42);
4950 outSISIDXREG(SISSR, 0x13, 0xa1);
4951 outSISIDXREG(SISSR, 0x14, 0x5a);
4952 sisfb_post_xgi_delay(ivideo, 1);
4954 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4957 outSISIDXREG(SISSR, 0x13, 0x21);
4958 outSISIDXREG(SISSR, 0x14, 0x4a);
4960 sisfb_post_xgi_delay(ivideo, 1);
4966 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4967 sisfb_post_xgi_delay(ivideo, 1);
4969 j = (ivideo->chip == XGI_20) ? 5 : 9;
4970 k = (ivideo->chip == XGI_20) ? 12 : 4;
4972 for(i = 0; i < k; i++) {
4974 reg = (ivideo->chip == XGI_20) ?
4975 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4976 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4977 sisfb_post_xgi_delay(ivideo, 50);
4979 ranksize = (ivideo->chip == XGI_20) ?
4980 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4982 inSISIDXREG(SISSR, 0x13, reg);
4983 if(reg & 0x80) ranksize <<= 1;
4985 if(ivideo->chip == XGI_20) {
4986 if(buswidth == 16) ranksize <<= 1;
4987 else if(buswidth == 32) ranksize <<= 2;
4989 if(buswidth == 64) ranksize <<= 1;
4995 if((ranksize * l) <= 256) {
4996 while((ranksize >>= 1)) reg += 0x10;
5001 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
5002 sisfb_post_xgi_delay(ivideo, 1);
5004 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5008 iounmap(ivideo->video_vbase);
5011 static void __devinit
5012 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5016 static const u8 cs90[8 * 3] = {
5026 static const u8 csb8[8 * 3] = {
5040 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5041 if(ivideo->haveXGIROM) {
5042 v1 = ivideo->bios_abase[0x90 + index];
5043 v2 = ivideo->bios_abase[0x90 + index + 1];
5044 v3 = ivideo->bios_abase[0x90 + index + 2];
5046 outSISIDXREG(SISSR, 0x28, v1);
5047 outSISIDXREG(SISSR, 0x29, v2);
5048 outSISIDXREG(SISSR, 0x2a, v3);
5049 sisfb_post_xgi_delay(ivideo, 0x43);
5050 sisfb_post_xgi_delay(ivideo, 0x43);
5051 sisfb_post_xgi_delay(ivideo, 0x43);
5053 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5054 if(ivideo->haveXGIROM) {
5055 v1 = ivideo->bios_abase[0xb8 + index];
5056 v2 = ivideo->bios_abase[0xb8 + index + 1];
5057 v3 = ivideo->bios_abase[0xb8 + index + 2];
5059 outSISIDXREG(SISSR, 0x2e, v1);
5060 outSISIDXREG(SISSR, 0x2f, v2);
5061 outSISIDXREG(SISSR, 0x30, v3);
5062 sisfb_post_xgi_delay(ivideo, 0x43);
5063 sisfb_post_xgi_delay(ivideo, 0x43);
5064 sisfb_post_xgi_delay(ivideo, 0x43);
5067 static int __devinit
5068 sisfb_post_xgi(struct pci_dev *pdev)
5070 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5071 unsigned char *bios = ivideo->bios_abase;
5072 struct pci_dev *mypdev = NULL;
5073 const u8 *ptr, *ptr2;
5074 u8 v1, v2, v3, v4, v5, reg, ramtype;
5075 u32 rega, regb, regd;
5077 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5078 static const u8 cs76[2] = { 0xa3, 0xfb };
5079 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5080 static const u8 cs158[8] = {
5081 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5083 static const u8 cs160[8] = {
5084 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5086 static const u8 cs168[8] = {
5087 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5089 static const u8 cs128[3 * 8] = {
5090 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5091 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5092 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5094 static const u8 cs148[2 * 8] = {
5095 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5096 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5098 static const u8 cs31a[8 * 4] = {
5099 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5100 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5104 static const u8 cs33a[8 * 4] = {
5105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5110 static const u8 cs45a[8 * 2] = {
5111 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5114 static const u8 cs170[7 * 8] = {
5115 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5116 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5117 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5118 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5119 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5120 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5121 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5123 static const u8 cs1a8[3 * 8] = {
5124 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5125 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5128 static const u8 cs100[2 * 8] = {
5129 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5130 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5134 reg = inSISREG(SISVGAENABLE) | 0x01;
5135 outSISREG(SISVGAENABLE, reg);
5138 reg = inSISREG(SISMISCR) | 0x01;
5139 outSISREG(SISMISCW, reg);
5142 outSISIDXREG(SISSR, 0x05, 0x86);
5143 inSISIDXREG(SISSR, 0x05, reg);
5147 /* Clear some regs */
5148 for(i = 0; i < 0x22; i++) {
5149 if(0x06 + i == 0x20) continue;
5150 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5152 for(i = 0; i < 0x0b; i++) {
5153 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5155 for(i = 0; i < 0x10; i++) {
5156 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5160 if(ivideo->haveXGIROM) {
5161 ptr = (const u8 *)&bios[0x78];
5163 for(i = 0; i < 3; i++) {
5164 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5168 if(ivideo->haveXGIROM) {
5169 ptr = (const u8 *)&bios[0x76];
5171 for(i = 0; i < 2; i++) {
5172 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5175 v1 = 0x18; v2 = 0x00;
5176 if(ivideo->haveXGIROM) {
5180 outSISIDXREG(SISSR, 0x07, v1);
5181 outSISIDXREG(SISSR, 0x11, 0x0f);
5182 outSISIDXREG(SISSR, 0x1f, v2);
5183 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5184 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5185 outSISIDXREG(SISSR, 0x27, 0x74);
5188 if(ivideo->haveXGIROM) {
5189 ptr = (const u8 *)&bios[0x7b];
5191 for(i = 0; i < 3; i++) {
5192 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5195 if(ivideo->chip == XGI_40) {
5196 if(ivideo->revision_id == 2) {
5197 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5199 outSISIDXREG(SISCR, 0x7d, 0xfe);
5200 outSISIDXREG(SISCR, 0x7e, 0x0f);
5202 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5203 andSISIDXREG(SISCR, 0x58, 0xd7);
5204 inSISIDXREG(SISCR, 0xcb, reg);
5206 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5210 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5211 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5213 if(ivideo->chip == XGI_20) {
5214 outSISIDXREG(SISSR, 0x36, 0x70);
5216 outSISIDXREG(SISVID, 0x00, 0x86);
5217 outSISIDXREG(SISVID, 0x32, 0x00);
5218 outSISIDXREG(SISVID, 0x30, 0x00);
5219 outSISIDXREG(SISVID, 0x32, 0x01);
5220 outSISIDXREG(SISVID, 0x30, 0x00);
5221 andSISIDXREG(SISVID, 0x2f, 0xdf);
5222 andSISIDXREG(SISCAP, 0x00, 0x3f);
5224 outSISIDXREG(SISPART1, 0x2f, 0x01);
5225 outSISIDXREG(SISPART1, 0x00, 0x00);
5226 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5227 outSISIDXREG(SISPART1, 0x2e, 0x08);
5228 andSISIDXREG(SISPART1, 0x35, 0x7f);
5229 andSISIDXREG(SISPART1, 0x50, 0xfe);
5231 inSISIDXREG(SISPART4, 0x00, reg);
5232 if(reg == 1 || reg == 2) {
5233 outSISIDXREG(SISPART2, 0x00, 0x1c);
5234 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5235 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5236 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5237 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5239 inSISIDXREG(SISPART4, 0x01, reg);
5240 if((reg & 0xf0) >= 0xb0) {
5241 inSISIDXREG(SISPART4, 0x23, reg);
5242 if(reg & 0x20) reg |= 0x40;
5243 outSISIDXREG(SISPART4, 0x23, reg);
5244 reg = (reg & 0x20) ? 0x02 : 0x00;
5245 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5251 inSISIDXREG(SISSR, 0x3b, reg);
5253 inSISIDXREG(SISSR, 0x3a, reg);
5254 v2 = (reg & 0x30) >> 3;
5255 if(!(v2 & 0x04)) v2 ^= 0x02;
5256 inSISIDXREG(SISSR, 0x39, reg);
5257 if(reg & 0x80) v2 |= 0x80;
5260 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5261 SIS_PCI_PUT_DEVICE(mypdev);
5262 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5267 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5269 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5271 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5273 pci_read_config_dword(mypdev, 0x94, ®d);
5275 pci_write_config_dword(mypdev, 0x94, regd);
5277 SIS_PCI_PUT_DEVICE(mypdev);
5278 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5280 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5281 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5282 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5283 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5284 if((v2 & 0x06) == 4)
5289 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5291 outSISIDXREG(SISSR, 0x22, v1);
5293 if(ivideo->revision_id == 2) {
5294 inSISIDXREG(SISSR, 0x3b, v1);
5295 inSISIDXREG(SISSR, 0x3a, v2);
5296 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5297 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5298 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5300 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5301 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5305 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5306 SIS_PCI_PUT_DEVICE(mypdev);
5311 inSISIDXREG(SISSR, 0x3b, reg);
5312 inSISIDXREG(SISCR, 0x5f, v2);
5313 if((!(reg & 0x02)) && (v2 & 0x0e))
5315 outSISIDXREG(SISSR, 0x27, v1);
5317 if(bios[0x64] & 0x01) {
5318 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5322 pci_read_config_dword(pdev, 0x50, ®d);
5323 regd = (regd >> 20) & 0x0f;
5326 orSISIDXREG(SISCR, 0x5f, 0x08);
5328 outSISIDXREG(SISCR, 0x48, v1);
5330 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5331 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5332 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5333 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5334 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5335 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5336 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5337 outSISIDXREG(SISCR, 0x74, 0xd0);
5338 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5339 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5340 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5342 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5344 SIS_PCI_PUT_DEVICE(mypdev);
5346 outSISIDXREG(SISCR, 0x77, v1);
5354 if(ivideo->haveXGIROM) {
5355 v1 = bios[0x140 + regb];
5357 outSISIDXREG(SISCR, 0x6d, v1);
5360 if(ivideo->haveXGIROM) {
5361 ptr = (const u8 *)&bios[0x128];
5363 for(i = 0, j = 0; i < 3; i++, j += 8) {
5364 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5369 if(ivideo->haveXGIROM) {
5370 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5371 ptr = (const u8 *)&bios[index];
5372 ptr2 = (const u8 *)&bios[index + 0x20];
5374 for(i = 0; i < 2; i++) {
5376 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5379 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5383 for(j = 0; j < 16; j++) {
5385 if(regd & 0x01) reg |= 0x04;
5386 if(regd & 0x02) reg |= 0x08;
5388 outSISIDXREG(SISCR, rega, reg);
5389 inSISIDXREG(SISCR, rega, reg);
5390 inSISIDXREG(SISCR, rega, reg);
5395 andSISIDXREG(SISCR, 0x6e, 0xfc);
5398 if(ivideo->haveXGIROM) {
5399 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5400 ptr = (const u8 *)&bios[index];
5402 for(i = 0; i < 4; i++) {
5403 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5405 for(j = 0; j < 2; j++) {
5408 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5412 for(k = 0; k < 16; k++) {
5414 if(regd & 0x01) reg |= 0x01;
5415 if(regd & 0x02) reg |= 0x02;
5417 outSISIDXREG(SISCR, 0x6f, reg);
5418 inSISIDXREG(SISCR, 0x6f, reg);
5419 inSISIDXREG(SISCR, 0x6f, reg);
5426 if(ivideo->haveXGIROM) {
5427 ptr = (const u8 *)&bios[0x148];
5429 for(i = 0, j = 0; i < 2; i++, j += 8) {
5430 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5433 andSISIDXREG(SISCR, 0x89, 0x8f);
5436 if(ivideo->haveXGIROM) {
5437 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5438 ptr = (const u8 *)&bios[index];
5440 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5442 for(i = 0; i < 5; i++) {
5444 if(regd & 0x01) reg |= 0x01;
5445 if(regd & 0x02) reg |= 0x02;
5447 outSISIDXREG(SISCR, 0x89, reg);
5448 inSISIDXREG(SISCR, 0x89, reg);
5449 inSISIDXREG(SISCR, 0x89, reg);
5453 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5454 if(ivideo->haveXGIROM) {
5455 v1 = bios[0x118 + regb];
5456 v2 = bios[0xf8 + regb];
5457 v3 = bios[0x120 + regb];
5460 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5461 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5462 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5463 outSISIDXREG(SISCR, 0x41, v2);
5466 if(ivideo->haveXGIROM) {
5467 ptr = (const u8 *)&bios[0x170];
5469 for(i = 0, j = 0; i < 7; i++, j += 8) {
5470 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5473 outSISIDXREG(SISCR, 0x59, v3);
5476 if(ivideo->haveXGIROM) {
5477 ptr = (const u8 *)&bios[0x1a8];
5479 for(i = 0, j = 0; i < 3; i++, j += 8) {
5480 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5484 if(ivideo->haveXGIROM) {
5485 ptr = (const u8 *)&bios[0x100];
5487 for(i = 0, j = 0; i < 2; i++, j += 8) {
5488 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5491 outSISIDXREG(SISCR, 0xcf, v4);
5493 outSISIDXREG(SISCR, 0x83, 0x09);
5494 outSISIDXREG(SISCR, 0x87, 0x00);
5496 if(ivideo->chip == XGI_40) {
5497 if( (ivideo->revision_id == 1) ||
5498 (ivideo->revision_id == 2) ) {
5499 outSISIDXREG(SISCR, 0x8c, 0x87);
5503 outSISIDXREG(SISSR, 0x17, 0x00);
5504 outSISIDXREG(SISSR, 0x1a, 0x87);
5506 if(ivideo->chip == XGI_20) {
5507 outSISIDXREG(SISSR, 0x15, 0x00);
5508 outSISIDXREG(SISSR, 0x1c, 0x00);
5511 ramtype = 0x00; v1 = 0x10;
5512 if(ivideo->haveXGIROM) {
5513 ramtype = bios[0x62];
5516 if(!(ramtype & 0x80)) {
5517 if(ivideo->chip == XGI_20) {
5518 outSISIDXREG(SISCR, 0x97, v1);
5519 inSISIDXREG(SISCR, 0x97, reg);
5521 ramtype = (reg & 0x01) << 1;
5524 inSISIDXREG(SISSR, 0x39, reg);
5525 ramtype = reg & 0x02;
5527 inSISIDXREG(SISSR, 0x3a, reg);
5528 ramtype = (reg >> 1) & 0x01;
5538 sisfb_post_xgi_setclocks(ivideo, regb);
5539 if((ivideo->chip == XGI_20) ||
5540 (ivideo->revision_id == 1) ||
5541 (ivideo->revision_id == 2)) {
5542 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5543 if(ivideo->haveXGIROM) {
5544 v1 = bios[regb + 0x158];
5545 v2 = bios[regb + 0x160];
5546 v3 = bios[regb + 0x168];
5548 outSISIDXREG(SISCR, 0x82, v1);
5549 outSISIDXREG(SISCR, 0x85, v2);
5550 outSISIDXREG(SISCR, 0x86, v3);
5552 outSISIDXREG(SISCR, 0x82, 0x88);
5553 outSISIDXREG(SISCR, 0x86, 0x00);
5554 inSISIDXREG(SISCR, 0x86, reg);
5555 outSISIDXREG(SISCR, 0x86, 0x88);
5556 inSISIDXREG(SISCR, 0x86, reg);
5557 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5558 outSISIDXREG(SISCR, 0x82, 0x77);
5559 outSISIDXREG(SISCR, 0x85, 0x00);
5560 inSISIDXREG(SISCR, 0x85, reg);
5561 outSISIDXREG(SISCR, 0x85, 0x88);
5562 inSISIDXREG(SISCR, 0x85, reg);
5563 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5564 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5566 if(ivideo->chip == XGI_40) {
5567 outSISIDXREG(SISCR, 0x97, 0x00);
5569 outSISIDXREG(SISCR, 0x98, 0x01);
5570 outSISIDXREG(SISCR, 0x9a, 0x02);
5572 outSISIDXREG(SISSR, 0x18, 0x01);
5573 if((ivideo->chip == XGI_20) ||
5574 (ivideo->revision_id == 2)) {
5575 outSISIDXREG(SISSR, 0x19, 0x40);
5577 outSISIDXREG(SISSR, 0x19, 0x20);
5579 outSISIDXREG(SISSR, 0x16, 0x00);
5580 outSISIDXREG(SISSR, 0x16, 0x80);
5581 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5582 sisfb_post_xgi_delay(ivideo, 0x43);
5583 sisfb_post_xgi_delay(ivideo, 0x43);
5584 sisfb_post_xgi_delay(ivideo, 0x43);
5585 outSISIDXREG(SISSR, 0x18, 0x00);
5586 if((ivideo->chip == XGI_20) ||
5587 (ivideo->revision_id == 2)) {
5588 outSISIDXREG(SISSR, 0x19, 0x40);
5590 outSISIDXREG(SISSR, 0x19, 0x20);
5592 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5593 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5595 outSISIDXREG(SISSR, 0x16, 0x00);
5596 outSISIDXREG(SISSR, 0x16, 0x80);
5597 sisfb_post_xgi_delay(ivideo, 4);
5598 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5599 if(ivideo->haveXGIROM) {
5601 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5603 v3 = bios[index + 1];
5604 v4 = bios[index + 2];
5605 v5 = bios[index + 3];
5607 outSISIDXREG(SISSR, 0x18, v1);
5608 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5609 outSISIDXREG(SISSR, 0x16, v2);
5610 outSISIDXREG(SISSR, 0x16, v3);
5611 sisfb_post_xgi_delay(ivideo, 0x43);
5612 outSISIDXREG(SISSR, 0x1b, 0x03);
5613 sisfb_post_xgi_delay(ivideo, 0x22);
5614 outSISIDXREG(SISSR, 0x18, v1);
5615 outSISIDXREG(SISSR, 0x19, 0x00);
5616 outSISIDXREG(SISSR, 0x16, v4);
5617 outSISIDXREG(SISSR, 0x16, v5);
5618 outSISIDXREG(SISSR, 0x1b, 0x00);
5621 outSISIDXREG(SISCR, 0x82, 0x77);
5622 outSISIDXREG(SISCR, 0x86, 0x00);
5623 inSISIDXREG(SISCR, 0x86, reg);
5624 outSISIDXREG(SISCR, 0x86, 0x88);
5625 inSISIDXREG(SISCR, 0x86, reg);
5626 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5627 if(ivideo->haveXGIROM) {
5628 v1 = bios[regb + 0x168];
5629 v2 = bios[regb + 0x160];
5630 v3 = bios[regb + 0x158];
5632 outSISIDXREG(SISCR, 0x86, v1);
5633 outSISIDXREG(SISCR, 0x82, 0x77);
5634 outSISIDXREG(SISCR, 0x85, 0x00);
5635 inSISIDXREG(SISCR, 0x85, reg);
5636 outSISIDXREG(SISCR, 0x85, 0x88);
5637 inSISIDXREG(SISCR, 0x85, reg);
5638 outSISIDXREG(SISCR, 0x85, v2);
5639 outSISIDXREG(SISCR, 0x82, v3);
5640 outSISIDXREG(SISCR, 0x98, 0x01);
5641 outSISIDXREG(SISCR, 0x9a, 0x02);
5643 outSISIDXREG(SISSR, 0x28, 0x64);
5644 outSISIDXREG(SISSR, 0x29, 0x63);
5645 sisfb_post_xgi_delay(ivideo, 15);
5646 outSISIDXREG(SISSR, 0x18, 0x00);
5647 outSISIDXREG(SISSR, 0x19, 0x20);
5648 outSISIDXREG(SISSR, 0x16, 0x00);
5649 outSISIDXREG(SISSR, 0x16, 0x80);
5650 outSISIDXREG(SISSR, 0x18, 0xc5);
5651 outSISIDXREG(SISSR, 0x19, 0x23);
5652 outSISIDXREG(SISSR, 0x16, 0x00);
5653 outSISIDXREG(SISSR, 0x16, 0x80);
5654 sisfb_post_xgi_delay(ivideo, 1);
5655 outSISIDXREG(SISCR, 0x97,0x11);
5656 sisfb_post_xgi_setclocks(ivideo, regb);
5657 sisfb_post_xgi_delay(ivideo, 0x46);
5658 outSISIDXREG(SISSR, 0x18, 0xc5);
5659 outSISIDXREG(SISSR, 0x19, 0x23);
5660 outSISIDXREG(SISSR, 0x16, 0x00);
5661 outSISIDXREG(SISSR, 0x16, 0x80);
5662 sisfb_post_xgi_delay(ivideo, 1);
5663 outSISIDXREG(SISSR, 0x1b, 0x04);
5664 sisfb_post_xgi_delay(ivideo, 1);
5665 outSISIDXREG(SISSR, 0x1b, 0x00);
5666 sisfb_post_xgi_delay(ivideo, 1);
5668 if(ivideo->haveXGIROM) {
5671 outSISIDXREG(SISSR, 0x18, v1);
5672 outSISIDXREG(SISSR, 0x19, 0x06);
5673 outSISIDXREG(SISSR, 0x16, 0x04);
5674 outSISIDXREG(SISSR, 0x16, 0x84);
5675 sisfb_post_xgi_delay(ivideo, 1);
5678 sisfb_post_xgi_setclocks(ivideo, regb);
5679 if((ivideo->chip == XGI_40) &&
5680 ((ivideo->revision_id == 1) ||
5681 (ivideo->revision_id == 2))) {
5682 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5683 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5684 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5686 outSISIDXREG(SISCR, 0x82, 0x88);
5687 outSISIDXREG(SISCR, 0x86, 0x00);
5688 inSISIDXREG(SISCR, 0x86, reg);
5689 outSISIDXREG(SISCR, 0x86, 0x88);
5690 outSISIDXREG(SISCR, 0x82, 0x77);
5691 outSISIDXREG(SISCR, 0x85, 0x00);
5692 inSISIDXREG(SISCR, 0x85, reg);
5693 outSISIDXREG(SISCR, 0x85, 0x88);
5694 inSISIDXREG(SISCR, 0x85, reg);
5695 v1 = cs160[regb]; v2 = cs158[regb];
5696 if(ivideo->haveXGIROM) {
5697 v1 = bios[regb + 0x160];
5698 v2 = bios[regb + 0x158];
5700 outSISIDXREG(SISCR, 0x85, v1);
5701 outSISIDXREG(SISCR, 0x82, v2);
5703 if(ivideo->chip == XGI_40) {
5704 outSISIDXREG(SISCR, 0x97, 0x11);
5706 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5707 outSISIDXREG(SISCR, 0x98, 0x01);
5709 outSISIDXREG(SISCR, 0x98, 0x03);
5711 outSISIDXREG(SISCR, 0x9a, 0x02);
5713 if(ivideo->chip == XGI_40) {
5714 outSISIDXREG(SISSR, 0x18, 0x01);
5716 outSISIDXREG(SISSR, 0x18, 0x00);
5718 outSISIDXREG(SISSR, 0x19, 0x40);
5719 outSISIDXREG(SISSR, 0x16, 0x00);
5720 outSISIDXREG(SISSR, 0x16, 0x80);
5721 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5722 sisfb_post_xgi_delay(ivideo, 0x43);
5723 sisfb_post_xgi_delay(ivideo, 0x43);
5724 sisfb_post_xgi_delay(ivideo, 0x43);
5725 outSISIDXREG(SISSR, 0x18, 0x00);
5726 outSISIDXREG(SISSR, 0x19, 0x40);
5727 outSISIDXREG(SISSR, 0x16, 0x00);
5728 outSISIDXREG(SISSR, 0x16, 0x80);
5730 sisfb_post_xgi_delay(ivideo, 4);
5732 if(ivideo->haveXGIROM) {
5735 outSISIDXREG(SISSR, 0x18, v1);
5736 outSISIDXREG(SISSR, 0x19, 0x01);
5737 if(ivideo->chip == XGI_40) {
5738 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5739 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5741 outSISIDXREG(SISSR, 0x16, 0x05);
5742 outSISIDXREG(SISSR, 0x16, 0x85);
5744 sisfb_post_xgi_delay(ivideo, 0x43);
5745 if(ivideo->chip == XGI_40) {
5746 outSISIDXREG(SISSR, 0x1b, 0x01);
5748 outSISIDXREG(SISSR, 0x1b, 0x03);
5750 sisfb_post_xgi_delay(ivideo, 0x22);
5751 outSISIDXREG(SISSR, 0x18, v1);
5752 outSISIDXREG(SISSR, 0x19, 0x00);
5753 if(ivideo->chip == XGI_40) {
5754 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5755 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5757 outSISIDXREG(SISSR, 0x16, 0x05);
5758 outSISIDXREG(SISSR, 0x16, 0x85);
5760 outSISIDXREG(SISSR, 0x1b, 0x00);
5765 if(ivideo->haveXGIROM) {
5766 v1 = bios[0x110 + regb];
5768 outSISIDXREG(SISSR, 0x1b, v1);
5771 v1 = 0x00; v2 = 0x00;
5772 if(ivideo->haveXGIROM) {
5778 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5780 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5781 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5785 /* Set default mode, don't clear screen */
5786 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5787 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5788 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5789 ivideo->curFSTN = ivideo->curDSTN = 0;
5790 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5791 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5793 outSISIDXREG(SISSR, 0x05, 0x86);
5795 /* Disable read-cache */
5796 andSISIDXREG(SISSR, 0x21, 0xdf);
5797 sisfb_post_xgi_ramsize(ivideo);
5798 /* Enable read-cache */
5799 orSISIDXREG(SISSR, 0x21, 0x20);
5804 printk(KERN_DEBUG "-----------------\n");
5805 for(i = 0; i < 0xff; i++) {
5806 inSISIDXREG(SISCR, i, reg);
5807 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5809 for(i = 0; i < 0x40; i++) {
5810 inSISIDXREG(SISSR, i, reg);
5811 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5813 printk(KERN_DEBUG "-----------------\n");
5817 if(ivideo->chip == XGI_20) {
5818 orSISIDXREG(SISCR, 0x32, 0x20);
5820 inSISIDXREG(SISPART4, 0x00, reg);
5821 if((reg == 1) || (reg == 2)) {
5822 sisfb_sense_crt1(ivideo);
5824 orSISIDXREG(SISCR, 0x32, 0x20);
5828 /* Set default mode, don't clear screen */
5829 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5830 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5831 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5832 ivideo->curFSTN = ivideo->curDSTN = 0;
5833 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5835 outSISIDXREG(SISSR, 0x05, 0x86);
5838 orSISIDXREG(SISSR, 0x01, 0x20);
5840 /* Save mode number in CR34 */
5841 outSISIDXREG(SISCR, 0x34, 0x2e);
5843 /* Let everyone know what the current mode is */
5844 ivideo->modeprechange = 0x2e;
5846 if(ivideo->chip == XGI_40) {
5847 inSISIDXREG(SISCR, 0xca, reg);
5848 inSISIDXREG(SISCR, 0xcc, v1);
5849 if((reg & 0x10) && (!(v1 & 0x04))) {
5851 "sisfb: Please connect power to the card.\n");
5860 static int __devinit
5861 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5863 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5864 struct sis_video_info *ivideo = NULL;
5865 struct fb_info *sis_fb_info = NULL;
5873 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5874 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5878 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
5881 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5882 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5885 ivideo = (struct sis_video_info *)sis_fb_info->par;
5886 ivideo->memyselfandi = sis_fb_info;
5888 ivideo->sisfb_id = SISFB_ID;
5890 if(card_list == NULL) {
5891 ivideo->cardnumber = 0;
5893 struct sis_video_info *countvideo = card_list;
5894 ivideo->cardnumber = 1;
5895 while((countvideo = countvideo->next) != 0)
5896 ivideo->cardnumber++;
5899 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5901 ivideo->warncount = 0;
5902 ivideo->chip_id = pdev->device;
5903 ivideo->chip_vendor = pdev->vendor;
5904 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
5905 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5906 pci_read_config_word(pdev, PCI_COMMAND, ®16);
5907 ivideo->sisvga_enabled = reg16 & 0x01;
5908 ivideo->pcibus = pdev->bus->number;
5909 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5910 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5911 ivideo->subsysvendor = pdev->subsystem_vendor;
5912 ivideo->subsysdevice = pdev->subsystem_device;
5913 #ifdef SIS_OLD_CONFIG_COMPAT
5914 ivideo->ioctl32registered = 0;
5918 if(sisfb_mode_idx == -1) {
5919 sisfb_get_vga_mode_from_kernel();
5923 ivideo->chip = chipinfo->chip;
5924 ivideo->sisvga_engine = chipinfo->vgaengine;
5925 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5926 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5927 ivideo->mni = chipinfo->mni;
5929 ivideo->detectedpdc = 0xff;
5930 ivideo->detectedpdca = 0xff;
5931 ivideo->detectedlcda = 0xff;
5933 ivideo->sisfb_thismonitor.datavalid = FALSE;
5935 ivideo->current_base = 0;
5937 ivideo->engineok = 0;
5939 ivideo->sisfb_was_boot_device = 0;
5940 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5941 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5942 if(ivideo->sisvga_enabled)
5943 ivideo->sisfb_was_boot_device = 1;
5945 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5946 "but marked as boot video device ???\n");
5947 printk(KERN_DEBUG "sisfb: I will not accept this "
5948 "as the primary VGA device\n");
5953 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5954 ivideo->sisfb_accel = sisfb_accel;
5955 ivideo->sisfb_ypan = sisfb_ypan;
5956 ivideo->sisfb_max = sisfb_max;
5957 ivideo->sisfb_userom = sisfb_userom;
5958 ivideo->sisfb_useoem = sisfb_useoem;
5959 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5960 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5961 ivideo->sisfb_crt1off = sisfb_crt1off;
5962 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5963 ivideo->sisfb_crt2type = sisfb_crt2type;
5964 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5965 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5966 ivideo->sisfb_dstn = sisfb_dstn;
5967 ivideo->sisfb_fstn = sisfb_fstn;
5968 ivideo->sisfb_tvplug = sisfb_tvplug;
5969 ivideo->sisfb_tvstd = sisfb_tvstd;
5970 ivideo->tvxpos = sisfb_tvxposoffset;
5971 ivideo->tvypos = sisfb_tvyposoffset;
5972 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5973 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5974 ivideo->sisfb_inverse = sisfb_inverse;
5977 ivideo->refresh_rate = 0;
5978 if(ivideo->sisfb_parm_rate != -1) {
5979 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5982 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5983 ivideo->SiS_Pr.CenterScreen = -1;
5984 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5985 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5987 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5988 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5989 ivideo->SiS_Pr.SiS_ChSW = FALSE;
5990 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5991 ivideo->SiS_Pr.HaveEMI = FALSE;
5992 ivideo->SiS_Pr.HaveEMILCD = FALSE;
5993 ivideo->SiS_Pr.OverruleEMI = FALSE;
5994 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
5995 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5996 ivideo->SiS_Pr.PDC = -1;
5997 ivideo->SiS_Pr.PDCA = -1;
5998 ivideo->SiS_Pr.DDCPortMixup = FALSE;
5999 #ifdef CONFIG_FB_SIS_315
6000 if(ivideo->chip >= SIS_330) {
6001 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
6002 if(ivideo->chip >= SIS_661) {
6003 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
6008 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6010 pci_set_drvdata(pdev, ivideo);
6012 /* Patch special cases */
6013 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6014 switch(ivideo->nbridge->device) {
6015 #ifdef CONFIG_FB_SIS_300
6016 case PCI_DEVICE_ID_SI_730:
6017 ivideo->chip = SIS_730;
6018 strcpy(ivideo->myid, "SiS 730");
6021 #ifdef CONFIG_FB_SIS_315
6022 case PCI_DEVICE_ID_SI_651:
6023 /* ivideo->chip is ok */
6024 strcpy(ivideo->myid, "SiS 651");
6026 case PCI_DEVICE_ID_SI_740:
6027 ivideo->chip = SIS_740;
6028 strcpy(ivideo->myid, "SiS 740");
6030 case PCI_DEVICE_ID_SI_661:
6031 ivideo->chip = SIS_661;
6032 strcpy(ivideo->myid, "SiS 661");
6034 case PCI_DEVICE_ID_SI_741:
6035 ivideo->chip = SIS_741;
6036 strcpy(ivideo->myid, "SiS 741");
6038 case PCI_DEVICE_ID_SI_760:
6039 ivideo->chip = SIS_760;
6040 strcpy(ivideo->myid, "SiS 760");
6042 case PCI_DEVICE_ID_SI_761:
6043 ivideo->chip = SIS_761;
6044 strcpy(ivideo->myid, "SiS 761");
6052 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6053 strcpy(sis_fb_info->modename, ivideo->myid);
6056 ivideo->SiS_Pr.ChipType = ivideo->chip;
6058 ivideo->SiS_Pr.ivideo = (void *)ivideo;
6060 #ifdef CONFIG_FB_SIS_315
6061 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6062 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6063 ivideo->SiS_Pr.ChipType = SIS_315H;
6067 if(!ivideo->sisvga_enabled) {
6068 if(pci_enable_device(pdev)) {
6069 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6070 pci_set_drvdata(pdev, NULL);
6076 ivideo->video_base = pci_resource_start(pdev, 0);
6077 ivideo->mmio_base = pci_resource_start(pdev, 1);
6078 ivideo->mmio_size = pci_resource_len(pdev, 1);
6079 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
6080 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
6082 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
6084 #ifdef CONFIG_FB_SIS_300
6085 /* Find PCI systems for Chrontel/GPIO communication setup */
6086 if(ivideo->chip == SIS_630) {
6089 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6090 mychswtable[i].subsysCard == ivideo->subsysdevice) {
6091 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6092 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6093 "requiring Chrontel/GPIO setup\n",
6094 mychswtable[i].vendorName,
6095 mychswtable[i].cardName);
6096 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6100 } while(mychswtable[i].subsysVendor != 0);
6104 #ifdef CONFIG_FB_SIS_315
6105 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6106 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
6110 outSISIDXREG(SISSR, 0x05, 0x86);
6112 if( (!ivideo->sisvga_enabled)
6113 #if !defined(__i386__) && !defined(__x86_64__)
6114 || (sisfb_resetcard)
6117 for(i = 0x30; i <= 0x3f; i++) {
6118 outSISIDXREG(SISCR, i, 0x00);
6122 /* Find out about current video mode */
6123 ivideo->modeprechange = 0x03;
6124 inSISIDXREG(SISCR, 0x34, reg);
6126 ivideo->modeprechange = reg & 0x7f;
6127 } else if(ivideo->sisvga_enabled) {
6128 #if defined(__i386__) || defined(__x86_64__)
6129 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
6131 ivideo->modeprechange = readb(tt + 0x49);
6137 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6139 if((reg & 0x80) && (reg != 0xff)) {
6140 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6142 printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6143 "X server is active\n");
6151 /* Search and copy ROM image */
6152 ivideo->bios_abase = NULL;
6153 ivideo->SiS_Pr.VirtualRomBase = NULL;
6154 ivideo->SiS_Pr.UseROM = FALSE;
6155 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
6156 if(ivideo->sisfb_userom) {
6157 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6158 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6159 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6160 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6161 ivideo->SiS_Pr.UseROM ? "" : "not ");
6162 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6163 ivideo->SiS_Pr.UseROM = FALSE;
6164 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6165 if( (ivideo->revision_id == 2) &&
6166 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6167 ivideo->SiS_Pr.DDCPortMixup = TRUE;
6171 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6174 /* Find systems for special custom timing */
6175 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6176 sisfb_detect_custom_timing(ivideo);
6179 /* POST card in case this has not been done by the BIOS */
6180 if( (!ivideo->sisvga_enabled)
6181 #if !defined(__i386__) && !defined(__x86_64__)
6182 || (sisfb_resetcard)
6185 #ifdef CONFIG_FB_SIS_300
6186 if(ivideo->sisvga_engine == SIS_300_VGA) {
6187 if(ivideo->chip == SIS_300) {
6188 sisfb_post_sis300(pdev);
6189 ivideo->sisfb_can_post = 1;
6194 #ifdef CONFIG_FB_SIS_315
6195 if(ivideo->sisvga_engine == SIS_315_VGA) {
6197 /* if((ivideo->chip == SIS_315H) ||
6198 (ivideo->chip == SIS_315) ||
6199 (ivideo->chip == SIS_315PRO) ||
6200 (ivideo->chip == SIS_330)) {
6201 sisfb_post_sis315330(pdev);
6202 } else */ if(ivideo->chip == XGI_20) {
6203 result = sisfb_post_xgi(pdev);
6204 ivideo->sisfb_can_post = 1;
6205 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6206 result = sisfb_post_xgi(pdev);
6207 ivideo->sisfb_can_post = 1;
6209 printk(KERN_INFO "sisfb: Card is not "
6210 "POSTed and sisfb can't do this either.\n");
6213 printk(KERN_ERR "sisfb: Failed to POST card\n");
6221 ivideo->sisfb_card_posted = 1;
6223 /* Find out about RAM size */
6224 if(sisfb_get_dram_size(ivideo)) {
6225 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6231 /* Enable PCI addressing and MMIO */
6232 if((ivideo->sisfb_mode_idx < 0) ||
6233 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6234 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6235 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6236 /* Enable 2D accelerator engine */
6237 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6240 if(sisfb_pdc != 0xff) {
6241 if(ivideo->sisvga_engine == SIS_300_VGA)
6245 ivideo->SiS_Pr.PDC = sisfb_pdc;
6247 #ifdef CONFIG_FB_SIS_315
6248 if(ivideo->sisvga_engine == SIS_315_VGA) {
6249 if(sisfb_pdca != 0xff)
6250 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6254 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6255 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6256 (int)(ivideo->video_size >> 20));
6257 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6262 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6263 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6268 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6269 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6270 if(!ivideo->video_vbase) {
6271 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6276 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6277 if(!ivideo->mmio_vbase) {
6278 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6280 error_0: iounmap(ivideo->video_vbase);
6281 error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6282 error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6283 error_3: vfree(ivideo->bios_abase);
6284 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6288 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6290 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6291 pci_set_drvdata(pdev, NULL);
6292 if(!ivideo->sisvga_enabled)
6293 pci_disable_device(pdev);
6298 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6299 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6301 if(ivideo->video_offset) {
6302 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6303 ivideo->video_offset / 1024);
6306 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6307 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6310 /* Determine the size of the command queue */
6311 if(ivideo->sisvga_engine == SIS_300_VGA) {
6312 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6314 if(ivideo->chip == XGI_20) {
6315 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6317 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6321 /* Engines are no longer initialized here; this is
6322 * now done after the first mode-switch (if the
6323 * submitted var has its acceleration flags set).
6326 /* Calculate the base of the (unused) hw cursor */
6327 ivideo->hwcursor_vbase = ivideo->video_vbase
6328 + ivideo->video_size
6329 - ivideo->cmdQueueSize
6330 - ivideo->hwcursor_size;
6331 ivideo->caps |= HW_CURSOR_CAP;
6333 /* Initialize offscreen memory manager */
6334 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6335 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6338 /* Used for clearing the screen only, therefore respect our mem limit */
6339 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6340 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6344 ivideo->vbflags = 0;
6345 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6346 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6347 ivideo->defmodeidx = DEFAULT_MODE;
6350 if(ivideo->chip < XGI_20) {
6351 if(ivideo->bios_abase) {
6352 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6356 if((ivideo->sisfb_mode_idx < 0) ||
6357 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6359 sisfb_sense_crt1(ivideo);
6361 sisfb_get_VB_type(ivideo);
6363 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6364 sisfb_detect_VB_connect(ivideo);
6367 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6369 /* Decide on which CRT2 device to use */
6370 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6371 if(ivideo->sisfb_crt2type != -1) {
6372 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6373 (ivideo->vbflags & CRT2_LCD)) {
6374 ivideo->currentvbflags |= CRT2_LCD;
6375 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6376 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6379 /* Chrontel 700x TV detection often unreliable, therefore
6380 * use a different default order on such machines
6382 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6383 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6384 if(ivideo->vbflags & CRT2_LCD)
6385 ivideo->currentvbflags |= CRT2_LCD;
6386 else if(ivideo->vbflags & CRT2_TV)
6387 ivideo->currentvbflags |= CRT2_TV;
6388 else if(ivideo->vbflags & CRT2_VGA)
6389 ivideo->currentvbflags |= CRT2_VGA;
6391 if(ivideo->vbflags & CRT2_TV)
6392 ivideo->currentvbflags |= CRT2_TV;
6393 else if(ivideo->vbflags & CRT2_LCD)
6394 ivideo->currentvbflags |= CRT2_LCD;
6395 else if(ivideo->vbflags & CRT2_VGA)
6396 ivideo->currentvbflags |= CRT2_VGA;
6401 if(ivideo->vbflags & CRT2_LCD) {
6402 sisfb_detect_lcd_type(ivideo);
6405 sisfb_save_pdc_emi(ivideo);
6407 if(!ivideo->sisfb_crt1off) {
6408 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6410 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6411 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6412 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6416 if(ivideo->sisfb_mode_idx >= 0) {
6417 int bu = ivideo->sisfb_mode_idx;
6418 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6419 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6420 if(bu != ivideo->sisfb_mode_idx) {
6421 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6422 sisbios_mode[bu].xres,
6423 sisbios_mode[bu].yres,
6424 sisbios_mode[bu].bpp);
6428 if(ivideo->sisfb_mode_idx < 0) {
6429 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6431 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6434 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6437 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6442 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6444 if(ivideo->refresh_rate != 0) {
6445 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6446 ivideo->sisfb_mode_idx);
6449 if(ivideo->rate_idx == 0) {
6450 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6451 ivideo->refresh_rate = 60;
6454 if(ivideo->sisfb_thismonitor.datavalid) {
6455 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6456 ivideo->sisfb_mode_idx,
6458 ivideo->refresh_rate)) {
6459 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6460 "exceeds monitor specs!\n");
6464 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6465 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6466 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6468 sisfb_set_vparms(ivideo);
6470 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6472 /* ---------------- For 2.4: Now switch the mode ------------------ */
6474 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6475 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6476 ivideo->refresh_rate);
6478 /* Determine whether or not acceleration is to be
6479 * used. Need to know before pre/post_set_mode()
6482 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6483 if(ivideo->sisfb_accel) {
6485 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6488 /* Now switch the mode */
6489 sisfb_pre_setmode(ivideo);
6491 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
6492 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6495 iounmap(ivideo->mmio_vbase);
6499 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6501 sisfb_post_setmode(ivideo);
6503 /* Maximize regardless of sisfb_max at startup */
6504 ivideo->default_var.yres_virtual = 32767;
6506 /* Force reset of x virtual in crtc_to_var */
6507 ivideo->default_var.xres_virtual = 0;
6509 /* Copy mode timing to var */
6510 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6512 /* Find out about screen pitch */
6513 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6514 sisfb_set_pitch(ivideo);
6516 /* Init the accelerator (does nothing currently) */
6517 sisfb_initaccel(ivideo);
6519 /* Init some fbinfo entries */
6520 sis_fb_info->node = -1;
6521 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6522 sis_fb_info->fbops = &sisfb_ops;
6523 sis_fb_info->disp = &ivideo->sis_disp;
6524 sis_fb_info->blank = &sisfb_blank;
6525 sis_fb_info->switch_con = &sisfb_switch;
6526 sis_fb_info->updatevar = &sisfb_update_var;
6527 sis_fb_info->changevar = NULL;
6528 strcpy(sis_fb_info->fontname, sisfb_fontname);
6530 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6532 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6534 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6535 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6536 ivideo->refresh_rate);
6538 /* Set up the default var according to chosen default display mode */
6539 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6540 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6541 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6543 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6545 ivideo->default_var.pixclock = (u32) (1000000000 /
6546 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6548 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6549 ivideo->rate_idx, &ivideo->default_var)) {
6550 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6551 ivideo->default_var.pixclock <<= 1;
6555 if(ivideo->sisfb_ypan) {
6556 /* Maximize regardless of sisfb_max at startup */
6557 ivideo->default_var.yres_virtual =
6558 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6559 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6560 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6564 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6567 if(ivideo->sisfb_accel) {
6569 #ifdef STUPID_ACCELF_TEXT_SHIT
6570 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6573 sisfb_initaccel(ivideo);
6575 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6576 sis_fb_info->flags = FBINFO_DEFAULT |
6577 FBINFO_HWACCEL_YPAN |
6578 FBINFO_HWACCEL_XPAN |
6579 FBINFO_HWACCEL_COPYAREA |
6580 FBINFO_HWACCEL_FILLRECT |
6581 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6583 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6585 sis_fb_info->var = ivideo->default_var;
6586 sis_fb_info->fix = ivideo->sisfb_fix;
6587 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6588 sis_fb_info->fbops = &sisfb_ops;
6590 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6591 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6593 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6596 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6599 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6600 MTRR_TYPE_WRCOMB, 1);
6601 if(ivideo->mtrr < 0) {
6602 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6606 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6607 vc_resize_con(1, 1, 0);
6610 if(register_framebuffer(sis_fb_info) < 0) {
6611 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6613 iounmap(ivideo->mmio_vbase);
6617 ivideo->registered = 1;
6620 ivideo->next = card_list;
6623 #ifdef SIS_OLD_CONFIG_COMPAT
6626 /* Our ioctls are all "32/64bit compatible" */
6627 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6628 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6629 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6630 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6631 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6632 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6633 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6634 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6635 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6636 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6637 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6638 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6641 "sisfb: Error registering ioctl32 translations\n");
6643 ivideo->ioctl32registered = 1;
6647 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6648 ivideo->sisfb_accel ? "enabled" : "disabled",
6649 ivideo->sisfb_ypan ?
6650 (ivideo->sisfb_max ? "enabled (auto-max)" :
6651 "enabled (no auto-max)") :
6655 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6656 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6657 GET_FB_IDX(sis_fb_info->node),
6661 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6663 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6665 } /* if mode = "none" */
6670 /*****************************************************/
6671 /* PCI DEVICE HANDLING */
6672 /*****************************************************/
6674 static void __devexit sisfb_remove(struct pci_dev *pdev)
6676 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6677 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6678 int registered = ivideo->registered;
6679 int modechanged = ivideo->modechanged;
6681 #ifdef SIS_OLD_CONFIG_COMPAT
6682 if(ivideo->ioctl32registered) {
6684 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6685 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6686 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6687 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6688 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6689 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6690 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6691 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6692 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6693 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6694 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6695 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6698 "sisfb: Error unregistering ioctl32 translations\n");
6703 iounmap(ivideo->mmio_vbase);
6704 iounmap(ivideo->video_vbase);
6706 /* Release mem regions */
6707 release_mem_region(ivideo->video_base, ivideo->video_size);
6708 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6710 vfree(ivideo->bios_abase);
6713 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6716 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6719 /* Release MTRR region */
6720 if(ivideo->mtrr >= 0)
6721 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6724 pci_set_drvdata(pdev, NULL);
6726 /* If device was disabled when starting, disable
6729 if(!ivideo->sisvga_enabled)
6730 pci_disable_device(pdev);
6732 /* Unregister the framebuffer */
6733 if(ivideo->registered) {
6734 unregister_framebuffer(sis_fb_info);
6735 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6736 framebuffer_release(sis_fb_info);
6742 /* OK, our ivideo is gone for good from here. */
6744 /* TODO: Restore the initial mode
6745 * This sounds easy but is as good as impossible
6746 * on many machines with SiS chip and video bridge
6747 * since text modes are always set up differently
6748 * from machine to machine. Depends on the type
6749 * of integration between chipset and bridge.
6751 if(registered && modechanged)
6753 "sisfb: Restoring of text mode not supported yet\n");
6756 static struct pci_driver sisfb_driver = {
6758 .id_table = sisfb_pci_table,
6759 .probe = sisfb_probe,
6760 .remove = __devexit_p(sisfb_remove)
6763 SISINITSTATIC int __init sisfb_init(void)
6765 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6767 char *options = NULL;
6769 if(fb_get_options("sisfb", &options))
6772 sisfb_setup(options);
6775 return pci_register_driver(&sisfb_driver);
6778 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6780 module_init(sisfb_init);
6784 /*****************************************************/
6786 /*****************************************************/
6790 static char *mode = NULL;
6791 static int vesa = -1;
6792 static unsigned int rate = 0;
6793 static unsigned int crt1off = 1;
6794 static unsigned int mem = 0;
6795 static char *forcecrt2type = NULL;
6796 static int forcecrt1 = -1;
6797 static int pdc = -1;
6798 static int pdc1 = -1;
6799 static int noaccel = -1;
6800 static int noypan = -1;
6801 static int nomax = -1;
6802 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6803 static int inverse = 0;
6805 static int userom = -1;
6806 static int useoem = -1;
6807 static char *tvstandard = NULL;
6808 static int nocrt2rate = 0;
6809 static int scalelcd = -1;
6810 static char *specialtiming = NULL;
6811 static int lvdshl = -1;
6812 static int tvxposoffset = 0, tvyposoffset = 0;
6813 #if !defined(__i386__) && !defined(__x86_64__)
6814 static int resetcard = 0;
6815 static int videoram = 0;
6818 static int __init sisfb_init_module(void)
6820 sisfb_setdefaultparms();
6823 sisfb_parm_rate = rate;
6825 if((scalelcd == 0) || (scalelcd == 1))
6826 sisfb_scalelcd = scalelcd ^ 1;
6828 /* Need to check crt2 type first for fstn/dstn */
6831 sisfb_search_crt2type(forcecrt2type);
6834 sisfb_search_tvstd(tvstandard);
6837 sisfb_search_mode(mode, FALSE);
6839 sisfb_search_vesamode(vesa, FALSE);
6841 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6843 sisfb_forcecrt1 = forcecrt1;
6846 else if(forcecrt1 == 0)
6851 else if(noaccel == 0)
6856 else if(noypan == 0)
6864 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6865 if(inverse) sisfb_inverse = 1;
6869 sisfb_parm_mem = mem;
6872 sisfb_userom = userom;
6875 sisfb_useoem = useoem;
6878 sisfb_pdc = (pdc & 0x7f);
6881 sisfb_pdca = (pdc1 & 0x1f);
6883 sisfb_nocrt2rate = nocrt2rate;
6886 sisfb_search_specialtiming(specialtiming);
6888 if((lvdshl >= 0) && (lvdshl <= 3))
6889 sisfb_lvdshl = lvdshl;
6891 sisfb_tvxposoffset = tvxposoffset;
6892 sisfb_tvyposoffset = tvyposoffset;
6894 #if !defined(__i386__) && !defined(__x86_64__)
6895 sisfb_resetcard = (resetcard) ? 1 : 0;
6897 sisfb_videoram = videoram;
6900 return sisfb_init();
6903 static void __exit sisfb_remove_module(void)
6905 pci_unregister_driver(&sisfb_driver);
6906 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6909 module_init(sisfb_init_module);
6910 module_exit(sisfb_remove_module);
6912 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6913 MODULE_LICENSE("GPL");
6914 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6916 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6917 MODULE_PARM(mem, "i");
6918 MODULE_PARM(noaccel, "i");
6919 MODULE_PARM(noypan, "i");
6920 MODULE_PARM(nomax, "i");
6921 MODULE_PARM(userom, "i");
6922 MODULE_PARM(useoem, "i");
6923 MODULE_PARM(mode, "s");
6924 MODULE_PARM(vesa, "i");
6925 MODULE_PARM(rate, "i");
6926 MODULE_PARM(forcecrt1, "i");
6927 MODULE_PARM(forcecrt2type, "s");
6928 MODULE_PARM(scalelcd, "i");
6929 MODULE_PARM(pdc, "i");
6930 MODULE_PARM(pdc1, "i");
6931 MODULE_PARM(specialtiming, "s");
6932 MODULE_PARM(lvdshl, "i");
6933 MODULE_PARM(tvstandard, "s");
6934 MODULE_PARM(tvxposoffset, "i");
6935 MODULE_PARM(tvyposoffset, "i");
6936 MODULE_PARM(nocrt2rate, "i");
6937 MODULE_PARM(inverse, "i");
6938 #if !defined(__i386__) && !defined(__x86_64__)
6939 MODULE_PARM(resetcard, "i");
6940 MODULE_PARM(videoram, "i");
6944 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6945 module_param(mem, int, 0);
6946 module_param(noaccel, int, 0);
6947 module_param(noypan, int, 0);
6948 module_param(nomax, int, 0);
6949 module_param(userom, int, 0);
6950 module_param(useoem, int, 0);
6951 module_param(mode, charp, 0);
6952 module_param(vesa, int, 0);
6953 module_param(rate, int, 0);
6954 module_param(forcecrt1, int, 0);
6955 module_param(forcecrt2type, charp, 0);
6956 module_param(scalelcd, int, 0);
6957 module_param(pdc, int, 0);
6958 module_param(pdc1, int, 0);
6959 module_param(specialtiming, charp, 0);
6960 module_param(lvdshl, int, 0);
6961 module_param(tvstandard, charp, 0);
6962 module_param(tvxposoffset, int, 0);
6963 module_param(tvyposoffset, int, 0);
6964 module_param(nocrt2rate, int, 0);
6965 #if !defined(__i386__) && !defined(__x86_64__)
6966 module_param(resetcard, int, 0);
6967 module_param(videoram, int, 0);
6971 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6972 MODULE_PARM_DESC(mem,
6973 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6974 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6975 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6976 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6977 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6978 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6979 "for XFree86 4.x/X.org 6.7 and later.\n");
6981 MODULE_PARM_DESC(mem,
6982 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6983 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6984 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6985 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6986 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6987 "The value is to be specified without 'KB'.\n");
6990 MODULE_PARM_DESC(noaccel,
6991 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6994 MODULE_PARM_DESC(noypan,
6995 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6996 "will be performed by redrawing the screen. (default: 0)\n");
6998 MODULE_PARM_DESC(nomax,
6999 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
7000 "memory for the virtual screen in order to optimize scrolling performance. If\n"
7001 "this is set to anything other than 0, sisfb will not do this and thereby \n"
7002 "enable the user to positively specify a virtual Y size of the screen using\n"
7003 "fbset. (default: 0)\n");
7005 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7006 MODULE_PARM_DESC(mode,
7007 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7008 "1024x768x16. Other formats supported include XxY-Depth and\n"
7009 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7010 "number, it will be interpreted as a VESA mode number. (default: none if\n"
7011 "sisfb is a module; this leaves the console untouched and the driver will\n"
7012 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7013 "is in the kernel)\n");
7014 MODULE_PARM_DESC(vesa,
7015 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7016 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
7017 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7018 "0x0103 if sisfb is in the kernel)\n");
7021 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7022 MODULE_PARM_DESC(mode,
7023 "\nSelects the desired default display mode in the format XxYxDepth,\n"
7024 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
7025 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7026 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7028 MODULE_PARM_DESC(vesa,
7029 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7030 "0x117 (default: 0x0103)\n");
7033 MODULE_PARM_DESC(rate,
7034 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7035 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7036 "will be ignored (default: 60)\n");
7038 MODULE_PARM_DESC(forcecrt1,
7039 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7040 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7041 "0=CRT1 OFF) (default: [autodetected])\n");
7043 MODULE_PARM_DESC(forcecrt2type,
7044 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7045 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7046 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7047 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7048 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7049 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7050 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7051 "depends on the very hardware in use. (default: [autodetected])\n");
7053 MODULE_PARM_DESC(scalelcd,
7054 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7055 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7056 "show black bars around the image, TMDS panels will probably do the scaling\n"
7057 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7059 MODULE_PARM_DESC(pdc,
7060 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
7061 "should detect this correctly in most cases; however, sometimes this is not\n"
7062 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
7063 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7064 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7065 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
7067 #ifdef CONFIG_FB_SIS_315
7068 MODULE_PARM_DESC(pdc1,
7069 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
7070 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7071 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7072 "implemented yet.\n");
7075 MODULE_PARM_DESC(specialtiming,
7076 "\nPlease refer to documentation for more information on this option.\n");
7078 MODULE_PARM_DESC(lvdshl,
7079 "\nPlease refer to documentation for more information on this option.\n");
7081 MODULE_PARM_DESC(tvstandard,
7082 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7083 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7085 MODULE_PARM_DESC(tvxposoffset,
7086 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7089 MODULE_PARM_DESC(tvyposoffset,
7090 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7093 MODULE_PARM_DESC(nocrt2rate,
7094 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7095 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7097 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7098 MODULE_PARM_DESC(inverse,
7099 "\nSetting this to anything but 0 should invert the display colors, but this\n"
7100 "does not seem to work. (default: 0)\n");
7103 #if !defined(__i386__) && !defined(__x86_64__)
7104 #ifdef CONFIG_FB_SIS_300
7105 MODULE_PARM_DESC(resetcard,
7106 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
7107 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7108 "currently). Default: 0\n");
7110 MODULE_PARM_DESC(videoram,
7111 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7112 "some non-x86 architectures where the memory auto detection fails. Only\n"
7113 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
7117 #endif /* /MODULE */
7119 /* _GPL only for new symbols. */
7120 EXPORT_SYMBOL(sis_malloc);
7121 EXPORT_SYMBOL(sis_free);
7122 EXPORT_SYMBOL_GPL(sis_malloc_new);
7123 EXPORT_SYMBOL_GPL(sis_free_new);