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>
47 #include <linux/tty.h>
48 #include <linux/slab.h>
50 #include <linux/selection.h>
51 #include <linux/ioport.h>
52 #include <linux/init.h>
53 #include <linux/pci.h>
54 #include <linux/vmalloc.h>
55 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
56 #include <linux/vt_kern.h>
58 #include <linux/capability.h>
60 #include <linux/types.h>
61 #include <asm/uaccess.h>
67 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
68 #include <video/fbcon.h>
69 #include <video/fbcon-cfb8.h>
70 #include <video/fbcon-cfb16.h>
71 #include <video/fbcon-cfb24.h>
72 #include <video/fbcon-cfb32.h>
78 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
79 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
80 #error "This version of sisfb requires at least 2.6.3"
84 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
86 extern struct display_switch fbcon_sis8;
88 #ifdef FBCON_HAS_CFB16
89 extern struct display_switch fbcon_sis16;
91 #ifdef FBCON_HAS_CFB32
92 extern struct display_switch fbcon_sis32;
96 static void sisfb_handle_command(struct sis_video_info *ivideo,
97 struct sisfb_cmd *sisfb_command);
99 /* ------------------ Internal helper routines ----------------- */
102 sisfb_setdefaultparms(void)
112 /* Module: "None" for 2.4, default mode for 2.5+ */
113 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
116 sisfb_mode_idx = MODE_INDEX_NONE;
119 /* Static: Default mode */
122 sisfb_parm_rate = -1;
124 sisfb_forcecrt1 = -1;
130 sisfb_specialtiming = CUT_NONE;
136 sisfb_tvxposoffset = 0;
137 sisfb_tvyposoffset = 0;
138 sisfb_nocrt2rate = 0;
139 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
141 sisfb_fontname[0] = 0;
143 #if !defined(__i386__) && !defined(__x86_64__)
149 /* ------------- Parameter parsing -------------- */
151 static void __devinit
152 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
156 /* We don't know the hardware specs yet and there is no ivideo */
159 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
160 sisfb_mode_idx = MODE_INDEX_NONE;
163 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
165 sisfb_mode_idx = DEFAULT_MODE;
170 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
172 while(sisbios_mode[i++].mode_no[0] != 0) {
173 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
174 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
176 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
177 sisbios_mode[i-1].mode_no[1] == 0x56 ||
178 sisbios_mode[i-1].mode_no[1] == 0x53)
181 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
182 sisbios_mode[i-1].mode_no[1] == 0x5b)
185 sisfb_mode_idx = i - 1;
191 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
194 static void __devinit
195 sisfb_search_mode(char *name, BOOLEAN quiet)
197 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
199 char strbuf[16], strbuf1[20];
200 char *nameptr = name;
202 /* We don't know the hardware specs yet and there is no ivideo */
206 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
208 sisfb_mode_idx = DEFAULT_MODE;
212 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
213 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
215 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
217 sisfb_mode_idx = DEFAULT_MODE;
221 if(strlen(name) <= 19) {
222 strcpy(strbuf1, name);
223 for(i = 0; i < strlen(strbuf1); i++) {
224 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
227 /* This does some fuzzy mode naming detection */
228 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
229 if((rate <= 32) || (depth > 32)) {
230 j = rate; rate = depth; depth = j;
232 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
234 sisfb_parm_rate = rate;
235 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
236 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
240 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
241 sprintf(strbuf, "%ux%ux8", xres, yres);
244 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
251 while(sisbios_mode[i].mode_no[0] != 0) {
252 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
254 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
255 sisbios_mode[i-1].mode_no[1] == 0x56 ||
256 sisbios_mode[i-1].mode_no[1] == 0x53)
259 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
260 sisbios_mode[i-1].mode_no[1] == 0x5b)
263 sisfb_mode_idx = i - 1;
270 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
274 static void __devinit
275 sisfb_get_vga_mode_from_kernel(void)
279 int mydepth = screen_info.lfb_depth;
281 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
283 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
284 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
285 (mydepth >= 8) && (mydepth <= 32) ) {
287 if(mydepth == 24) mydepth = 32;
289 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
290 screen_info.lfb_height,
294 "sisfb: Using vga mode %s pre-set by kernel as default\n",
297 sisfb_search_mode(mymode, TRUE);
305 sisfb_search_crt2type(const char *name)
309 /* We don't know the hardware specs yet and there is no ivideo */
311 if(name == NULL) return;
313 while(sis_crt2type[i].type_no != -1) {
314 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
315 sisfb_crt2type = sis_crt2type[i].type_no;
316 sisfb_tvplug = sis_crt2type[i].tvplug_no;
317 sisfb_crt2flags = sis_crt2type[i].flags;
323 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
324 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
326 if(sisfb_crt2type < 0)
327 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
331 sisfb_search_tvstd(const char *name)
335 /* We don't know the hardware specs yet and there is no ivideo */
340 while(sis_tvtype[i].type_no != -1) {
341 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
342 sisfb_tvstd = sis_tvtype[i].type_no;
350 sisfb_search_specialtiming(const char *name)
353 BOOLEAN found = FALSE;
355 /* We don't know the hardware specs yet and there is no ivideo */
360 if(!strnicmp(name, "none", 4)) {
361 sisfb_specialtiming = CUT_FORCENONE;
362 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
364 while(mycustomttable[i].chipID != 0) {
365 if(!strnicmp(name,mycustomttable[i].optionName,
366 strlen(mycustomttable[i].optionName))) {
367 sisfb_specialtiming = mycustomttable[i].SpecialID;
369 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
370 mycustomttable[i].vendorName,
371 mycustomttable[i].cardName,
372 mycustomttable[i].optionName);
378 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
379 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
381 while(mycustomttable[i].chipID != 0) {
382 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
383 mycustomttable[i].optionName,
384 mycustomttable[i].vendorName,
385 mycustomttable[i].cardName);
392 /* ----------- Various detection routines ----------- */
394 static void __devinit
395 sisfb_detect_custom_timing(struct sis_video_info *ivideo)
397 unsigned char *biosver = NULL;
398 unsigned char *biosdate = NULL;
403 if(ivideo->SiS_Pr.UseROM) {
404 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
405 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
406 for(i = 0; i < 32768; i++)
407 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
412 if( (mycustomttable[i].chipID == ivideo->chip) &&
413 ((!strlen(mycustomttable[i].biosversion)) ||
414 (ivideo->SiS_Pr.UseROM &&
415 (!strncmp(mycustomttable[i].biosversion, biosver,
416 strlen(mycustomttable[i].biosversion))))) &&
417 ((!strlen(mycustomttable[i].biosdate)) ||
418 (ivideo->SiS_Pr.UseROM &&
419 (!strncmp(mycustomttable[i].biosdate, biosdate,
420 strlen(mycustomttable[i].biosdate))))) &&
421 ((!mycustomttable[i].bioschksum) ||
422 (ivideo->SiS_Pr.UseROM &&
423 (mycustomttable[i].bioschksum == chksum))) &&
424 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
425 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
427 for(j = 0; j < 5; j++) {
428 if(mycustomttable[i].biosFootprintAddr[j]) {
429 if(ivideo->SiS_Pr.UseROM) {
430 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
431 mycustomttable[i].biosFootprintData[j]) {
439 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
440 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
441 mycustomttable[i].vendorName,
442 mycustomttable[i].cardName);
443 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
444 mycustomttable[i].optionName);
449 } while(mycustomttable[i].chipID);
452 static BOOLEAN __devinit
453 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
455 int i, j, xres, yres, refresh, index;
458 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
459 buffer[2] != 0xff || buffer[3] != 0xff ||
460 buffer[4] != 0xff || buffer[5] != 0xff ||
461 buffer[6] != 0xff || buffer[7] != 0x00) {
462 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
466 if(buffer[0x12] != 0x01) {
467 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
472 monitor->feature = buffer[0x18];
474 if(!buffer[0x14] & 0x80) {
475 if(!(buffer[0x14] & 0x08)) {
477 "sisfb: WARNING: Monitor does not support separate syncs\n");
481 if(buffer[0x13] >= 0x01) {
482 /* EDID V1 rev 1 and 2: Search for monitor descriptor
487 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
488 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
489 buffer[j + 4] == 0x00) {
490 monitor->hmin = buffer[j + 7];
491 monitor->hmax = buffer[j + 8];
492 monitor->vmin = buffer[j + 5];
493 monitor->vmax = buffer[j + 6];
494 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
495 monitor->datavalid = TRUE;
502 if(!monitor->datavalid) {
503 /* Otherwise: Get a range from the list of supported
504 * Estabished Timings. This is not entirely accurate,
505 * because fixed frequency monitors are not supported
508 monitor->hmin = 65535; monitor->hmax = 0;
509 monitor->vmin = 65535; monitor->vmax = 0;
510 monitor->dclockmax = 0;
511 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
512 for(i = 0; i < 13; i++) {
513 if(emodes & sisfb_ddcsmodes[i].mask) {
514 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
515 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
516 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
517 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
518 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
522 for(i = 0; i < 8; i++) {
523 xres = (buffer[index] + 31) * 8;
524 switch(buffer[index + 1] & 0xc0) {
525 case 0xc0: yres = (xres * 9) / 16; break;
526 case 0x80: yres = (xres * 4) / 5; break;
527 case 0x40: yres = (xres * 3) / 4; break;
528 default: yres = xres; break;
530 refresh = (buffer[index + 1] & 0x3f) + 60;
531 if((xres >= 640) && (yres >= 480)) {
532 for(j = 0; j < 8; j++) {
533 if((xres == sisfb_ddcfmodes[j].x) &&
534 (yres == sisfb_ddcfmodes[j].y) &&
535 (refresh == sisfb_ddcfmodes[j].v)) {
536 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
537 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
538 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
539 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
540 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
546 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
547 monitor->datavalid = TRUE;
551 return monitor->datavalid;
554 static void __devinit
555 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
557 unsigned short temp, i, realcrtno = crtno;
558 unsigned char buffer[256];
560 monitor->datavalid = FALSE;
563 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
564 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
568 if((ivideo->sisfb_crt1off) && (!crtno))
571 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
572 realcrtno, 0, &buffer[0], ivideo->vbflags2);
573 if((!temp) || (temp == 0xffff)) {
574 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
577 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
578 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
580 (temp & 0x1a) ? "" : "[none of the supported]",
581 (temp & 0x02) ? "2 " : "",
582 (temp & 0x08) ? "D&P" : "",
583 (temp & 0x10) ? "FPDI-2" : "");
585 i = 3; /* Number of retrys */
587 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
588 realcrtno, 1, &buffer[0], ivideo->vbflags2);
589 } while((temp) && i--);
591 if(sisfb_interpret_edid(monitor, &buffer[0])) {
592 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
593 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
594 monitor->dclockmax / 1000);
596 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
599 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
602 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
607 /* -------------- Mode validation --------------- */
610 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
611 int mode_idx, int rate_idx, int rate)
614 unsigned int dclock, hsync;
616 if(!monitor->datavalid)
622 /* Skip for 320x200, 320x240, 640x400 */
623 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
634 #ifdef CONFIG_FB_SIS_315
637 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
641 if(rate < (monitor->vmin - 1))
643 if(rate > (monitor->vmax + 1))
646 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
647 sisbios_mode[mode_idx].mode_no[ivideo->mni],
648 &htotal, &vtotal, rate_idx)) {
649 dclock = (htotal * vtotal * rate) / 1000;
650 if(dclock > (monitor->dclockmax + 1000))
652 hsync = dclock / htotal;
653 if(hsync < (monitor->hmin - 1))
655 if(hsync > (monitor->hmax + 1))
664 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
666 u16 xres=0, yres, myres;
668 #ifdef CONFIG_FB_SIS_300
669 if(ivideo->sisvga_engine == SIS_300_VGA) {
670 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
674 #ifdef CONFIG_FB_SIS_315
675 if(ivideo->sisvga_engine == SIS_315_VGA) {
676 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
681 myres = sisbios_mode[myindex].yres;
683 switch(vbflags & VB_DISPTYPE_DISP2) {
686 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
688 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
689 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
690 if(sisbios_mode[myindex].xres > xres)
696 if(ivideo->sisfb_fstn) {
697 if(sisbios_mode[myindex].xres == 320) {
699 switch(sisbios_mode[myindex].mode_no[1]) {
700 case 0x50: myindex = MODE_FSTN_8; break;
701 case 0x56: myindex = MODE_FSTN_16; break;
702 case 0x53: return -1;
708 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
709 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
710 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
716 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
717 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
723 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
724 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
734 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
737 u16 xres = sisbios_mode[mode_idx].xres;
738 u16 yres = sisbios_mode[mode_idx].yres;
740 ivideo->rate_idx = 0;
741 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
742 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
743 if(sisfb_vrate[i].refresh == rate) {
744 ivideo->rate_idx = sisfb_vrate[i].idx;
746 } else if(sisfb_vrate[i].refresh > rate) {
747 if((sisfb_vrate[i].refresh - rate) <= 3) {
748 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
749 rate, sisfb_vrate[i].refresh);
750 ivideo->rate_idx = sisfb_vrate[i].idx;
751 ivideo->refresh_rate = sisfb_vrate[i].refresh;
752 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
753 && (sisfb_vrate[i].idx != 1)) {
754 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
755 rate, sisfb_vrate[i-1].refresh);
756 ivideo->rate_idx = sisfb_vrate[i-1].idx;
757 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
760 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
761 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
762 rate, sisfb_vrate[i].refresh);
763 ivideo->rate_idx = sisfb_vrate[i].idx;
769 if(ivideo->rate_idx > 0) {
770 return ivideo->rate_idx;
772 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
779 sisfb_bridgeisslave(struct sis_video_info *ivideo)
783 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
786 inSISIDXREG(SISPART1,0x00,P1_00);
787 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
788 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
796 sisfballowretracecrt1(struct sis_video_info *ivideo)
800 inSISIDXREG(SISCR,0x17,temp);
804 inSISIDXREG(SISSR,0x1f,temp);
812 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
814 if(!sisfballowretracecrt1(ivideo))
817 if(inSISREG(SISINPSTAT) & 0x08)
824 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
828 if(!sisfballowretracecrt1(ivideo))
832 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
834 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
838 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
840 unsigned char temp, reg;
842 switch(ivideo->sisvga_engine) {
843 case SIS_300_VGA: reg = 0x25; break;
844 case SIS_315_VGA: reg = 0x30; break;
845 default: return FALSE;
848 inSISIDXREG(SISPART1, reg, temp);
856 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
858 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
859 if(!sisfb_bridgeisslave(ivideo)) {
860 return sisfbcheckvretracecrt2(ivideo);
863 return sisfbcheckvretracecrt1(ivideo);
867 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
869 u8 idx, reg1, reg2, reg3, reg4;
872 (*vcount) = (*hcount) = 0;
874 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
876 ret |= (FB_VBLANK_HAVE_VSYNC |
877 FB_VBLANK_HAVE_HBLANK |
878 FB_VBLANK_HAVE_VBLANK |
879 FB_VBLANK_HAVE_VCOUNT |
880 FB_VBLANK_HAVE_HCOUNT);
881 switch(ivideo->sisvga_engine) {
882 case SIS_300_VGA: idx = 0x25; break;
884 case SIS_315_VGA: idx = 0x30; break;
886 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
887 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
888 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
889 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
890 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
891 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
892 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
893 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
894 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
896 } else if(sisfballowretracecrt1(ivideo)) {
898 ret |= (FB_VBLANK_HAVE_VSYNC |
899 FB_VBLANK_HAVE_VBLANK |
900 FB_VBLANK_HAVE_VCOUNT |
901 FB_VBLANK_HAVE_HCOUNT);
902 reg1 = inSISREG(SISINPSTAT);
903 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
904 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
905 inSISIDXREG(SISCR,0x20,reg1);
906 inSISIDXREG(SISCR,0x1b,reg1);
907 inSISIDXREG(SISCR,0x1c,reg2);
908 inSISIDXREG(SISCR,0x1d,reg3);
909 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
910 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
917 sisfb_myblank(struct sis_video_info *ivideo, int blank)
919 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
920 BOOLEAN backlight = TRUE;
923 case FB_BLANK_UNBLANK: /* on */
932 case FB_BLANK_NORMAL: /* blank */
941 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
950 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
959 case FB_BLANK_POWERDOWN: /* off */
972 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
974 if( (!ivideo->sisfb_thismonitor.datavalid) ||
975 ((ivideo->sisfb_thismonitor.datavalid) &&
976 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
978 if(ivideo->sisvga_engine == SIS_315_VGA) {
979 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
982 if(!(sisfb_bridgeisslave(ivideo))) {
983 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
984 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
990 if(ivideo->currentvbflags & CRT2_LCD) {
992 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
994 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
996 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
998 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
999 #ifdef CONFIG_FB_SIS_315
1000 if(ivideo->vbflags2 & VB2_CHRONTEL) {
1002 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
1004 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
1010 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
1011 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
1012 ((ivideo->sisvga_engine == SIS_315_VGA) &&
1013 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
1014 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
1017 if(ivideo->sisvga_engine == SIS_300_VGA) {
1018 if((ivideo->vbflags2 & VB2_30xB) &&
1019 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1020 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
1022 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1023 if((ivideo->vbflags2 & VB2_30xB) &&
1024 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1025 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1029 } else if(ivideo->currentvbflags & CRT2_VGA) {
1031 if(ivideo->vbflags2 & VB2_30xB) {
1032 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1040 /* ------------- Callbacks from init.c/init301.c -------------- */
1042 #ifdef CONFIG_FB_SIS_300
1044 sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1046 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1049 pci_read_config_dword(ivideo->nbridge, reg, &val);
1050 return (unsigned int)val;
1054 sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1056 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1058 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1062 sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1064 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1067 if(!ivideo->lpcdev) return 0;
1069 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1070 return (unsigned int)val;
1074 #ifdef CONFIG_FB_SIS_315
1076 sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1078 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1080 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1084 sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1086 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1089 if(!ivideo->lpcdev) return 0;
1091 pci_read_config_word(ivideo->lpcdev, reg, &val);
1092 return (unsigned int)val;
1096 /* ----------- FBDev related routines for all series ----------- */
1099 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1101 return (var->bits_per_pixel == 8) ? 256 : 16;
1105 sisfb_set_vparms(struct sis_video_info *ivideo)
1107 switch(ivideo->video_bpp) {
1109 ivideo->DstColor = 0x0000;
1110 ivideo->SiS310_AccelDepth = 0x00000000;
1111 ivideo->video_cmap_len = 256;
1114 ivideo->DstColor = 0x8000;
1115 ivideo->SiS310_AccelDepth = 0x00010000;
1116 ivideo->video_cmap_len = 16;
1119 ivideo->DstColor = 0xC000;
1120 ivideo->SiS310_AccelDepth = 0x00020000;
1121 ivideo->video_cmap_len = 16;
1124 ivideo->video_cmap_len = 16;
1125 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1131 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1133 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1135 if(maxyres > 32767) maxyres = 32767;
1141 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1143 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1144 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1145 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1146 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1147 ivideo->scrnpitchCRT1 <<= 1;
1153 sisfb_set_pitch(struct sis_video_info *ivideo)
1155 BOOLEAN isslavemode = FALSE;
1156 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1157 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1159 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
1161 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1162 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1163 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1164 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1167 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1168 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1169 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1170 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1171 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1176 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1178 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1180 switch(var->bits_per_pixel) {
1182 var->red.offset = var->green.offset = var->blue.offset = 0;
1183 var->red.length = var->green.length = var->blue.length = 6;
1186 var->red.offset = 11;
1187 var->red.length = 5;
1188 var->green.offset = 5;
1189 var->green.length = 6;
1190 var->blue.offset = 0;
1191 var->blue.length = 5;
1192 var->transp.offset = 0;
1193 var->transp.length = 0;
1196 var->red.offset = 16;
1197 var->red.length = 8;
1198 var->green.offset = 8;
1199 var->green.length = 8;
1200 var->blue.offset = 0;
1201 var->blue.length = 8;
1202 var->transp.offset = 24;
1203 var->transp.length = 8;
1209 sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1211 unsigned short modeno = ivideo->mode_no;
1213 /* >=2.6.12's fbcon clears the screen anyway */
1214 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
1215 if(!clrscrn) modeno |= 0x80;
1220 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1222 sisfb_pre_setmode(ivideo);
1224 if(SiSSetMode(&ivideo->SiS_Pr, modeno) == 0) {
1225 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1229 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1231 sisfb_post_setmode(ivideo);
1238 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1240 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1241 unsigned int htotal = 0, vtotal = 0;
1242 unsigned int drate = 0, hrate = 0;
1243 int found_mode = 0, ret;
1247 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1249 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1251 pixclock = var->pixclock;
1253 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1254 vtotal += var->yres;
1256 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1257 vtotal += var->yres;
1259 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1260 vtotal += var->yres;
1262 } else vtotal += var->yres;
1264 if(!(htotal) || !(vtotal)) {
1265 DPRINTK("sisfb: Invalid 'var' information\n");
1269 if(pixclock && htotal && vtotal) {
1270 drate = 1000000000 / pixclock;
1271 hrate = (drate * 1000) / htotal;
1272 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1274 ivideo->refresh_rate = 60;
1277 old_mode = ivideo->sisfb_mode_idx;
1278 ivideo->sisfb_mode_idx = 0;
1280 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1281 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1282 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1283 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1284 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1285 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1289 ivideo->sisfb_mode_idx++;
1293 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1294 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1295 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1297 ivideo->sisfb_mode_idx = -1;
1300 if(ivideo->sisfb_mode_idx < 0) {
1301 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1302 var->yres, var->bits_per_pixel);
1303 ivideo->sisfb_mode_idx = old_mode;
1307 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1308 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1309 ivideo->refresh_rate = 60;
1312 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1313 if(ivideo->sisfb_thismonitor.datavalid) {
1314 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
1315 ivideo->rate_idx, ivideo->refresh_rate)) {
1316 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1321 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1322 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1326 /* If acceleration to be used? Need to know
1327 * before pre/post_set_mode()
1330 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1331 #ifdef STUPID_ACCELF_TEXT_SHIT
1332 if(var->accel_flags & FB_ACCELF_TEXT) {
1333 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1335 info->flags |= FBINFO_HWACCEL_DISABLED;
1338 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1340 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1343 if((ret = sisfb_set_mode(ivideo, 1))) {
1347 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1348 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1349 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1351 sisfb_calc_pitch(ivideo, var);
1352 sisfb_set_pitch(ivideo);
1354 sisfb_set_vparms(ivideo);
1356 ivideo->current_width = ivideo->video_width;
1357 ivideo->current_height = ivideo->video_height;
1358 ivideo->current_bpp = ivideo->video_bpp;
1359 ivideo->current_htotal = htotal;
1360 ivideo->current_vtotal = vtotal;
1361 ivideo->current_linelength = ivideo->video_linelength;
1362 ivideo->current_pixclock = var->pixclock;
1363 ivideo->current_refresh_rate = ivideo->refresh_rate;
1364 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1365 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1373 sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1375 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1377 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1378 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1379 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1380 if(ivideo->sisvga_engine == SIS_315_VGA) {
1381 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1386 sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1388 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1389 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1390 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1391 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1392 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1393 if(ivideo->sisvga_engine == SIS_315_VGA) {
1394 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1400 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1402 if(var->xoffset > (var->xres_virtual - var->xres)) {
1405 if(var->yoffset > (var->yres_virtual - var->yres)) {
1409 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
1411 /* calculate base bpp dep. */
1412 switch(var->bits_per_pixel) {
1416 ivideo->current_base >>= 1;
1420 ivideo->current_base >>= 2;
1424 ivideo->current_base += (ivideo->video_offset >> 2);
1426 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1427 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1432 /* ------------ FBDev related routines for 2.4 series ----------- */
1434 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1436 #include "sisfb_fbdev_2_4.h"
1440 /* ------------ FBDev related routines for 2.6 series ----------- */
1442 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1445 sisfb_open(struct fb_info *info, int user)
1451 sisfb_release(struct fb_info *info, int user)
1457 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1458 unsigned transp, struct fb_info *info)
1460 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1462 if(regno >= sisfb_get_cmap_len(&info->var))
1465 switch(info->var.bits_per_pixel) {
1467 outSISREG(SISDACA, regno);
1468 outSISREG(SISDACD, (red >> 10));
1469 outSISREG(SISDACD, (green >> 10));
1470 outSISREG(SISDACD, (blue >> 10));
1471 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1472 outSISREG(SISDAC2A, regno);
1473 outSISREG(SISDAC2D, (red >> 8));
1474 outSISREG(SISDAC2D, (green >> 8));
1475 outSISREG(SISDAC2D, (blue >> 8));
1479 ((u32 *)(info->pseudo_palette))[regno] =
1481 ((green & 0xfc00) >> 5) |
1482 ((blue & 0xf800) >> 11);
1488 ((u32 *)(info->pseudo_palette))[regno] =
1489 (red << 16) | (green << 8) | (blue);
1496 sisfb_set_par(struct fb_info *info)
1500 if((err = sisfb_do_set_var(&info->var, 1, info)))
1503 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1504 sisfb_get_fix(&info->fix, info->currcon, info);
1506 sisfb_get_fix(&info->fix, -1, info);
1512 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1514 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1515 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1516 unsigned int drate = 0, hrate = 0, maxyres;
1518 int refresh_rate, search_idx, tidx;
1519 BOOLEAN recalc_clock = FALSE;
1522 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1524 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1526 pixclock = var->pixclock;
1528 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1529 vtotal += var->yres;
1531 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1532 vtotal += var->yres;
1534 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1535 vtotal += var->yres;
1538 vtotal += var->yres;
1540 if(!(htotal) || !(vtotal)) {
1541 SISFAIL("sisfb: no valid timing data");
1545 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1546 (sisbios_mode[search_idx].xres <= var->xres) ) {
1547 if( (sisbios_mode[search_idx].xres == var->xres) &&
1548 (sisbios_mode[search_idx].yres == var->yres) &&
1549 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1550 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1551 ivideo->currentvbflags)) > 0) {
1562 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1563 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1564 (var->yres <= sisbios_mode[search_idx].yres) &&
1565 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1566 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1567 ivideo->currentvbflags)) > 0) {
1577 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1578 var->xres, var->yres, var->bits_per_pixel,
1579 sisbios_mode[search_idx].xres,
1580 sisbios_mode[search_idx].yres,
1581 var->bits_per_pixel);
1582 var->xres = sisbios_mode[search_idx].xres;
1583 var->yres = sisbios_mode[search_idx].yres;
1586 "sisfb: Failed to find supported mode near %dx%dx%d\n",
1587 var->xres, var->yres, var->bits_per_pixel);
1592 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1593 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1594 (var->bits_per_pixel == 8) ) {
1595 /* Slave modes on LVDS and 301B-DH */
1597 recalc_clock = TRUE;
1598 } else if( (ivideo->current_htotal == htotal) &&
1599 (ivideo->current_vtotal == vtotal) &&
1600 (ivideo->current_pixclock == pixclock) ) {
1601 /* x=x & y=y & c=c -> assume depth change */
1602 drate = 1000000000 / pixclock;
1603 hrate = (drate * 1000) / htotal;
1604 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1605 } else if( ( (ivideo->current_htotal != htotal) ||
1606 (ivideo->current_vtotal != vtotal) ) &&
1607 (ivideo->current_pixclock == var->pixclock) ) {
1608 /* x!=x | y!=y & c=c -> invalid pixclock */
1609 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1611 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1612 } else if(ivideo->sisfb_parm_rate != -1) {
1613 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1614 refresh_rate = ivideo->sisfb_parm_rate;
1618 recalc_clock = TRUE;
1619 } else if((pixclock) && (htotal) && (vtotal)) {
1620 drate = 1000000000 / pixclock;
1621 hrate = (drate * 1000) / htotal;
1622 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1623 } else if(ivideo->current_refresh_rate) {
1624 refresh_rate = ivideo->current_refresh_rate;
1625 recalc_clock = TRUE;
1628 recalc_clock = TRUE;
1631 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1633 /* Eventually recalculate timing and clock */
1635 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1636 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1637 sisbios_mode[search_idx].mode_no[ivideo->mni],
1639 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1640 sisbios_mode[search_idx].mode_no[ivideo->mni],
1642 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1643 var->pixclock <<= 1;
1647 if(ivideo->sisfb_thismonitor.datavalid) {
1648 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1649 myrateindex, refresh_rate)) {
1651 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1655 /* Adapt RGB settings */
1656 sisfb_bpp_to_var(ivideo, var);
1658 /* Sanity check for offsets */
1659 if(var->xoffset < 0) var->xoffset = 0;
1660 if(var->yoffset < 0) var->yoffset = 0;
1662 if(var->xres > var->xres_virtual)
1663 var->xres_virtual = var->xres;
1665 if(ivideo->sisfb_ypan) {
1666 maxyres = sisfb_calc_maxyres(ivideo, var);
1667 if(ivideo->sisfb_max) {
1668 var->yres_virtual = maxyres;
1670 if(var->yres_virtual > maxyres) {
1671 var->yres_virtual = maxyres;
1674 if(var->yres_virtual <= var->yres) {
1675 var->yres_virtual = var->yres;
1678 if(var->yres != var->yres_virtual) {
1679 var->yres_virtual = var->yres;
1685 /* Truncate offsets to maximum if too high */
1686 if(var->xoffset > var->xres_virtual - var->xres) {
1687 var->xoffset = var->xres_virtual - var->xres - 1;
1690 if(var->yoffset > var->yres_virtual - var->yres) {
1691 var->yoffset = var->yres_virtual - var->yres - 1;
1694 /* Set everything else to 0 */
1695 var->red.msb_right =
1696 var->green.msb_right =
1697 var->blue.msb_right =
1698 var->transp.offset =
1699 var->transp.length =
1700 var->transp.msb_right = 0;
1706 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1708 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1711 if(var->xoffset > (var->xres_virtual - var->xres))
1714 if(var->yoffset > (var->yres_virtual - var->yres))
1717 if(var->vmode & FB_VMODE_YWRAP)
1720 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
1721 var->yoffset + info->var.yres > info->var.yres_virtual)
1724 if((err = sisfb_pan_var(ivideo, var)) < 0)
1727 info->var.xoffset = var->xoffset;
1728 info->var.yoffset = var->yoffset;
1734 sisfb_blank(int blank, struct fb_info *info)
1736 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1738 return sisfb_myblank(ivideo, blank);
1743 /* ----------- FBDev related routines for all series ---------- */
1745 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1746 static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1749 static int sisfb_ioctl(struct inode *inode, struct file *file,
1750 unsigned int cmd, unsigned long arg,
1751 struct fb_info *info)
1754 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1755 struct sis_memreq sismemreq;
1756 struct fb_vblank sisvbblank;
1761 u32 __user *argp = (u32 __user *)arg;
1765 if(!capable(CAP_SYS_RAWIO))
1768 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1771 sis_malloc(&sismemreq);
1773 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1774 sis_free((u32)sismemreq.offset);
1780 if(!capable(CAP_SYS_RAWIO))
1783 if(get_user(gpu32, argp))
1789 case FBIOGET_VBLANK:
1790 sisvbblank.count = 0;
1791 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1793 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1798 case SISFB_GET_INFO_SIZE:
1799 return put_user(sizeof(struct sisfb_info), argp);
1801 case SISFB_GET_INFO_OLD:
1802 if(ivideo->warncount++ < 10)
1804 "sisfb: Deprecated ioctl call received - update your application!\n");
1805 case SISFB_GET_INFO: /* For communication with X driver */
1806 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1807 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1808 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1809 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1810 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1811 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1812 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1813 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1814 if(ivideo->modechanged) {
1815 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1817 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1819 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1820 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1821 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1822 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1823 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1824 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1825 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1826 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1827 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1828 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1829 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1830 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1831 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1832 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1833 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1834 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1835 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1836 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1837 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1838 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1839 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1840 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1841 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1842 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1843 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1844 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1845 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1846 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1848 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1849 sizeof(ivideo->sisfb_infoblock)))
1854 case SISFB_GET_VBRSTATUS_OLD:
1855 if(ivideo->warncount++ < 10)
1857 "sisfb: Deprecated ioctl call received - update your application!\n");
1858 case SISFB_GET_VBRSTATUS:
1859 if(sisfb_CheckVBRetrace(ivideo))
1860 return put_user((u32)1, argp);
1862 return put_user((u32)0, argp);
1864 case SISFB_GET_AUTOMAXIMIZE_OLD:
1865 if(ivideo->warncount++ < 10)
1867 "sisfb: Deprecated ioctl call received - update your application!\n");
1868 case SISFB_GET_AUTOMAXIMIZE:
1869 if(ivideo->sisfb_max)
1870 return put_user((u32)1, argp);
1872 return put_user((u32)0, argp);
1874 case SISFB_SET_AUTOMAXIMIZE_OLD:
1875 if(ivideo->warncount++ < 10)
1877 "sisfb: Deprecated ioctl call received - update your application!\n");
1878 case SISFB_SET_AUTOMAXIMIZE:
1879 if(get_user(gpu32, argp))
1882 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1885 case SISFB_SET_TVPOSOFFSET:
1886 if(get_user(gpu32, argp))
1889 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1890 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1893 case SISFB_GET_TVPOSOFFSET:
1894 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1898 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1899 sizeof(struct sisfb_cmd)))
1902 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1904 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1905 sizeof(struct sisfb_cmd)))
1910 case SISFB_SET_LOCK:
1911 if(get_user(gpu32, argp))
1914 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1918 #ifdef SIS_NEW_CONFIG_COMPAT
1919 return -ENOIOCTLCMD;
1928 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1930 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1932 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1934 strcpy(fix->id, ivideo->myid);
1936 fix->smem_start = ivideo->video_base + ivideo->video_offset;
1937 fix->smem_len = ivideo->sisfb_mem;
1938 fix->type = FB_TYPE_PACKED_PIXELS;
1940 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1942 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1944 fix->line_length = ivideo->video_linelength;
1945 fix->mmio_start = ivideo->mmio_base;
1946 fix->mmio_len = ivideo->mmio_size;
1947 if(ivideo->sisvga_engine == SIS_300_VGA) {
1948 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1949 } else if((ivideo->chip == SIS_330) ||
1950 (ivideo->chip == SIS_760) ||
1951 (ivideo->chip == SIS_761)) {
1952 fix->accel = FB_ACCEL_SIS_XABRE;
1953 } else if(ivideo->chip == XGI_20) {
1954 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1955 } else if(ivideo->chip >= XGI_40) {
1956 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1958 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1964 /* ---------------- fb_ops structures ----------------- */
1966 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1967 static struct fb_ops sisfb_ops = {
1968 .owner = THIS_MODULE,
1969 .fb_get_fix = sisfb_get_fix,
1970 .fb_get_var = sisfb_get_var,
1971 .fb_set_var = sisfb_set_var,
1972 .fb_get_cmap = sisfb_get_cmap,
1973 .fb_set_cmap = sisfb_set_cmap,
1974 .fb_pan_display = sisfb_pan_display,
1975 .fb_ioctl = sisfb_ioctl
1979 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1980 static struct fb_ops sisfb_ops = {
1981 .owner = THIS_MODULE,
1982 .fb_open = sisfb_open,
1983 .fb_release = sisfb_release,
1984 .fb_check_var = sisfb_check_var,
1985 .fb_set_par = sisfb_set_par,
1986 .fb_setcolreg = sisfb_setcolreg,
1987 .fb_pan_display = sisfb_pan_display,
1988 .fb_blank = sisfb_blank,
1989 .fb_fillrect = fbcon_sis_fillrect,
1990 .fb_copyarea = fbcon_sis_copyarea,
1991 .fb_imageblit = cfb_imageblit,
1992 #ifdef CONFIG_FB_SOFT_CURSOR
1993 .fb_cursor = soft_cursor,
1995 .fb_sync = fbcon_sis_sync,
1996 #ifdef SIS_NEW_CONFIG_COMPAT
1997 .fb_compat_ioctl= sisfb_ioctl,
1999 .fb_ioctl = sisfb_ioctl
2003 /* ---------------- Chip generation dependent routines ---------------- */
2005 static struct pci_dev * __devinit
2006 sisfb_get_northbridge(int basechipid)
2008 struct pci_dev *pdev = NULL;
2009 int nbridgenum, nbridgeidx, i;
2010 static const unsigned short nbridgeids[] = {
2011 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2012 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2013 PCI_DEVICE_ID_SI_730,
2014 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2015 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2016 PCI_DEVICE_ID_SI_651,
2017 PCI_DEVICE_ID_SI_740,
2018 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
2019 PCI_DEVICE_ID_SI_741,
2020 PCI_DEVICE_ID_SI_660,
2021 PCI_DEVICE_ID_SI_760,
2022 PCI_DEVICE_ID_SI_761
2025 switch(basechipid) {
2026 #ifdef CONFIG_FB_SIS_300
2027 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2028 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2030 #ifdef CONFIG_FB_SIS_315
2031 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2032 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
2033 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
2035 default: return NULL;
2037 for(i = 0; i < nbridgenum; i++) {
2038 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2039 nbridgeids[nbridgeidx+i], NULL)))
2045 static int __devinit
2046 sisfb_get_dram_size(struct sis_video_info *ivideo)
2048 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2052 ivideo->video_size = 0;
2053 ivideo->UMAsize = ivideo->LFBsize = 0;
2055 switch(ivideo->chip) {
2056 #ifdef CONFIG_FB_SIS_300
2058 inSISIDXREG(SISSR, 0x14, reg);
2059 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2064 if(!ivideo->nbridge)
2066 pci_read_config_byte(ivideo->nbridge, 0x63, ®);
2067 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2070 #ifdef CONFIG_FB_SIS_315
2074 inSISIDXREG(SISSR, 0x14, reg);
2075 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2076 switch((reg >> 2) & 0x03) {
2079 ivideo->video_size <<= 1;
2082 ivideo->video_size += (ivideo->video_size/2);
2086 inSISIDXREG(SISSR, 0x14, reg);
2087 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2088 if(reg & 0x0c) ivideo->video_size <<= 1;
2093 inSISIDXREG(SISSR, 0x14, reg);
2094 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2098 inSISIDXREG(SISCR, 0x79, reg);
2099 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2104 inSISIDXREG(SISCR, 0x79, reg);
2105 reg = (reg & 0xf0) >> 4;
2107 ivideo->video_size = (1 << reg) << 20;
2108 ivideo->UMAsize = ivideo->video_size;
2110 inSISIDXREG(SISCR, 0x78, reg);
2114 ivideo->LFBsize = (32 << 20);
2116 ivideo->LFBsize = (64 << 20);
2118 ivideo->video_size += ivideo->LFBsize;
2124 inSISIDXREG(SISSR, 0x14, reg);
2125 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2126 if(ivideo->chip != XGI_20) {
2127 reg = (reg & 0x0c) >> 2;
2128 if(ivideo->revision_id == 2) {
2129 if(reg & 0x01) reg = 0x02;
2132 if(reg == 0x02) ivideo->video_size <<= 1;
2133 else if(reg == 0x03) ivideo->video_size <<= 2;
2143 /* -------------- video bridge device detection --------------- */
2145 static void __devinit
2146 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2150 /* No CRT2 on XGI Z7 */
2151 if(ivideo->chip == XGI_20) {
2152 ivideo->sisfb_crt1off = 0;
2156 #ifdef CONFIG_FB_SIS_300
2157 if(ivideo->sisvga_engine == SIS_300_VGA) {
2158 inSISIDXREG(SISSR, 0x17, temp);
2159 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2160 /* PAL/NTSC is stored on SR16 on such machines */
2161 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2162 inSISIDXREG(SISSR, 0x16, temp);
2164 ivideo->vbflags |= TV_PAL;
2166 ivideo->vbflags |= TV_NTSC;
2172 inSISIDXREG(SISCR, 0x32, cr32);
2174 if(cr32 & SIS_CRT1) {
2175 ivideo->sisfb_crt1off = 0;
2177 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2180 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2182 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2183 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2184 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2186 /* Check given parms for hardware compatibility.
2187 * (Cannot do this in the search_xx routines since we don't
2188 * know what hardware we are running on then)
2191 if(ivideo->chip != SIS_550) {
2192 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2195 if(ivideo->sisfb_tvplug != -1) {
2196 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2197 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2198 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2199 ivideo->sisfb_tvplug = -1;
2200 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2204 if(ivideo->sisfb_tvplug != -1) {
2205 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2206 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2207 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2208 ivideo->sisfb_tvplug = -1;
2209 printk(KERN_ERR "sisfb: HiVision not supported\n");
2213 if(ivideo->sisfb_tvstd != -1) {
2214 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2215 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2216 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2217 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2218 ivideo->sisfb_tvstd = -1;
2219 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2224 /* Detect/set TV plug & type */
2225 if(ivideo->sisfb_tvplug != -1) {
2226 ivideo->vbflags |= ivideo->sisfb_tvplug;
2228 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2229 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2230 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2232 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2233 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2237 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2238 if(ivideo->sisfb_tvstd != -1) {
2239 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2240 ivideo->vbflags |= ivideo->sisfb_tvstd;
2242 if(ivideo->vbflags & TV_SCART) {
2243 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2244 ivideo->vbflags |= TV_PAL;
2246 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2247 if(ivideo->sisvga_engine == SIS_300_VGA) {
2248 inSISIDXREG(SISSR, 0x38, temp);
2249 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2250 else ivideo->vbflags |= TV_NTSC;
2251 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2252 inSISIDXREG(SISSR, 0x38, temp);
2253 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2254 else ivideo->vbflags |= TV_NTSC;
2256 inSISIDXREG(SISCR, 0x79, temp);
2257 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2258 else ivideo->vbflags |= TV_NTSC;
2263 /* Copy forceCRT1 option to CRT1off if option is given */
2264 if(ivideo->sisfb_forcecrt1 != -1) {
2265 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2269 /* ------------------ Sensing routines ------------------ */
2271 static BOOLEAN __devinit
2272 sisfb_test_DDC1(struct sis_video_info *ivideo)
2277 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2279 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2281 return (count == -1) ? FALSE : TRUE;
2284 static void __devinit
2285 sisfb_sense_crt1(struct sis_video_info *ivideo)
2287 BOOLEAN mustwait = FALSE;
2289 #ifdef CONFIG_FB_SIS_315
2295 inSISIDXREG(SISSR,0x1F,sr1F);
2296 orSISIDXREG(SISSR,0x1F,0x04);
2297 andSISIDXREG(SISSR,0x1F,0x3F);
2298 if(sr1F & 0xc0) mustwait = TRUE;
2300 #ifdef CONFIG_FB_SIS_315
2301 if(ivideo->sisvga_engine == SIS_315_VGA) {
2302 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2304 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2308 inSISIDXREG(SISCR,0x17,cr17);
2311 orSISIDXREG(SISCR,0x17,0x80);
2313 outSISIDXREG(SISSR, 0x00, 0x01);
2314 outSISIDXREG(SISSR, 0x00, 0x03);
2318 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2321 #ifdef CONFIG_FB_SIS_315
2322 if(ivideo->chip >= SIS_330) {
2323 andSISIDXREG(SISCR,0x32,~0x20);
2324 if(ivideo->chip >= SIS_340) {
2325 outSISIDXREG(SISCR, 0x57, 0x4a);
2327 outSISIDXREG(SISCR, 0x57, 0x5f);
2329 orSISIDXREG(SISCR, 0x53, 0x02);
2330 while((inSISREG(SISINPSTAT)) & 0x01) break;
2331 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2332 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2333 andSISIDXREG(SISCR, 0x53, 0xfd);
2334 andSISIDXREG(SISCR, 0x57, 0x00);
2338 if(temp == 0xffff) {
2341 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2342 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2343 } while(((temp == 0) || (temp == 0xffff)) && i--);
2345 if((temp == 0) || (temp == 0xffff)) {
2346 if(sisfb_test_DDC1(ivideo)) temp = 1;
2350 if((temp) && (temp != 0xffff)) {
2351 orSISIDXREG(SISCR,0x32,0x20);
2354 #ifdef CONFIG_FB_SIS_315
2355 if(ivideo->sisvga_engine == SIS_315_VGA) {
2356 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2360 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2362 outSISIDXREG(SISSR,0x1F,sr1F);
2365 /* Determine and detect attached devices on SiS30x */
2366 static void __devinit
2367 SiS_SenseLCD(struct sis_video_info *ivideo)
2369 unsigned char buffer[256];
2370 unsigned short temp, realcrtno, i;
2371 u8 reg, cr37 = 0, paneltype = 0;
2374 ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2376 /* LCD detection only for TMDS bridges */
2377 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2379 if(ivideo->vbflags2 & VB2_30xBDH)
2382 /* If LCD already set up by BIOS, skip it */
2383 inSISIDXREG(SISCR, 0x32, reg);
2388 if(ivideo->SiS_Pr.DDCPortMixup)
2391 /* Check DDC capabilities */
2392 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2393 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2395 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2399 i = 3; /* Number of retrys */
2401 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2402 ivideo->sisvga_engine, realcrtno, 1,
2403 &buffer[0], ivideo->vbflags2);
2404 } while((temp) && i--);
2409 /* No digital device */
2410 if(!(buffer[0x14] & 0x80))
2413 /* First detailed timing preferred timing? */
2414 if(!(buffer[0x18] & 0x02))
2417 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2418 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2430 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2441 if((buffer[0x47] & 0x18) == 0x18)
2442 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2446 outSISIDXREG(SISCR, 0x36, paneltype);
2448 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2449 orSISIDXREG(SISCR, 0x32, 0x08);
2451 ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2454 static int __devinit
2455 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2457 int temp, mytest, result, i, j;
2459 for(j = 0; j < 10; j++) {
2461 for(i = 0; i < 3; i++) {
2463 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2464 temp = (type >> 8) | (mytest & 0x00ff);
2465 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2466 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2469 inSISIDXREG(SISPART4,0x03,temp);
2472 if(temp == mytest) result++;
2474 outSISIDXREG(SISPART4,0x11,0x00);
2475 andSISIDXREG(SISPART4,0x10,0xe0);
2476 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2479 if((result == 0) || (result >= 2)) break;
2484 static void __devinit
2485 SiS_Sense30x(struct sis_video_info *ivideo)
2487 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2488 u16 svhs=0, svhs_c=0;
2489 u16 cvbs=0, cvbs_c=0;
2490 u16 vga2=0, vga2_c=0;
2492 char stdstr[] = "sisfb: Detected";
2493 char tvstr[] = "TV connected to";
2495 if(ivideo->vbflags2 & VB2_301) {
2496 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2497 inSISIDXREG(SISPART4,0x01,myflag);
2499 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2501 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2502 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2503 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2504 svhs = 0x0200; cvbs = 0x0100;
2505 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2506 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2510 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2511 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2512 svhs_c = 0x0408; cvbs_c = 0x0808;
2516 if(ivideo->haveXGIROM) {
2517 biosflag = ivideo->bios_abase[0x58] & 0x03;
2518 } else if(ivideo->newrom) {
2519 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2520 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2521 if(ivideo->bios_abase) {
2522 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2526 if(ivideo->chip == SIS_300) {
2527 inSISIDXREG(SISSR,0x3b,myflag);
2528 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2531 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2535 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2536 orSISIDXREG(SISSR,0x1e,0x20);
2538 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2539 if(ivideo->vbflags2 & VB2_30xC) {
2540 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2542 orSISIDXREG(SISPART4,0x0d,0x04);
2544 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2546 inSISIDXREG(SISPART2,0x00,backupP2_00);
2547 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2549 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2550 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2551 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2554 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2555 SISDoSense(ivideo, 0, 0);
2558 andSISIDXREG(SISCR, 0x32, ~0x14);
2560 if(vga2_c || vga2) {
2561 if(SISDoSense(ivideo, vga2, vga2_c)) {
2562 if(biosflag & 0x01) {
2563 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2564 orSISIDXREG(SISCR, 0x32, 0x04);
2566 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2567 orSISIDXREG(SISCR, 0x32, 0x10);
2572 andSISIDXREG(SISCR, 0x32, 0x3f);
2574 if(ivideo->vbflags2 & VB2_30xCLV) {
2575 orSISIDXREG(SISPART4,0x0d,0x04);
2578 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2579 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2580 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2581 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2582 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2583 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2584 orSISIDXREG(SISCR,0x32,0x80);
2587 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2590 andSISIDXREG(SISCR, 0x32, ~0x03);
2592 if(!(ivideo->vbflags & TV_YPBPR)) {
2593 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2594 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2595 orSISIDXREG(SISCR, 0x32, 0x02);
2597 if((biosflag & 0x02) || (!result)) {
2598 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2599 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2600 orSISIDXREG(SISCR, 0x32, 0x01);
2605 SISDoSense(ivideo, 0, 0);
2607 outSISIDXREG(SISPART2,0x00,backupP2_00);
2608 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2609 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2611 if(ivideo->vbflags2 & VB2_30xCLV) {
2612 inSISIDXREG(SISPART2,0x00,biosflag);
2613 if(biosflag & 0x20) {
2614 for(myflag = 2; myflag > 0; myflag--) {
2616 outSISIDXREG(SISPART2,0x00,biosflag);
2621 outSISIDXREG(SISPART2,0x00,backupP2_00);
2624 /* Determine and detect attached TV's on Chrontel */
2625 static void __devinit
2626 SiS_SenseCh(struct sis_video_info *ivideo)
2628 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2630 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2632 #ifdef CONFIG_FB_SIS_300
2633 unsigned char test[3];
2637 if(ivideo->chip < SIS_315H) {
2639 #ifdef CONFIG_FB_SIS_300
2640 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2641 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2642 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2643 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2644 /* See Chrontel TB31 for explanation */
2645 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2646 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2647 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2648 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2650 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2651 if(temp2 != temp1) temp1 = temp2;
2653 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2654 /* Read power status */
2655 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2656 if((temp1 & 0x03) != 0x03) {
2657 /* Power all outputs */
2658 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2659 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2661 /* Sense connected TV devices */
2662 for(i = 0; i < 3; i++) {
2663 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2664 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2665 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2666 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2667 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2668 if(!(temp1 & 0x08)) test[i] = 0x02;
2669 else if(!(temp1 & 0x02)) test[i] = 0x01;
2671 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2674 if(test[0] == test[1]) temp1 = test[0];
2675 else if(test[0] == test[2]) temp1 = test[0];
2676 else if(test[1] == test[2]) temp1 = test[1];
2679 "sisfb: TV detection unreliable - test results varied\n");
2683 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2684 ivideo->vbflags |= TV_SVIDEO;
2685 orSISIDXREG(SISCR, 0x32, 0x02);
2686 andSISIDXREG(SISCR, 0x32, ~0x05);
2687 } else if (temp1 == 0x01) {
2688 printk(KERN_INFO "%s CVBS output\n", stdstr);
2689 ivideo->vbflags |= TV_AVIDEO;
2690 orSISIDXREG(SISCR, 0x32, 0x01);
2691 andSISIDXREG(SISCR, 0x32, ~0x06);
2693 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2694 andSISIDXREG(SISCR, 0x32, ~0x07);
2696 } else if(temp1 == 0) {
2697 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2698 andSISIDXREG(SISCR, 0x32, ~0x07);
2700 /* Set general purpose IO for Chrontel communication */
2701 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2706 #ifdef CONFIG_FB_SIS_315
2707 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2708 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2709 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2710 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2711 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2713 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2714 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2716 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2717 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2718 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2719 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2721 if(temp2 & 0x02) temp1 |= 0x01;
2722 if(temp2 & 0x10) temp1 |= 0x01;
2723 if(temp2 & 0x04) temp1 |= 0x02;
2724 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2727 printk(KERN_INFO "%s CVBS output\n", stdstr);
2728 ivideo->vbflags |= TV_AVIDEO;
2729 orSISIDXREG(SISCR, 0x32, 0x01);
2730 andSISIDXREG(SISCR, 0x32, ~0x06);
2733 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2734 ivideo->vbflags |= TV_SVIDEO;
2735 orSISIDXREG(SISCR, 0x32, 0x02);
2736 andSISIDXREG(SISCR, 0x32, ~0x05);
2739 printk(KERN_INFO "%s SCART output\n", stdstr);
2740 orSISIDXREG(SISCR, 0x32, 0x04);
2741 andSISIDXREG(SISCR, 0x32, ~0x03);
2744 andSISIDXREG(SISCR, 0x32, ~0x07);
2750 static void __devinit
2751 sisfb_get_VB_type(struct sis_video_info *ivideo)
2753 char stdstr[] = "sisfb: Detected";
2754 char bridgestr[] = "video bridge";
2758 /* No CRT2 on XGI Z7 */
2759 if(ivideo->chip == XGI_20)
2762 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2765 inSISIDXREG(SISPART4, 0x01, reg);
2767 ivideo->vbflags |= VB_301; /* Deprecated */
2768 ivideo->vbflags2 |= VB2_301;
2769 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2770 } else if(reg < 0xc0) {
2771 ivideo->vbflags |= VB_301B; /* Deprecated */
2772 ivideo->vbflags2 |= VB2_301B;
2773 inSISIDXREG(SISPART4,0x23,reg);
2775 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2776 ivideo->vbflags2 |= VB2_30xBDH;
2777 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2779 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2781 } else if(reg < 0xd0) {
2782 ivideo->vbflags |= VB_301C; /* Deprecated */
2783 ivideo->vbflags2 |= VB2_301C;
2784 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2785 } else if(reg < 0xe0) {
2786 ivideo->vbflags |= VB_301LV; /* Deprecated */
2787 ivideo->vbflags2 |= VB2_301LV;
2788 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2789 } else if(reg <= 0xe1) {
2790 inSISIDXREG(SISPART4,0x39,reg);
2792 ivideo->vbflags |= VB_302LV; /* Deprecated */
2793 ivideo->vbflags2 |= VB2_302LV;
2794 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2796 ivideo->vbflags |= VB_301C; /* Deprecated */
2797 ivideo->vbflags2 |= VB2_301C;
2798 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2800 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2801 ivideo->vbflags2 |= VB2_302ELV;
2802 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2808 ivideo->vbflags |= VB_302B; /* Deprecated */
2809 ivideo->vbflags2 |= VB2_302B;
2810 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2814 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2815 inSISIDXREG(SISCR, 0x37, reg);
2816 reg &= SIS_EXTERNAL_CHIP_MASK;
2818 if(ivideo->sisvga_engine == SIS_300_VGA) {
2819 #ifdef CONFIG_FB_SIS_300
2821 case SIS_EXTERNAL_CHIP_LVDS:
2822 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2823 ivideo->vbflags2 |= VB2_LVDS;
2825 case SIS_EXTERNAL_CHIP_TRUMPION:
2826 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2827 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2829 case SIS_EXTERNAL_CHIP_CHRONTEL:
2830 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2831 ivideo->vbflags2 |= VB2_CHRONTEL;
2833 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2834 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2835 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2838 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2840 } else if(ivideo->chip < SIS_661) {
2841 #ifdef CONFIG_FB_SIS_315
2843 case SIS310_EXTERNAL_CHIP_LVDS:
2844 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2845 ivideo->vbflags2 |= VB2_LVDS;
2847 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2848 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2849 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2852 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2854 } else if(ivideo->chip >= SIS_661) {
2855 #ifdef CONFIG_FB_SIS_315
2856 inSISIDXREG(SISCR, 0x38, reg);
2860 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2861 ivideo->vbflags2 |= VB2_LVDS;
2864 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2865 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2868 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2869 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2872 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2875 if(ivideo->vbflags2 & VB2_LVDS) {
2876 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2878 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2879 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2881 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2882 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2884 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2885 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2889 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2890 SiS_SenseLCD(ivideo);
2891 SiS_Sense30x(ivideo);
2892 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2893 SiS_SenseCh(ivideo);
2897 /* ---------- Engine initialization routines ------------ */
2900 sisfb_engine_init(struct sis_video_info *ivideo)
2903 /* Initialize command queue (we use MMIO only) */
2905 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2907 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2908 MMIO_CMD_QUEUE_CAP |
2912 #ifdef CONFIG_FB_SIS_300
2913 if(ivideo->sisvga_engine == SIS_300_VGA) {
2917 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2919 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2922 tq_state |= (u8)(tqueue_pos >> 8);
2923 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2925 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2927 ivideo->caps |= TURBO_QUEUE_CAP;
2931 #ifdef CONFIG_FB_SIS_315
2932 if(ivideo->sisvga_engine == SIS_315_VGA) {
2933 u32 tempq = 0, templ;
2936 if(ivideo->chip == XGI_20) {
2937 switch(ivideo->cmdQueueSize) {
2939 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2943 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2946 switch(ivideo->cmdQueueSize) {
2947 case (4 * 1024 * 1024):
2948 temp = SIS_CMD_QUEUE_SIZE_4M;
2950 case (2 * 1024 * 1024):
2951 temp = SIS_CMD_QUEUE_SIZE_2M;
2953 case (1 * 1024 * 1024):
2954 temp = SIS_CMD_QUEUE_SIZE_1M;
2958 temp = SIS_CMD_QUEUE_SIZE_512k;
2962 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2963 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2965 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2966 /* Must disable dual pipe on XGI_40. Can't do
2967 * this in MMIO mode, because it requires
2968 * setting/clearing a bit in the MMIO fire trigger
2971 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2973 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2975 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2977 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2978 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2980 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2981 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2983 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2984 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2985 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2986 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2988 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2990 sisfb_syncaccel(ivideo);
2992 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2997 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2998 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3000 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3001 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3003 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3004 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3006 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3010 ivideo->engineok = 1;
3013 static void __devinit
3014 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3019 inSISIDXREG(SISCR, 0x36, reg);
3021 if(ivideo->sisvga_engine == SIS_300_VGA) {
3022 ivideo->CRT2LCDType = sis300paneltype[reg];
3023 } else if(ivideo->chip >= SIS_661) {
3024 ivideo->CRT2LCDType = sis661paneltype[reg];
3026 ivideo->CRT2LCDType = sis310paneltype[reg];
3027 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3028 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3029 (ivideo->CRT2LCDType != LCD_320x240_3)) {
3030 ivideo->CRT2LCDType = LCD_320x240;
3035 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3036 /* For broken BIOSes: Assume 1024x768, RGB18 */
3037 ivideo->CRT2LCDType = LCD_1024x768;
3038 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3039 setSISIDXREG(SISCR,0x37,0xee,0x01);
3040 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3043 for(i = 0; i < SIS_LCD_NUMBER; i++) {
3044 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3045 ivideo->lcdxres = sis_lcd_data[i].xres;
3046 ivideo->lcdyres = sis_lcd_data[i].yres;
3047 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3052 #ifdef CONFIG_FB_SIS_300
3053 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3054 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3055 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3056 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3057 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
3058 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3059 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3060 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
3061 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3065 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3066 ivideo->lcdxres, ivideo->lcdyres);
3069 static void __devinit
3070 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3072 #ifdef CONFIG_FB_SIS_300
3073 /* Save the current PanelDelayCompensation if the LCD is currently used */
3074 if(ivideo->sisvga_engine == SIS_300_VGA) {
3075 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3077 inSISIDXREG(SISCR,0x30,tmp);
3079 /* Currently on LCD? If yes, read current pdc */
3080 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3081 ivideo->detectedpdc &= 0x3c;
3082 if(ivideo->SiS_Pr.PDC == -1) {
3083 /* Let option override detection */
3084 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3086 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3087 ivideo->detectedpdc);
3089 if((ivideo->SiS_Pr.PDC != -1) &&
3090 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3091 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3092 ivideo->SiS_Pr.PDC);
3098 #ifdef CONFIG_FB_SIS_315
3099 if(ivideo->sisvga_engine == SIS_315_VGA) {
3101 /* Try to find about LCDA */
3102 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3104 inSISIDXREG(SISPART1,0x13,tmp);
3106 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3107 ivideo->detectedlcda = 0x03;
3112 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3114 inSISIDXREG(SISCR,0x30,tmp);
3115 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3116 /* Currently on LCD? If yes, read current pdc */
3118 inSISIDXREG(SISPART1,0x2D,pdc);
3119 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3120 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3121 inSISIDXREG(SISPART1,0x35,pdc);
3122 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3123 inSISIDXREG(SISPART1,0x20,pdc);
3124 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3125 if(ivideo->newrom) {
3126 /* New ROM invalidates other PDC resp. */
3127 if(ivideo->detectedlcda != 0xff) {
3128 ivideo->detectedpdc = 0xff;
3130 ivideo->detectedpdca = 0xff;
3133 if(ivideo->SiS_Pr.PDC == -1) {
3134 if(ivideo->detectedpdc != 0xff) {
3135 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3138 if(ivideo->SiS_Pr.PDCA == -1) {
3139 if(ivideo->detectedpdca != 0xff) {
3140 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3143 if(ivideo->detectedpdc != 0xff) {
3145 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3146 ivideo->detectedpdc);
3148 if(ivideo->detectedpdca != 0xff) {
3150 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3151 ivideo->detectedpdca);
3156 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3157 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3158 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3159 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3160 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3161 ivideo->SiS_Pr.HaveEMI = TRUE;
3162 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3163 ivideo->SiS_Pr.HaveEMILCD = TRUE;
3168 /* Let user override detected PDCs (all bridges) */
3169 if(ivideo->vbflags2 & VB2_30xBLV) {
3170 if((ivideo->SiS_Pr.PDC != -1) &&
3171 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3172 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3173 ivideo->SiS_Pr.PDC);
3175 if((ivideo->SiS_Pr.PDCA != -1) &&
3176 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3177 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3178 ivideo->SiS_Pr.PDCA);
3186 /* -------------------- Memory manager routines ---------------------- */
3188 static u32 __devinit
3189 sisfb_getheapstart(struct sis_video_info *ivideo)
3191 u32 ret = ivideo->sisfb_parm_mem * 1024;
3192 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3195 /* Calculate heap start = end of memory for console
3197 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3198 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3200 * On 76x in UMA+LFB mode, the layout is as follows:
3201 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3202 * where the heap is the entire UMA area, eventually
3203 * into the LFB area if the given mem parameter is
3204 * higher than the size of the UMA memory.
3206 * Basically given by "mem" parameter
3208 * maximum = videosize - cmd_queue - hwcursor
3209 * (results in a heap of size 0)
3210 * default = SiS 300: depends on videosize
3211 * SiS 315/330/340/XGI: 32k below max
3214 if(ivideo->sisvga_engine == SIS_300_VGA) {
3215 if(ivideo->video_size > 0x1000000) {
3217 } else if(ivideo->video_size > 0x800000) {
3222 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3225 def = maxoffs - 0x8000;
3228 /* Use default for secondary card for now (FIXME) */
3229 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3235 static u32 __devinit
3236 sisfb_getheapsize(struct sis_video_info *ivideo)
3238 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3241 if(ivideo->UMAsize && ivideo->LFBsize) {
3242 if( (!ivideo->sisfb_parm_mem) ||
3243 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3244 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3245 ret = ivideo->UMAsize;
3246 max -= ivideo->UMAsize;
3248 ret = max - (ivideo->sisfb_parm_mem * 1024);
3249 max = ivideo->sisfb_parm_mem * 1024;
3251 ivideo->video_offset = ret;
3252 ivideo->sisfb_mem = max;
3254 ret = max - ivideo->heapstart;
3255 ivideo->sisfb_mem = ivideo->heapstart;
3261 static int __devinit
3262 sisfb_heap_init(struct sis_video_info *ivideo)
3266 ivideo->video_offset = 0;
3267 if(ivideo->sisfb_parm_mem) {
3268 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3269 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3270 ivideo->sisfb_parm_mem = 0;
3274 ivideo->heapstart = sisfb_getheapstart(ivideo);
3275 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3277 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3278 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3280 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3281 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3283 ivideo->sisfb_heap.vinfo = ivideo;
3285 ivideo->sisfb_heap.poha_chain = NULL;
3286 ivideo->sisfb_heap.poh_freelist = NULL;
3288 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3292 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3293 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3294 poh->size = ivideo->sisfb_heap_size;
3295 poh->offset = ivideo->heapstart;
3297 ivideo->sisfb_heap.oh_free.poh_next = poh;
3298 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3299 ivideo->sisfb_heap.oh_free.size = 0;
3300 ivideo->sisfb_heap.max_freesize = poh->size;
3302 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3303 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3304 ivideo->sisfb_heap.oh_used.size = SENTINEL;
3306 if(ivideo->cardnumber == 0) {
3307 /* For the first card, make this heap the "global" one
3308 * for old DRM (which could handle only one card)
3310 sisfb_heap = &ivideo->sisfb_heap;
3316 static struct SIS_OH *
3317 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3319 struct SIS_OHALLOC *poha;
3324 if(memheap->poh_freelist == NULL) {
3325 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3329 poha->poha_next = memheap->poha_chain;
3330 memheap->poha_chain = poha;
3332 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3334 poh = &poha->aoh[0];
3335 for(i = cOhs - 1; i != 0; i--) {
3336 poh->poh_next = poh + 1;
3340 poh->poh_next = NULL;
3341 memheap->poh_freelist = &poha->aoh[0];
3344 poh = memheap->poh_freelist;
3345 memheap->poh_freelist = poh->poh_next;
3350 static struct SIS_OH *
3351 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3353 struct SIS_OH *pohThis;
3354 struct SIS_OH *pohRoot;
3357 if(size > memheap->max_freesize) {
3358 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3359 (unsigned int) size / 1024);
3363 pohThis = memheap->oh_free.poh_next;
3365 while(pohThis != &memheap->oh_free) {
3366 if(size <= pohThis->size) {
3370 pohThis = pohThis->poh_next;
3374 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3375 (unsigned int) size / 1024);
3379 if(size == pohThis->size) {
3381 sisfb_delete_node(pohThis);
3383 pohRoot = sisfb_poh_new_node(memheap);
3387 pohRoot->offset = pohThis->offset;
3388 pohRoot->size = size;
3390 pohThis->offset += size;
3391 pohThis->size -= size;
3394 memheap->max_freesize -= size;
3396 pohThis = &memheap->oh_used;
3397 sisfb_insert_node(pohThis, pohRoot);
3403 sisfb_delete_node(struct SIS_OH *poh)
3405 poh->poh_prev->poh_next = poh->poh_next;
3406 poh->poh_next->poh_prev = poh->poh_prev;
3410 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3412 struct SIS_OH *pohTemp = pohList->poh_next;
3414 pohList->poh_next = poh;
3415 pohTemp->poh_prev = poh;
3417 poh->poh_prev = pohList;
3418 poh->poh_next = pohTemp;
3421 static struct SIS_OH *
3422 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3424 struct SIS_OH *pohThis;
3425 struct SIS_OH *poh_freed;
3426 struct SIS_OH *poh_prev;
3427 struct SIS_OH *poh_next;
3432 poh_freed = memheap->oh_used.poh_next;
3434 while(poh_freed != &memheap->oh_used) {
3435 if(poh_freed->offset == base) {
3440 poh_freed = poh_freed->poh_next;
3446 memheap->max_freesize += poh_freed->size;
3448 poh_prev = poh_next = NULL;
3449 ulUpper = poh_freed->offset + poh_freed->size;
3450 ulLower = poh_freed->offset;
3452 pohThis = memheap->oh_free.poh_next;
3454 while(pohThis != &memheap->oh_free) {
3455 if(pohThis->offset == ulUpper) {
3457 } else if((pohThis->offset + pohThis->size) == ulLower) {
3460 pohThis = pohThis->poh_next;
3463 sisfb_delete_node(poh_freed);
3465 if(poh_prev && poh_next) {
3466 poh_prev->size += (poh_freed->size + poh_next->size);
3467 sisfb_delete_node(poh_next);
3468 sisfb_free_node(memheap, poh_freed);
3469 sisfb_free_node(memheap, poh_next);
3474 poh_prev->size += poh_freed->size;
3475 sisfb_free_node(memheap, poh_freed);
3480 poh_next->size += poh_freed->size;
3481 poh_next->offset = poh_freed->offset;
3482 sisfb_free_node(memheap, poh_freed);
3486 sisfb_insert_node(&memheap->oh_free, poh_freed);
3492 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3497 poh->poh_next = memheap->poh_freelist;
3498 memheap->poh_freelist = poh;
3502 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3504 struct SIS_OH *poh = NULL;
3506 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3507 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3510 req->offset = req->size = 0;
3511 DPRINTK("sisfb: Video RAM allocation failed\n");
3513 req->offset = poh->offset;
3514 req->size = poh->size;
3515 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3516 (poh->offset + ivideo->video_vbase));
3521 sis_malloc(struct sis_memreq *req)
3523 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3525 if(&ivideo->sisfb_heap == sisfb_heap)
3526 sis_int_malloc(ivideo, req);
3528 req->offset = req->size = 0;
3532 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3534 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3536 sis_int_malloc(ivideo, req);
3539 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3542 sis_int_free(struct sis_video_info *ivideo, u32 base)
3546 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3549 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3552 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3553 (unsigned int) base);
3560 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3562 sis_int_free(ivideo, base);
3566 sis_free_new(struct pci_dev *pdev, u32 base)
3568 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3570 sis_int_free(ivideo, base);
3573 /* --------------------- SetMode routines ------------------------- */
3576 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3580 /* Check if MMIO and engines are enabled,
3581 * and sync in case they are. Can't use
3582 * ivideo->accel here, as this might have
3583 * been changed before this is called.
3585 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3586 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3587 /* MMIO and 2D/3D engine enabled? */
3588 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3589 #ifdef CONFIG_FB_SIS_300
3590 if(ivideo->sisvga_engine == SIS_300_VGA) {
3591 /* Don't care about TurboQueue. It's
3592 * enough to know that the engines
3595 sisfb_syncaccel(ivideo);
3598 #ifdef CONFIG_FB_SIS_315
3599 if(ivideo->sisvga_engine == SIS_315_VGA) {
3600 /* Check that any queue mode is
3601 * enabled, and that the queue
3602 * is not in the state of "reset"
3604 inSISIDXREG(SISSR, 0x26, cr30);
3605 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3606 sisfb_syncaccel(ivideo);
3614 sisfb_pre_setmode(struct sis_video_info *ivideo)
3616 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3619 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3621 outSISIDXREG(SISSR, 0x05, 0x86);
3623 inSISIDXREG(SISCR, 0x31, cr31);
3627 cr33 = ivideo->rate_idx & 0x0F;
3629 #ifdef CONFIG_FB_SIS_315
3630 if(ivideo->sisvga_engine == SIS_315_VGA) {
3631 if(ivideo->chip >= SIS_661) {
3632 inSISIDXREG(SISCR, 0x38, cr38);
3633 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3636 inSISIDXREG(SISCR, tvregnum, cr38);
3637 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3641 #ifdef CONFIG_FB_SIS_300
3642 if(ivideo->sisvga_engine == SIS_300_VGA) {
3644 inSISIDXREG(SISCR, tvregnum, cr38);
3648 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3649 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3650 ivideo->curFSTN = ivideo->curDSTN = 0;
3652 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3655 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3656 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3657 #ifdef CONFIG_FB_SIS_315
3658 if(ivideo->chip >= SIS_661) {
3660 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3661 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3662 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3663 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3665 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3666 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3667 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3669 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3670 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3671 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3673 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3676 } else if((ivideo->vbflags & TV_HIVISION) &&
3677 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3678 if(ivideo->chip >= SIS_661) {
3684 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3687 ivideo->currentvbflags |= TV_HIVISION;
3688 } else if(ivideo->vbflags & TV_SCART) {
3689 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3692 ivideo->currentvbflags |= TV_SCART;
3694 if(ivideo->vbflags & TV_SVIDEO) {
3695 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3696 ivideo->currentvbflags |= TV_SVIDEO;
3698 if(ivideo->vbflags & TV_AVIDEO) {
3699 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3700 ivideo->currentvbflags |= TV_AVIDEO;
3703 cr31 |= SIS_DRIVER_MODE;
3705 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3706 if(ivideo->vbflags & TV_PAL) {
3707 cr31 |= 0x01; cr35 |= 0x01;
3708 ivideo->currentvbflags |= TV_PAL;
3709 if(ivideo->vbflags & TV_PALM) {
3710 cr38 |= 0x40; cr35 |= 0x04;
3711 ivideo->currentvbflags |= TV_PALM;
3712 } else if(ivideo->vbflags & TV_PALN) {
3713 cr38 |= 0x80; cr35 |= 0x08;
3714 ivideo->currentvbflags |= TV_PALN;
3717 cr31 &= ~0x01; cr35 &= ~0x01;
3718 ivideo->currentvbflags |= TV_NTSC;
3719 if(ivideo->vbflags & TV_NTSCJ) {
3720 cr38 |= 0x40; cr35 |= 0x02;
3721 ivideo->currentvbflags |= TV_NTSCJ;
3728 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3729 cr31 |= SIS_DRIVER_MODE;
3730 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3731 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3732 ivideo->curFSTN = ivideo->sisfb_fstn;
3733 ivideo->curDSTN = ivideo->sisfb_dstn;
3737 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3738 cr31 |= SIS_DRIVER_MODE;
3739 if(ivideo->sisfb_nocrt2rate) {
3740 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3742 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3746 default: /* disable CRT2 */
3748 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3751 outSISIDXREG(SISCR, 0x30, cr30);
3752 outSISIDXREG(SISCR, 0x33, cr33);
3754 if(ivideo->chip >= SIS_661) {
3755 #ifdef CONFIG_FB_SIS_315
3756 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3757 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3758 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3759 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3761 } else if(ivideo->chip != SIS_300) {
3762 outSISIDXREG(SISCR, tvregnum, cr38);
3764 outSISIDXREG(SISCR, 0x31, cr31);
3766 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3768 sisfb_check_engine_and_sync(ivideo);
3771 /* Fix SR11 for 661 and later */
3772 #ifdef CONFIG_FB_SIS_315
3774 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3778 if(ivideo->chip >= SIS_661) {
3779 inSISIDXREG(SISSR,0x11,tmpreg);
3781 inSISIDXREG(SISSR,0x3e,tmpreg);
3782 tmpreg = (tmpreg + 1) & 0xff;
3783 outSISIDXREG(SISSR,0x3e,tmpreg);
3784 inSISIDXREG(SISSR,0x11,tmpreg);
3787 andSISIDXREG(SISSR,0x11,0x0f);
3794 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3796 if(val > 32) val = 32;
3797 if(val < -32) val = -32;
3798 ivideo->tvxpos = val;
3800 if(ivideo->sisfblocked) return;
3801 if(!ivideo->modechanged) return;
3803 if(ivideo->currentvbflags & CRT2_TV) {
3805 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3807 int x = ivideo->tvx;
3809 switch(ivideo->chronteltype) {
3813 outSISIDXREG(SISSR,0x05,0x86);
3814 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3815 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3818 /* Not supported by hardware */
3822 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3824 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3825 unsigned short temp;
3827 p2_1f = ivideo->p2_1f;
3828 p2_20 = ivideo->p2_20;
3829 p2_2b = ivideo->p2_2b;
3830 p2_42 = ivideo->p2_42;
3831 p2_43 = ivideo->p2_43;
3833 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3835 p2_1f = temp & 0xff;
3836 p2_20 = (temp & 0xf00) >> 4;
3837 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3838 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3840 p2_43 = temp & 0xff;
3841 p2_42 = (temp & 0xf00) >> 4;
3842 outSISIDXREG(SISPART2,0x1f,p2_1f);
3843 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3844 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3845 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3846 outSISIDXREG(SISPART2,0x43,p2_43);
3852 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3854 if(val > 32) val = 32;
3855 if(val < -32) val = -32;
3856 ivideo->tvypos = val;
3858 if(ivideo->sisfblocked) return;
3859 if(!ivideo->modechanged) return;
3861 if(ivideo->currentvbflags & CRT2_TV) {
3863 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3865 int y = ivideo->tvy;
3867 switch(ivideo->chronteltype) {
3871 outSISIDXREG(SISSR,0x05,0x86);
3872 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3873 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3876 /* Not supported by hardware */
3880 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3884 p2_01 = ivideo->p2_01;
3885 p2_02 = ivideo->p2_02;
3889 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3890 while((p2_01 <= 0) || (p2_02 <= 0)) {
3895 outSISIDXREG(SISPART2,0x01,p2_01);
3896 outSISIDXREG(SISPART2,0x02,p2_02);
3902 sisfb_post_setmode(struct sis_video_info *ivideo)
3904 BOOLEAN crt1isoff = FALSE;
3905 BOOLEAN doit = TRUE;
3906 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3909 #ifdef CONFIG_FB_SIS_315
3913 outSISIDXREG(SISSR, 0x05, 0x86);
3915 #ifdef CONFIG_FB_SIS_315
3916 sisfb_fixup_SR11(ivideo);
3919 /* Now we actually HAVE changed the display mode */
3920 ivideo->modechanged = 1;
3922 /* We can't switch off CRT1 if bridge is in slave mode */
3923 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3924 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3926 ivideo->sisfb_crt1off = 0;
3928 #ifdef CONFIG_FB_SIS_300
3929 if(ivideo->sisvga_engine == SIS_300_VGA) {
3930 if((ivideo->sisfb_crt1off) && (doit)) {
3937 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3940 #ifdef CONFIG_FB_SIS_315
3941 if(ivideo->sisvga_engine == SIS_315_VGA) {
3942 if((ivideo->sisfb_crt1off) && (doit)) {
3951 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3952 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3957 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3958 ivideo->currentvbflags |= VB_SINGLE_MODE;
3960 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3961 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3962 ivideo->currentvbflags |= VB_MIRROR_MODE;
3964 ivideo->currentvbflags |= VB_SINGLE_MODE;
3968 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3970 if(ivideo->currentvbflags & CRT2_TV) {
3971 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3972 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3973 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3974 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3975 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3976 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3977 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3978 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3979 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3980 if(ivideo->chronteltype == 1) {
3981 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3982 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3983 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3984 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3989 if(ivideo->tvxpos) {
3990 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3992 if(ivideo->tvypos) {
3993 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3996 /* Eventually sync engines */
3997 sisfb_check_engine_and_sync(ivideo);
3999 /* (Re-)Initialize chip engines */
4001 sisfb_engine_init(ivideo);
4003 ivideo->engineok = 0;
4008 sisfb_reset_mode(struct sis_video_info *ivideo)
4010 if(sisfb_set_mode(ivideo, 0))
4013 sisfb_set_pitch(ivideo);
4014 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4015 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
4021 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4025 switch(sisfb_command->sisfb_cmd) {
4026 case SISFB_CMD_GETVBFLAGS:
4027 if(!ivideo->modechanged) {
4028 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4030 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4031 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4032 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
4035 case SISFB_CMD_SWITCHCRT1:
4036 /* arg[0]: 0 = off, 1 = on, 99 = query */
4037 if(!ivideo->modechanged) {
4038 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4039 } else if(sisfb_command->sisfb_arg[0] == 99) {
4041 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4042 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4043 } else if(ivideo->sisfblocked) {
4044 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4045 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4046 (sisfb_command->sisfb_arg[0] == 0)) {
4047 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4049 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4050 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4051 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4052 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4053 ivideo->sisfb_crt1off = mycrt1off;
4054 if(sisfb_reset_mode(ivideo)) {
4055 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
4058 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4063 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4064 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4065 sisfb_command->sisfb_cmd);
4070 SISINITSTATIC int __init
4071 sisfb_setup(char *options)
4075 sisfb_setdefaultparms();
4077 if(!options || !(*options))
4080 while((this_opt = strsep(&options, ",")) != NULL) {
4082 if(!(*this_opt)) continue;
4084 if(!strnicmp(this_opt, "off", 3)) {
4086 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4087 /* Need to check crt2 type first for fstn/dstn */
4088 sisfb_search_crt2type(this_opt + 14);
4089 } else if(!strnicmp(this_opt, "tvmode:",7)) {
4090 sisfb_search_tvstd(this_opt + 7);
4091 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4092 sisfb_search_tvstd(this_opt + 11);
4093 } else if(!strnicmp(this_opt, "mode:", 5)) {
4094 sisfb_search_mode(this_opt + 5, FALSE);
4095 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4096 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4097 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4098 } else if(!strnicmp(this_opt, "inverse", 7)) {
4100 /* fb_invert_cmaps(); */
4101 } else if(!strnicmp(this_opt, "font:", 5)) {
4102 if(strlen(this_opt + 5) < 40) {
4103 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4104 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4107 } else if(!strnicmp(this_opt, "rate:", 5)) {
4108 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4109 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4110 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4111 } else if(!strnicmp(this_opt, "mem:",4)) {
4112 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4113 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4114 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4115 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4116 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4117 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4119 } else if(!strnicmp(this_opt, "accel", 5)) {
4121 } else if(!strnicmp(this_opt, "noypan", 6)) {
4123 } else if(!strnicmp(this_opt, "ypan", 4)) {
4125 } else if(!strnicmp(this_opt, "nomax", 5)) {
4127 } else if(!strnicmp(this_opt, "max", 3)) {
4129 } else if(!strnicmp(this_opt, "userom:", 7)) {
4130 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4131 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4132 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4133 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4134 sisfb_nocrt2rate = 1;
4135 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4136 unsigned long temp = 2;
4137 temp = simple_strtoul(this_opt + 9, NULL, 0);
4138 if((temp == 0) || (temp == 1)) {
4139 sisfb_scalelcd = temp ^ 1;
4141 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4143 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4144 if((temp >= -32) && (temp <= 32)) {
4145 sisfb_tvxposoffset = temp;
4147 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4149 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4150 if((temp >= -32) && (temp <= 32)) {
4151 sisfb_tvyposoffset = temp;
4153 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4154 sisfb_search_specialtiming(this_opt + 14);
4155 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4157 temp = simple_strtoul(this_opt + 7, NULL, 0);
4158 if((temp >= 0) && (temp <= 3)) {
4159 sisfb_lvdshl = temp;
4161 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4162 sisfb_search_mode(this_opt, TRUE);
4163 #if !defined(__i386__) && !defined(__x86_64__)
4164 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4165 sisfb_resetcard = 1;
4166 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4167 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4170 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4179 static int __devinit
4180 sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4185 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4188 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4189 if(romptr > (0x10000 - 8))
4192 rom = rom_base + romptr;
4194 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4195 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4198 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4201 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4207 static unsigned char * __devinit
4208 sisfb_find_rom(struct pci_dev *pdev)
4210 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4211 SIS_IOTYPE1 *rom_base;
4212 unsigned char *myrombase = NULL;
4214 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4217 /* First, try the official pci ROM functions (except
4218 * on integrated chipsets which have no ROM).
4221 if(!ivideo->nbridge) {
4223 if((rom_base = pci_map_rom(pdev, &romsize))) {
4225 if(sisfb_check_rom(rom_base, ivideo)) {
4227 if((myrombase = vmalloc(65536))) {
4229 /* Work around bug in pci/rom.c: Folks forgot to check
4230 * whether the size retrieved from the BIOS image eventually
4231 * is larger than the mapped size
4233 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4234 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4236 memcpy_fromio(myrombase, rom_base,
4237 (romsize > 65536) ? 65536 : romsize);
4240 pci_unmap_rom(pdev, rom_base);
4244 if(myrombase) return myrombase;
4247 /* Otherwise do it the conventional way. */
4249 #if defined(__i386__) || defined(__x86_64__)
4251 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4253 rom_base = ioremap(temp, 65536);
4257 if(!sisfb_check_rom(rom_base, ivideo)) {
4262 if((myrombase = vmalloc(65536)))
4263 memcpy_fromio(myrombase, rom_base, 65536);
4272 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4273 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4274 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4276 rom_base = ioremap(ivideo->video_base, 65536);
4278 if(sisfb_check_rom(rom_base, ivideo)) {
4279 if((myrombase = vmalloc(65536)))
4280 memcpy_fromio(myrombase, rom_base, 65536);
4285 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4292 static void __devinit
4293 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4296 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4298 if(!ivideo->video_vbase) {
4300 "sisfb: Unable to map maximum video RAM for size detection\n");
4302 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4304 if((*mapsize) < (min << 20))
4307 if(ivideo->video_vbase) {
4309 "sisfb: Video RAM size detection limited to %dMB\n",
4310 (int)((*mapsize) >> 20));
4315 #ifdef CONFIG_FB_SIS_300
4316 static int __devinit
4317 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4319 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4320 unsigned short temp;
4324 andSISIDXREG(SISSR, 0x15, 0xFB);
4325 orSISIDXREG(SISSR, 0x15, 0x04);
4326 outSISIDXREG(SISSR, 0x13, 0x00);
4327 outSISIDXREG(SISSR, 0x14, 0xBF);
4329 for(i = 0; i < 2; i++) {
4331 for(j = 0; j < 4; j++) {
4332 writew(temp, FBAddress);
4333 if(readw(FBAddress) == temp)
4335 orSISIDXREG(SISSR, 0x3c, 0x01);
4336 inSISIDXREG(SISSR, 0x05, reg);
4337 inSISIDXREG(SISSR, 0x05, reg);
4338 andSISIDXREG(SISSR, 0x3c, 0xfe);
4339 inSISIDXREG(SISSR, 0x05, reg);
4340 inSISIDXREG(SISSR, 0x05, reg);
4345 writel(0x01234567L, FBAddress);
4346 writel(0x456789ABL, (FBAddress + 4));
4347 writel(0x89ABCDEFL, (FBAddress + 8));
4348 writel(0xCDEF0123L, (FBAddress + 12));
4350 inSISIDXREG(SISSR, 0x3b, reg);
4352 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4353 return 4; /* Channel A 128bit */
4356 if(readl((FBAddress + 4)) == 0x456789ABL)
4357 return 2; /* Channel B 64bit */
4359 return 1; /* 32bit */
4362 static int __devinit
4363 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4364 int PseudoRankCapacity, int PseudoAdrPinCount,
4365 unsigned int mapsize)
4367 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4368 unsigned short sr14;
4369 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4370 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4371 static const unsigned short SiS_DRAMType[17][5] = {
4372 {0x0C,0x0A,0x02,0x40,0x39},
4373 {0x0D,0x0A,0x01,0x40,0x48},
4374 {0x0C,0x09,0x02,0x20,0x35},
4375 {0x0D,0x09,0x01,0x20,0x44},
4376 {0x0C,0x08,0x02,0x10,0x31},
4377 {0x0D,0x08,0x01,0x10,0x40},
4378 {0x0C,0x0A,0x01,0x20,0x34},
4379 {0x0C,0x09,0x01,0x08,0x32},
4380 {0x0B,0x08,0x02,0x08,0x21},
4381 {0x0C,0x08,0x01,0x08,0x30},
4382 {0x0A,0x08,0x02,0x04,0x11},
4383 {0x0B,0x0A,0x01,0x10,0x28},
4384 {0x09,0x08,0x02,0x02,0x01},
4385 {0x0B,0x09,0x01,0x08,0x24},
4386 {0x0B,0x08,0x01,0x04,0x20},
4387 {0x0A,0x08,0x01,0x02,0x10},
4388 {0x09,0x08,0x01,0x01,0x00}
4391 for(k = 0; k <= 16; k++) {
4393 RankCapacity = buswidth * SiS_DRAMType[k][3];
4395 if(RankCapacity != PseudoRankCapacity)
4398 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4401 BankNumHigh = RankCapacity * 16 * iteration - 1;
4402 if(iteration == 3) { /* Rank No */
4403 BankNumMid = RankCapacity * 16 - 1;
4405 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4408 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4409 PhysicalAdrHigh = BankNumHigh;
4410 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4411 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4413 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4414 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4415 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4416 if(buswidth == 4) sr14 |= 0x80;
4417 else if(buswidth == 2) sr14 |= 0x40;
4418 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4419 outSISIDXREG(SISSR, 0x14, sr14);
4424 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4425 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4426 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4427 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4431 writew(((unsigned short)PhysicalAdrHigh),
4432 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4433 writew(((unsigned short)BankNumMid),
4434 (FBAddr + BankNumMid + PhysicalAdrHigh));
4435 writew(((unsigned short)PhysicalAdrHalfPage),
4436 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4437 writew(((unsigned short)PhysicalAdrOtherPage),
4438 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4441 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4448 static void __devinit
4449 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4451 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4453 int PseudoRankCapacity, PseudoAdrPinCount;
4455 buswidth = sisfb_post_300_buswidth(ivideo);
4457 for(i = 6; i >= 0; i--) {
4458 PseudoRankCapacity = 1 << i;
4459 for(j = 4; j >= 1; j--) {
4460 PseudoAdrPinCount = 15 - j;
4461 if((PseudoRankCapacity * j) <= 64) {
4462 if(sisfb_post_300_rwtest(ivideo,
4474 static void __devinit
4475 sisfb_post_sis300(struct pci_dev *pdev)
4477 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4478 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4479 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4480 u16 index, rindex, memtype = 0;
4481 unsigned int mapsize;
4483 if(!ivideo->SiS_Pr.UseROM)
4486 outSISIDXREG(SISSR, 0x05, 0x86);
4489 if(bios[0x52] & 0x80) {
4490 memtype = bios[0x52];
4492 inSISIDXREG(SISSR, 0x3a, memtype);
4497 v3 = 0x80; v6 = 0x80;
4498 if(ivideo->revision_id <= 0x13) {
4499 v1 = 0x44; v2 = 0x42;
4500 v4 = 0x44; v5 = 0x42;
4502 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4503 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4505 index = memtype * 5;
4506 rindex = index + 0x54;
4507 v1 = bios[rindex++];
4508 v2 = bios[rindex++];
4509 v3 = bios[rindex++];
4510 rindex = index + 0x7c;
4511 v4 = bios[rindex++];
4512 v5 = bios[rindex++];
4513 v6 = bios[rindex++];
4516 outSISIDXREG(SISSR, 0x28, v1);
4517 outSISIDXREG(SISSR, 0x29, v2);
4518 outSISIDXREG(SISSR, 0x2a, v3);
4519 outSISIDXREG(SISSR, 0x2e, v4);
4520 outSISIDXREG(SISSR, 0x2f, v5);
4521 outSISIDXREG(SISSR, 0x30, v6);
4526 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4528 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4530 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4531 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4535 v2 = bios[memtype + 8];
4536 v3 = bios[memtype + 16];
4537 v4 = bios[memtype + 24];
4538 v5 = bios[memtype + 32];
4539 v6 = bios[memtype + 40];
4540 v7 = bios[memtype + 48];
4541 v8 = bios[memtype + 56];
4543 if(ivideo->revision_id >= 0x80)
4545 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4546 outSISIDXREG(SISSR, 0x16, v2);
4547 outSISIDXREG(SISSR, 0x17, v3);
4548 outSISIDXREG(SISSR, 0x18, v4);
4549 outSISIDXREG(SISSR, 0x19, v5);
4550 outSISIDXREG(SISSR, 0x1a, v6);
4551 outSISIDXREG(SISSR, 0x1b, v7);
4552 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4553 andSISIDXREG(SISSR, 0x15 ,0xfb);
4554 orSISIDXREG(SISSR, 0x15, 0x04);
4556 if(bios[0x53] & 0x02) {
4557 orSISIDXREG(SISSR, 0x19, 0x20);
4560 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4561 if(ivideo->revision_id >= 0x80)
4563 outSISIDXREG(SISSR, 0x1f, v1);
4564 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4565 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4571 outSISIDXREG(SISSR, 0x23, v1);
4572 outSISIDXREG(SISSR, 0x24, v2);
4573 outSISIDXREG(SISSR, 0x25, v3);
4574 outSISIDXREG(SISSR, 0x21, 0x84);
4575 outSISIDXREG(SISSR, 0x22, 0x00);
4576 outSISIDXREG(SISCR, 0x37, 0x00);
4577 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4578 outSISIDXREG(SISPART1, 0x00, 0x00);
4579 v1 = 0x40; v2 = 0x11;
4584 outSISIDXREG(SISPART1, 0x02, v1);
4586 if(ivideo->revision_id >= 0x80)
4589 inSISIDXREG(SISPART4, 0x00, reg);
4590 if((reg == 1) || (reg == 2)) {
4591 outSISIDXREG(SISCR, 0x37, 0x02);
4592 outSISIDXREG(SISPART2, 0x00, 0x1c);
4593 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4594 if(ivideo->SiS_Pr.UseROM) {
4599 outSISIDXREG(SISPART4, 0x0d, v4);
4600 outSISIDXREG(SISPART4, 0x0e, v5);
4601 outSISIDXREG(SISPART4, 0x10, v6);
4602 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4603 inSISIDXREG(SISPART4, 0x01, reg);
4605 inSISIDXREG(SISPART4, 0x23, reg);
4608 outSISIDXREG(SISPART4, 0x23, reg);
4613 outSISIDXREG(SISSR, 0x32, v2);
4615 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4617 inSISIDXREG(SISSR, 0x16, reg);
4619 outSISIDXREG(SISCR, 0x35, reg);
4620 outSISIDXREG(SISCR, 0x83, 0x00);
4621 #if !defined(__i386__) && !defined(__x86_64__)
4622 if(sisfb_videoram) {
4623 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4624 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4625 outSISIDXREG(SISSR, 0x14, reg);
4628 /* Need to map max FB size for finding out about RAM size */
4630 sisfb_post_map_vram(ivideo, &mapsize, 4);
4632 if(ivideo->video_vbase) {
4633 sisfb_post_300_ramsize(pdev, mapsize);
4634 iounmap(ivideo->video_vbase);
4637 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4638 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4639 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4641 #if !defined(__i386__) && !defined(__x86_64__)
4648 inSISIDXREG(SISSR, 0x3a, reg);
4649 if((reg & 0x30) == 0x30) {
4650 v1 = 0x04; /* PCI */
4653 v1 = 0x14; /* AGP */
4657 outSISIDXREG(SISSR, 0x21, v1);
4658 outSISIDXREG(SISSR, 0x22, v2);
4661 sisfb_sense_crt1(ivideo);
4663 /* Set default mode, don't clear screen */
4664 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4665 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4666 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4667 ivideo->curFSTN = ivideo->curDSTN = 0;
4668 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4669 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4671 outSISIDXREG(SISSR, 0x05, 0x86);
4674 orSISIDXREG(SISSR, 0x01, 0x20);
4676 /* Save mode number in CR34 */
4677 outSISIDXREG(SISCR, 0x34, 0x2e);
4679 /* Let everyone know what the current mode is */
4680 ivideo->modeprechange = 0x2e;
4684 #ifdef CONFIG_FB_SIS_315
4686 static void __devinit
4687 sisfb_post_sis315330(struct pci_dev *pdev)
4693 static void __devinit
4694 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4699 for(i = 0; i <= (delay * 10 * 36); i++) {
4700 inSISIDXREG(SISSR, 0x05, reg);
4705 static int __devinit
4706 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4707 unsigned short pcivendor)
4709 struct pci_dev *pdev = NULL;
4710 unsigned short temp;
4713 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4714 temp = pdev->vendor;
4715 SIS_PCI_PUT_DEVICE(pdev);
4716 if(temp == pcivendor) {
4725 static int __devinit
4726 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4727 unsigned int enda, unsigned int mapsize)
4732 writel(0, ivideo->video_vbase);
4734 for(i = starta; i <= enda; i++) {
4737 writel(pos, ivideo->video_vbase + pos);
4740 sisfb_post_xgi_delay(ivideo, 150);
4742 if(readl(ivideo->video_vbase) != 0)
4745 for(i = starta; i <= enda; i++) {
4748 if(readl(ivideo->video_vbase + pos) != pos)
4757 static void __devinit
4758 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4760 unsigned int buswidth, ranksize, channelab, mapsize;
4763 static const u8 dramsr13[12 * 5] = {
4764 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4765 0x02, 0x0e, 0x0a, 0x40, 0x59,
4766 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4767 0x02, 0x0e, 0x09, 0x20, 0x55,
4768 0x02, 0x0d, 0x0a, 0x20, 0x49,
4769 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4770 0x02, 0x0e, 0x08, 0x10, 0x51,
4771 0x02, 0x0d, 0x09, 0x10, 0x45,
4772 0x02, 0x0c, 0x0a, 0x10, 0x39,
4773 0x02, 0x0d, 0x08, 0x08, 0x41,
4774 0x02, 0x0c, 0x09, 0x08, 0x35,
4775 0x02, 0x0c, 0x08, 0x04, 0x31
4777 static const u8 dramsr13_4[4 * 5] = {
4778 0x02, 0x0d, 0x09, 0x40, 0x45,
4779 0x02, 0x0c, 0x09, 0x20, 0x35,
4780 0x02, 0x0c, 0x08, 0x10, 0x31,
4781 0x02, 0x0b, 0x08, 0x08, 0x21
4784 /* Enable linear mode, disable 0xa0000 address decoding */
4785 /* We disable a0000 address decoding, because
4786 * - if running on x86, if the card is disabled, it means
4787 * that another card is in the system. We don't want
4788 * to interphere with that primary card's textmode.
4789 * - if running on non-x86, there usually is no VGA window
4792 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4794 /* Need to map max FB size for finding out about RAM size */
4795 mapsize = 256 << 20;
4796 sisfb_post_map_vram(ivideo, &mapsize, 32);
4798 if(!ivideo->video_vbase) {
4799 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4800 outSISIDXREG(SISSR, 0x13, 0x35);
4801 outSISIDXREG(SISSR, 0x14, 0x41);
4806 /* Non-interleaving */
4807 outSISIDXREG(SISSR, 0x15, 0x00);
4809 outSISIDXREG(SISSR, 0x1c, 0x00);
4811 if(ivideo->chip == XGI_20) {
4814 inSISIDXREG(SISCR, 0x97, reg);
4815 if(!(reg & 0x01)) { /* Single 32/16 */
4817 outSISIDXREG(SISSR, 0x13, 0xb1);
4818 outSISIDXREG(SISSR, 0x14, 0x52);
4819 sisfb_post_xgi_delay(ivideo, 1);
4821 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4824 outSISIDXREG(SISSR, 0x13, 0x31);
4825 outSISIDXREG(SISSR, 0x14, 0x42);
4826 sisfb_post_xgi_delay(ivideo, 1);
4827 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4831 outSISIDXREG(SISSR, 0x13, 0xb1);
4832 outSISIDXREG(SISSR, 0x14, 0x41);
4833 sisfb_post_xgi_delay(ivideo, 1);
4835 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4838 outSISIDXREG(SISSR, 0x13, 0x31);
4839 } else { /* Dual 16/8 */
4841 outSISIDXREG(SISSR, 0x13, 0xb1);
4842 outSISIDXREG(SISSR, 0x14, 0x41);
4843 sisfb_post_xgi_delay(ivideo, 1);
4845 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4848 outSISIDXREG(SISSR, 0x13, 0x31);
4849 outSISIDXREG(SISSR, 0x14, 0x31);
4850 sisfb_post_xgi_delay(ivideo, 1);
4851 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4855 outSISIDXREG(SISSR, 0x13, 0xb1);
4856 outSISIDXREG(SISSR, 0x14, 0x30);
4857 sisfb_post_xgi_delay(ivideo, 1);
4859 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4862 outSISIDXREG(SISSR, 0x13, 0x31);
4865 } else { /* XGI_40 */
4867 inSISIDXREG(SISCR, 0x97, reg);
4869 inSISIDXREG(SISSR, 0x39, reg);
4873 if(reg & 0x01) { /* DDRII */
4875 if(ivideo->revision_id == 2) {
4877 outSISIDXREG(SISSR, 0x13, 0xa1);
4878 outSISIDXREG(SISSR, 0x14, 0x44);
4880 sisfb_post_xgi_delay(ivideo, 1);
4881 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4884 outSISIDXREG(SISSR, 0x13, 0x21);
4885 outSISIDXREG(SISSR, 0x14, 0x34);
4886 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4890 outSISIDXREG(SISSR, 0x13, 0xa1);
4891 outSISIDXREG(SISSR, 0x14, 0x40);
4893 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4896 outSISIDXREG(SISSR, 0x13, 0x21);
4897 outSISIDXREG(SISSR, 0x14, 0x30);
4900 outSISIDXREG(SISSR, 0x13, 0xa1);
4901 outSISIDXREG(SISSR, 0x14, 0x4c);
4903 sisfb_post_xgi_delay(ivideo, 1);
4904 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4908 outSISIDXREG(SISSR, 0x14, 0x48);
4909 sisfb_post_xgi_delay(ivideo, 1);
4911 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4914 outSISIDXREG(SISSR, 0x13, 0x21);
4915 outSISIDXREG(SISSR, 0x14, 0x3c);
4918 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4922 outSISIDXREG(SISSR, 0x14, 0x38);
4926 sisfb_post_xgi_delay(ivideo, 1);
4931 if(ivideo->revision_id == 2) {
4933 outSISIDXREG(SISSR, 0x13, 0xa1);
4934 outSISIDXREG(SISSR, 0x14, 0x52);
4935 sisfb_post_xgi_delay(ivideo, 1);
4937 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4940 outSISIDXREG(SISSR, 0x13, 0x21);
4941 outSISIDXREG(SISSR, 0x14, 0x42);
4944 outSISIDXREG(SISSR, 0x13, 0xa1);
4945 outSISIDXREG(SISSR, 0x14, 0x5a);
4946 sisfb_post_xgi_delay(ivideo, 1);
4948 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4951 outSISIDXREG(SISSR, 0x13, 0x21);
4952 outSISIDXREG(SISSR, 0x14, 0x4a);
4954 sisfb_post_xgi_delay(ivideo, 1);
4960 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4961 sisfb_post_xgi_delay(ivideo, 1);
4963 j = (ivideo->chip == XGI_20) ? 5 : 9;
4964 k = (ivideo->chip == XGI_20) ? 12 : 4;
4966 for(i = 0; i < k; i++) {
4968 reg = (ivideo->chip == XGI_20) ?
4969 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4970 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4971 sisfb_post_xgi_delay(ivideo, 50);
4973 ranksize = (ivideo->chip == XGI_20) ?
4974 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4976 inSISIDXREG(SISSR, 0x13, reg);
4977 if(reg & 0x80) ranksize <<= 1;
4979 if(ivideo->chip == XGI_20) {
4980 if(buswidth == 16) ranksize <<= 1;
4981 else if(buswidth == 32) ranksize <<= 2;
4983 if(buswidth == 64) ranksize <<= 1;
4989 if((ranksize * l) <= 256) {
4990 while((ranksize >>= 1)) reg += 0x10;
4995 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4996 sisfb_post_xgi_delay(ivideo, 1);
4998 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5002 iounmap(ivideo->video_vbase);
5005 static void __devinit
5006 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5010 static const u8 cs90[8 * 3] = {
5020 static const u8 csb8[8 * 3] = {
5034 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5035 if(ivideo->haveXGIROM) {
5036 v1 = ivideo->bios_abase[0x90 + index];
5037 v2 = ivideo->bios_abase[0x90 + index + 1];
5038 v3 = ivideo->bios_abase[0x90 + index + 2];
5040 outSISIDXREG(SISSR, 0x28, v1);
5041 outSISIDXREG(SISSR, 0x29, v2);
5042 outSISIDXREG(SISSR, 0x2a, v3);
5043 sisfb_post_xgi_delay(ivideo, 0x43);
5044 sisfb_post_xgi_delay(ivideo, 0x43);
5045 sisfb_post_xgi_delay(ivideo, 0x43);
5047 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5048 if(ivideo->haveXGIROM) {
5049 v1 = ivideo->bios_abase[0xb8 + index];
5050 v2 = ivideo->bios_abase[0xb8 + index + 1];
5051 v3 = ivideo->bios_abase[0xb8 + index + 2];
5053 outSISIDXREG(SISSR, 0x2e, v1);
5054 outSISIDXREG(SISSR, 0x2f, v2);
5055 outSISIDXREG(SISSR, 0x30, v3);
5056 sisfb_post_xgi_delay(ivideo, 0x43);
5057 sisfb_post_xgi_delay(ivideo, 0x43);
5058 sisfb_post_xgi_delay(ivideo, 0x43);
5061 static int __devinit
5062 sisfb_post_xgi(struct pci_dev *pdev)
5064 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5065 unsigned char *bios = ivideo->bios_abase;
5066 struct pci_dev *mypdev = NULL;
5067 const u8 *ptr, *ptr2;
5068 u8 v1, v2, v3, v4, v5, reg, ramtype;
5069 u32 rega, regb, regd;
5071 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5072 static const u8 cs76[2] = { 0xa3, 0xfb };
5073 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5074 static const u8 cs158[8] = {
5075 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5077 static const u8 cs160[8] = {
5078 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5080 static const u8 cs168[8] = {
5081 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5083 static const u8 cs128[3 * 8] = {
5084 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5085 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5086 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5088 static const u8 cs148[2 * 8] = {
5089 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5090 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5092 static const u8 cs31a[8 * 4] = {
5093 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5094 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5095 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5096 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5098 static const u8 cs33a[8 * 4] = {
5099 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5100 0x00, 0x00, 0x00, 0x00, 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 cs45a[8 * 2] = {
5105 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5108 static const u8 cs170[7 * 8] = {
5109 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5110 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5111 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5112 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5113 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5114 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5115 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5117 static const u8 cs1a8[3 * 8] = {
5118 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5119 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5122 static const u8 cs100[2 * 8] = {
5123 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5124 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5128 reg = inSISREG(SISVGAENABLE) | 0x01;
5129 outSISREG(SISVGAENABLE, reg);
5132 reg = inSISREG(SISMISCR) | 0x01;
5133 outSISREG(SISMISCW, reg);
5136 outSISIDXREG(SISSR, 0x05, 0x86);
5137 inSISIDXREG(SISSR, 0x05, reg);
5141 /* Clear some regs */
5142 for(i = 0; i < 0x22; i++) {
5143 if(0x06 + i == 0x20) continue;
5144 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5146 for(i = 0; i < 0x0b; i++) {
5147 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5149 for(i = 0; i < 0x10; i++) {
5150 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5154 if(ivideo->haveXGIROM) {
5155 ptr = (const u8 *)&bios[0x78];
5157 for(i = 0; i < 3; i++) {
5158 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5162 if(ivideo->haveXGIROM) {
5163 ptr = (const u8 *)&bios[0x76];
5165 for(i = 0; i < 2; i++) {
5166 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5169 v1 = 0x18; v2 = 0x00;
5170 if(ivideo->haveXGIROM) {
5174 outSISIDXREG(SISSR, 0x07, v1);
5175 outSISIDXREG(SISSR, 0x11, 0x0f);
5176 outSISIDXREG(SISSR, 0x1f, v2);
5177 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5178 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5179 outSISIDXREG(SISSR, 0x27, 0x74);
5182 if(ivideo->haveXGIROM) {
5183 ptr = (const u8 *)&bios[0x7b];
5185 for(i = 0; i < 3; i++) {
5186 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5189 if(ivideo->chip == XGI_40) {
5190 if(ivideo->revision_id == 2) {
5191 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5193 outSISIDXREG(SISCR, 0x7d, 0xfe);
5194 outSISIDXREG(SISCR, 0x7e, 0x0f);
5196 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5197 andSISIDXREG(SISCR, 0x58, 0xd7);
5198 inSISIDXREG(SISCR, 0xcb, reg);
5200 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5204 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5205 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5207 if(ivideo->chip == XGI_20) {
5208 outSISIDXREG(SISSR, 0x36, 0x70);
5210 outSISIDXREG(SISVID, 0x00, 0x86);
5211 outSISIDXREG(SISVID, 0x32, 0x00);
5212 outSISIDXREG(SISVID, 0x30, 0x00);
5213 outSISIDXREG(SISVID, 0x32, 0x01);
5214 outSISIDXREG(SISVID, 0x30, 0x00);
5215 andSISIDXREG(SISVID, 0x2f, 0xdf);
5216 andSISIDXREG(SISCAP, 0x00, 0x3f);
5218 outSISIDXREG(SISPART1, 0x2f, 0x01);
5219 outSISIDXREG(SISPART1, 0x00, 0x00);
5220 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5221 outSISIDXREG(SISPART1, 0x2e, 0x08);
5222 andSISIDXREG(SISPART1, 0x35, 0x7f);
5223 andSISIDXREG(SISPART1, 0x50, 0xfe);
5225 inSISIDXREG(SISPART4, 0x00, reg);
5226 if(reg == 1 || reg == 2) {
5227 outSISIDXREG(SISPART2, 0x00, 0x1c);
5228 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5229 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5230 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5231 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5233 inSISIDXREG(SISPART4, 0x01, reg);
5234 if((reg & 0xf0) >= 0xb0) {
5235 inSISIDXREG(SISPART4, 0x23, reg);
5236 if(reg & 0x20) reg |= 0x40;
5237 outSISIDXREG(SISPART4, 0x23, reg);
5238 reg = (reg & 0x20) ? 0x02 : 0x00;
5239 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5245 inSISIDXREG(SISSR, 0x3b, reg);
5247 inSISIDXREG(SISSR, 0x3a, reg);
5248 v2 = (reg & 0x30) >> 3;
5249 if(!(v2 & 0x04)) v2 ^= 0x02;
5250 inSISIDXREG(SISSR, 0x39, reg);
5251 if(reg & 0x80) v2 |= 0x80;
5254 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5255 SIS_PCI_PUT_DEVICE(mypdev);
5256 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5261 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5263 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5265 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5267 pci_read_config_dword(mypdev, 0x94, ®d);
5269 pci_write_config_dword(mypdev, 0x94, regd);
5271 SIS_PCI_PUT_DEVICE(mypdev);
5272 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5274 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5275 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5276 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5277 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5278 if((v2 & 0x06) == 4)
5283 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5285 outSISIDXREG(SISSR, 0x22, v1);
5287 if(ivideo->revision_id == 2) {
5288 inSISIDXREG(SISSR, 0x3b, v1);
5289 inSISIDXREG(SISSR, 0x3a, v2);
5290 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5291 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5292 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5294 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5295 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5299 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5300 SIS_PCI_PUT_DEVICE(mypdev);
5305 inSISIDXREG(SISSR, 0x3b, reg);
5306 inSISIDXREG(SISCR, 0x5f, v2);
5307 if((!(reg & 0x02)) && (v2 & 0x0e))
5309 outSISIDXREG(SISSR, 0x27, v1);
5311 if(bios[0x64] & 0x01) {
5312 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5316 pci_read_config_dword(pdev, 0x50, ®d);
5317 regd = (regd >> 20) & 0x0f;
5320 orSISIDXREG(SISCR, 0x5f, 0x08);
5322 outSISIDXREG(SISCR, 0x48, v1);
5324 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5325 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5326 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5327 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5328 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5329 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5330 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5331 outSISIDXREG(SISCR, 0x74, 0xd0);
5332 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5333 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5334 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5336 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5338 SIS_PCI_PUT_DEVICE(mypdev);
5340 outSISIDXREG(SISCR, 0x77, v1);
5348 if(ivideo->haveXGIROM) {
5349 v1 = bios[0x140 + regb];
5351 outSISIDXREG(SISCR, 0x6d, v1);
5354 if(ivideo->haveXGIROM) {
5355 ptr = (const u8 *)&bios[0x128];
5357 for(i = 0, j = 0; i < 3; i++, j += 8) {
5358 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5363 if(ivideo->haveXGIROM) {
5364 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5365 ptr = (const u8 *)&bios[index];
5366 ptr2 = (const u8 *)&bios[index + 0x20];
5368 for(i = 0; i < 2; i++) {
5370 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5373 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5377 for(j = 0; j < 16; j++) {
5379 if(regd & 0x01) reg |= 0x04;
5380 if(regd & 0x02) reg |= 0x08;
5382 outSISIDXREG(SISCR, rega, reg);
5383 inSISIDXREG(SISCR, rega, reg);
5384 inSISIDXREG(SISCR, rega, reg);
5389 andSISIDXREG(SISCR, 0x6e, 0xfc);
5392 if(ivideo->haveXGIROM) {
5393 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5394 ptr = (const u8 *)&bios[index];
5396 for(i = 0; i < 4; i++) {
5397 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5399 for(j = 0; j < 2; j++) {
5402 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5406 for(k = 0; k < 16; k++) {
5408 if(regd & 0x01) reg |= 0x01;
5409 if(regd & 0x02) reg |= 0x02;
5411 outSISIDXREG(SISCR, 0x6f, reg);
5412 inSISIDXREG(SISCR, 0x6f, reg);
5413 inSISIDXREG(SISCR, 0x6f, reg);
5420 if(ivideo->haveXGIROM) {
5421 ptr = (const u8 *)&bios[0x148];
5423 for(i = 0, j = 0; i < 2; i++, j += 8) {
5424 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5427 andSISIDXREG(SISCR, 0x89, 0x8f);
5430 if(ivideo->haveXGIROM) {
5431 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5432 ptr = (const u8 *)&bios[index];
5434 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5436 for(i = 0; i < 5; i++) {
5438 if(regd & 0x01) reg |= 0x01;
5439 if(regd & 0x02) reg |= 0x02;
5441 outSISIDXREG(SISCR, 0x89, reg);
5442 inSISIDXREG(SISCR, 0x89, reg);
5443 inSISIDXREG(SISCR, 0x89, reg);
5447 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5448 if(ivideo->haveXGIROM) {
5449 v1 = bios[0x118 + regb];
5450 v2 = bios[0xf8 + regb];
5451 v3 = bios[0x120 + regb];
5454 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5455 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5456 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5457 outSISIDXREG(SISCR, 0x41, v2);
5460 if(ivideo->haveXGIROM) {
5461 ptr = (const u8 *)&bios[0x170];
5463 for(i = 0, j = 0; i < 7; i++, j += 8) {
5464 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5467 outSISIDXREG(SISCR, 0x59, v3);
5470 if(ivideo->haveXGIROM) {
5471 ptr = (const u8 *)&bios[0x1a8];
5473 for(i = 0, j = 0; i < 3; i++, j += 8) {
5474 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5478 if(ivideo->haveXGIROM) {
5479 ptr = (const u8 *)&bios[0x100];
5481 for(i = 0, j = 0; i < 2; i++, j += 8) {
5482 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5485 outSISIDXREG(SISCR, 0xcf, v4);
5487 outSISIDXREG(SISCR, 0x83, 0x09);
5488 outSISIDXREG(SISCR, 0x87, 0x00);
5490 if(ivideo->chip == XGI_40) {
5491 if( (ivideo->revision_id == 1) ||
5492 (ivideo->revision_id == 2) ) {
5493 outSISIDXREG(SISCR, 0x8c, 0x87);
5497 outSISIDXREG(SISSR, 0x17, 0x00);
5498 outSISIDXREG(SISSR, 0x1a, 0x87);
5500 if(ivideo->chip == XGI_20) {
5501 outSISIDXREG(SISSR, 0x15, 0x00);
5502 outSISIDXREG(SISSR, 0x1c, 0x00);
5505 ramtype = 0x00; v1 = 0x10;
5506 if(ivideo->haveXGIROM) {
5507 ramtype = bios[0x62];
5510 if(!(ramtype & 0x80)) {
5511 if(ivideo->chip == XGI_20) {
5512 outSISIDXREG(SISCR, 0x97, v1);
5513 inSISIDXREG(SISCR, 0x97, reg);
5515 ramtype = (reg & 0x01) << 1;
5518 inSISIDXREG(SISSR, 0x39, reg);
5519 ramtype = reg & 0x02;
5521 inSISIDXREG(SISSR, 0x3a, reg);
5522 ramtype = (reg >> 1) & 0x01;
5532 sisfb_post_xgi_setclocks(ivideo, regb);
5533 if((ivideo->chip == XGI_20) ||
5534 (ivideo->revision_id == 1) ||
5535 (ivideo->revision_id == 2)) {
5536 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5537 if(ivideo->haveXGIROM) {
5538 v1 = bios[regb + 0x158];
5539 v2 = bios[regb + 0x160];
5540 v3 = bios[regb + 0x168];
5542 outSISIDXREG(SISCR, 0x82, v1);
5543 outSISIDXREG(SISCR, 0x85, v2);
5544 outSISIDXREG(SISCR, 0x86, v3);
5546 outSISIDXREG(SISCR, 0x82, 0x88);
5547 outSISIDXREG(SISCR, 0x86, 0x00);
5548 inSISIDXREG(SISCR, 0x86, reg);
5549 outSISIDXREG(SISCR, 0x86, 0x88);
5550 inSISIDXREG(SISCR, 0x86, reg);
5551 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5552 outSISIDXREG(SISCR, 0x82, 0x77);
5553 outSISIDXREG(SISCR, 0x85, 0x00);
5554 inSISIDXREG(SISCR, 0x85, reg);
5555 outSISIDXREG(SISCR, 0x85, 0x88);
5556 inSISIDXREG(SISCR, 0x85, reg);
5557 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5558 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5560 if(ivideo->chip == XGI_40) {
5561 outSISIDXREG(SISCR, 0x97, 0x00);
5563 outSISIDXREG(SISCR, 0x98, 0x01);
5564 outSISIDXREG(SISCR, 0x9a, 0x02);
5566 outSISIDXREG(SISSR, 0x18, 0x01);
5567 if((ivideo->chip == XGI_20) ||
5568 (ivideo->revision_id == 2)) {
5569 outSISIDXREG(SISSR, 0x19, 0x40);
5571 outSISIDXREG(SISSR, 0x19, 0x20);
5573 outSISIDXREG(SISSR, 0x16, 0x00);
5574 outSISIDXREG(SISSR, 0x16, 0x80);
5575 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5576 sisfb_post_xgi_delay(ivideo, 0x43);
5577 sisfb_post_xgi_delay(ivideo, 0x43);
5578 sisfb_post_xgi_delay(ivideo, 0x43);
5579 outSISIDXREG(SISSR, 0x18, 0x00);
5580 if((ivideo->chip == XGI_20) ||
5581 (ivideo->revision_id == 2)) {
5582 outSISIDXREG(SISSR, 0x19, 0x40);
5584 outSISIDXREG(SISSR, 0x19, 0x20);
5586 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5587 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5589 outSISIDXREG(SISSR, 0x16, 0x00);
5590 outSISIDXREG(SISSR, 0x16, 0x80);
5591 sisfb_post_xgi_delay(ivideo, 4);
5592 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5593 if(ivideo->haveXGIROM) {
5595 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5597 v3 = bios[index + 1];
5598 v4 = bios[index + 2];
5599 v5 = bios[index + 3];
5601 outSISIDXREG(SISSR, 0x18, v1);
5602 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5603 outSISIDXREG(SISSR, 0x16, v2);
5604 outSISIDXREG(SISSR, 0x16, v3);
5605 sisfb_post_xgi_delay(ivideo, 0x43);
5606 outSISIDXREG(SISSR, 0x1b, 0x03);
5607 sisfb_post_xgi_delay(ivideo, 0x22);
5608 outSISIDXREG(SISSR, 0x18, v1);
5609 outSISIDXREG(SISSR, 0x19, 0x00);
5610 outSISIDXREG(SISSR, 0x16, v4);
5611 outSISIDXREG(SISSR, 0x16, v5);
5612 outSISIDXREG(SISSR, 0x1b, 0x00);
5615 outSISIDXREG(SISCR, 0x82, 0x77);
5616 outSISIDXREG(SISCR, 0x86, 0x00);
5617 inSISIDXREG(SISCR, 0x86, reg);
5618 outSISIDXREG(SISCR, 0x86, 0x88);
5619 inSISIDXREG(SISCR, 0x86, reg);
5620 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5621 if(ivideo->haveXGIROM) {
5622 v1 = bios[regb + 0x168];
5623 v2 = bios[regb + 0x160];
5624 v3 = bios[regb + 0x158];
5626 outSISIDXREG(SISCR, 0x86, v1);
5627 outSISIDXREG(SISCR, 0x82, 0x77);
5628 outSISIDXREG(SISCR, 0x85, 0x00);
5629 inSISIDXREG(SISCR, 0x85, reg);
5630 outSISIDXREG(SISCR, 0x85, 0x88);
5631 inSISIDXREG(SISCR, 0x85, reg);
5632 outSISIDXREG(SISCR, 0x85, v2);
5633 outSISIDXREG(SISCR, 0x82, v3);
5634 outSISIDXREG(SISCR, 0x98, 0x01);
5635 outSISIDXREG(SISCR, 0x9a, 0x02);
5637 outSISIDXREG(SISSR, 0x28, 0x64);
5638 outSISIDXREG(SISSR, 0x29, 0x63);
5639 sisfb_post_xgi_delay(ivideo, 15);
5640 outSISIDXREG(SISSR, 0x18, 0x00);
5641 outSISIDXREG(SISSR, 0x19, 0x20);
5642 outSISIDXREG(SISSR, 0x16, 0x00);
5643 outSISIDXREG(SISSR, 0x16, 0x80);
5644 outSISIDXREG(SISSR, 0x18, 0xc5);
5645 outSISIDXREG(SISSR, 0x19, 0x23);
5646 outSISIDXREG(SISSR, 0x16, 0x00);
5647 outSISIDXREG(SISSR, 0x16, 0x80);
5648 sisfb_post_xgi_delay(ivideo, 1);
5649 outSISIDXREG(SISCR, 0x97,0x11);
5650 sisfb_post_xgi_setclocks(ivideo, regb);
5651 sisfb_post_xgi_delay(ivideo, 0x46);
5652 outSISIDXREG(SISSR, 0x18, 0xc5);
5653 outSISIDXREG(SISSR, 0x19, 0x23);
5654 outSISIDXREG(SISSR, 0x16, 0x00);
5655 outSISIDXREG(SISSR, 0x16, 0x80);
5656 sisfb_post_xgi_delay(ivideo, 1);
5657 outSISIDXREG(SISSR, 0x1b, 0x04);
5658 sisfb_post_xgi_delay(ivideo, 1);
5659 outSISIDXREG(SISSR, 0x1b, 0x00);
5660 sisfb_post_xgi_delay(ivideo, 1);
5662 if(ivideo->haveXGIROM) {
5665 outSISIDXREG(SISSR, 0x18, v1);
5666 outSISIDXREG(SISSR, 0x19, 0x06);
5667 outSISIDXREG(SISSR, 0x16, 0x04);
5668 outSISIDXREG(SISSR, 0x16, 0x84);
5669 sisfb_post_xgi_delay(ivideo, 1);
5672 sisfb_post_xgi_setclocks(ivideo, regb);
5673 if((ivideo->chip == XGI_40) &&
5674 ((ivideo->revision_id == 1) ||
5675 (ivideo->revision_id == 2))) {
5676 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5677 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5678 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5680 outSISIDXREG(SISCR, 0x82, 0x88);
5681 outSISIDXREG(SISCR, 0x86, 0x00);
5682 inSISIDXREG(SISCR, 0x86, reg);
5683 outSISIDXREG(SISCR, 0x86, 0x88);
5684 outSISIDXREG(SISCR, 0x82, 0x77);
5685 outSISIDXREG(SISCR, 0x85, 0x00);
5686 inSISIDXREG(SISCR, 0x85, reg);
5687 outSISIDXREG(SISCR, 0x85, 0x88);
5688 inSISIDXREG(SISCR, 0x85, reg);
5689 v1 = cs160[regb]; v2 = cs158[regb];
5690 if(ivideo->haveXGIROM) {
5691 v1 = bios[regb + 0x160];
5692 v2 = bios[regb + 0x158];
5694 outSISIDXREG(SISCR, 0x85, v1);
5695 outSISIDXREG(SISCR, 0x82, v2);
5697 if(ivideo->chip == XGI_40) {
5698 outSISIDXREG(SISCR, 0x97, 0x11);
5700 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5701 outSISIDXREG(SISCR, 0x98, 0x01);
5703 outSISIDXREG(SISCR, 0x98, 0x03);
5705 outSISIDXREG(SISCR, 0x9a, 0x02);
5707 if(ivideo->chip == XGI_40) {
5708 outSISIDXREG(SISSR, 0x18, 0x01);
5710 outSISIDXREG(SISSR, 0x18, 0x00);
5712 outSISIDXREG(SISSR, 0x19, 0x40);
5713 outSISIDXREG(SISSR, 0x16, 0x00);
5714 outSISIDXREG(SISSR, 0x16, 0x80);
5715 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5716 sisfb_post_xgi_delay(ivideo, 0x43);
5717 sisfb_post_xgi_delay(ivideo, 0x43);
5718 sisfb_post_xgi_delay(ivideo, 0x43);
5719 outSISIDXREG(SISSR, 0x18, 0x00);
5720 outSISIDXREG(SISSR, 0x19, 0x40);
5721 outSISIDXREG(SISSR, 0x16, 0x00);
5722 outSISIDXREG(SISSR, 0x16, 0x80);
5724 sisfb_post_xgi_delay(ivideo, 4);
5726 if(ivideo->haveXGIROM) {
5729 outSISIDXREG(SISSR, 0x18, v1);
5730 outSISIDXREG(SISSR, 0x19, 0x01);
5731 if(ivideo->chip == XGI_40) {
5732 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5733 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5735 outSISIDXREG(SISSR, 0x16, 0x05);
5736 outSISIDXREG(SISSR, 0x16, 0x85);
5738 sisfb_post_xgi_delay(ivideo, 0x43);
5739 if(ivideo->chip == XGI_40) {
5740 outSISIDXREG(SISSR, 0x1b, 0x01);
5742 outSISIDXREG(SISSR, 0x1b, 0x03);
5744 sisfb_post_xgi_delay(ivideo, 0x22);
5745 outSISIDXREG(SISSR, 0x18, v1);
5746 outSISIDXREG(SISSR, 0x19, 0x00);
5747 if(ivideo->chip == XGI_40) {
5748 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5749 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5751 outSISIDXREG(SISSR, 0x16, 0x05);
5752 outSISIDXREG(SISSR, 0x16, 0x85);
5754 outSISIDXREG(SISSR, 0x1b, 0x00);
5759 if(ivideo->haveXGIROM) {
5760 v1 = bios[0x110 + regb];
5762 outSISIDXREG(SISSR, 0x1b, v1);
5765 v1 = 0x00; v2 = 0x00;
5766 if(ivideo->haveXGIROM) {
5772 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5774 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5775 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5779 /* Set default mode, don't clear screen */
5780 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5781 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5782 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5783 ivideo->curFSTN = ivideo->curDSTN = 0;
5784 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5785 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5787 outSISIDXREG(SISSR, 0x05, 0x86);
5789 /* Disable read-cache */
5790 andSISIDXREG(SISSR, 0x21, 0xdf);
5791 sisfb_post_xgi_ramsize(ivideo);
5792 /* Enable read-cache */
5793 orSISIDXREG(SISSR, 0x21, 0x20);
5798 printk(KERN_DEBUG "-----------------\n");
5799 for(i = 0; i < 0xff; i++) {
5800 inSISIDXREG(SISCR, i, reg);
5801 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5803 for(i = 0; i < 0x40; i++) {
5804 inSISIDXREG(SISSR, i, reg);
5805 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5807 printk(KERN_DEBUG "-----------------\n");
5811 if(ivideo->chip == XGI_20) {
5812 orSISIDXREG(SISCR, 0x32, 0x20);
5814 inSISIDXREG(SISPART4, 0x00, reg);
5815 if((reg == 1) || (reg == 2)) {
5816 sisfb_sense_crt1(ivideo);
5818 orSISIDXREG(SISCR, 0x32, 0x20);
5822 /* Set default mode, don't clear screen */
5823 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5824 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5825 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5826 ivideo->curFSTN = ivideo->curDSTN = 0;
5827 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5829 outSISIDXREG(SISSR, 0x05, 0x86);
5832 orSISIDXREG(SISSR, 0x01, 0x20);
5834 /* Save mode number in CR34 */
5835 outSISIDXREG(SISCR, 0x34, 0x2e);
5837 /* Let everyone know what the current mode is */
5838 ivideo->modeprechange = 0x2e;
5840 if(ivideo->chip == XGI_40) {
5841 inSISIDXREG(SISCR, 0xca, reg);
5842 inSISIDXREG(SISCR, 0xcc, v1);
5843 if((reg & 0x10) && (!(v1 & 0x04))) {
5845 "sisfb: Please connect power to the card.\n");
5854 static int __devinit
5855 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5857 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5858 struct sis_video_info *ivideo = NULL;
5859 struct fb_info *sis_fb_info = NULL;
5867 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5868 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5872 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
5875 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5876 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5879 ivideo = (struct sis_video_info *)sis_fb_info->par;
5880 ivideo->memyselfandi = sis_fb_info;
5882 ivideo->sisfb_id = SISFB_ID;
5884 if(card_list == NULL) {
5885 ivideo->cardnumber = 0;
5887 struct sis_video_info *countvideo = card_list;
5888 ivideo->cardnumber = 1;
5889 while((countvideo = countvideo->next) != 0)
5890 ivideo->cardnumber++;
5893 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5895 ivideo->warncount = 0;
5896 ivideo->chip_id = pdev->device;
5897 ivideo->chip_vendor = pdev->vendor;
5898 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
5899 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5900 pci_read_config_word(pdev, PCI_COMMAND, ®16);
5901 ivideo->sisvga_enabled = reg16 & 0x01;
5902 ivideo->pcibus = pdev->bus->number;
5903 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5904 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5905 ivideo->subsysvendor = pdev->subsystem_vendor;
5906 ivideo->subsysdevice = pdev->subsystem_device;
5907 #ifdef SIS_OLD_CONFIG_COMPAT
5908 ivideo->ioctl32registered = 0;
5912 if(sisfb_mode_idx == -1) {
5913 sisfb_get_vga_mode_from_kernel();
5917 ivideo->chip = chipinfo->chip;
5918 ivideo->sisvga_engine = chipinfo->vgaengine;
5919 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5920 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5921 ivideo->mni = chipinfo->mni;
5923 ivideo->detectedpdc = 0xff;
5924 ivideo->detectedpdca = 0xff;
5925 ivideo->detectedlcda = 0xff;
5927 ivideo->sisfb_thismonitor.datavalid = FALSE;
5929 ivideo->current_base = 0;
5931 ivideo->engineok = 0;
5933 ivideo->sisfb_was_boot_device = 0;
5934 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5935 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5936 if(ivideo->sisvga_enabled)
5937 ivideo->sisfb_was_boot_device = 1;
5939 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5940 "but marked as boot video device ???\n");
5941 printk(KERN_DEBUG "sisfb: I will not accept this "
5942 "as the primary VGA device\n");
5947 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5948 ivideo->sisfb_accel = sisfb_accel;
5949 ivideo->sisfb_ypan = sisfb_ypan;
5950 ivideo->sisfb_max = sisfb_max;
5951 ivideo->sisfb_userom = sisfb_userom;
5952 ivideo->sisfb_useoem = sisfb_useoem;
5953 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5954 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5955 ivideo->sisfb_crt1off = sisfb_crt1off;
5956 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5957 ivideo->sisfb_crt2type = sisfb_crt2type;
5958 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5959 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5960 ivideo->sisfb_dstn = sisfb_dstn;
5961 ivideo->sisfb_fstn = sisfb_fstn;
5962 ivideo->sisfb_tvplug = sisfb_tvplug;
5963 ivideo->sisfb_tvstd = sisfb_tvstd;
5964 ivideo->tvxpos = sisfb_tvxposoffset;
5965 ivideo->tvypos = sisfb_tvyposoffset;
5966 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5967 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5968 ivideo->sisfb_inverse = sisfb_inverse;
5971 ivideo->refresh_rate = 0;
5972 if(ivideo->sisfb_parm_rate != -1) {
5973 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5976 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5977 ivideo->SiS_Pr.CenterScreen = -1;
5978 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5979 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5981 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5982 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5983 ivideo->SiS_Pr.SiS_ChSW = FALSE;
5984 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5985 ivideo->SiS_Pr.HaveEMI = FALSE;
5986 ivideo->SiS_Pr.HaveEMILCD = FALSE;
5987 ivideo->SiS_Pr.OverruleEMI = FALSE;
5988 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
5989 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5990 ivideo->SiS_Pr.PDC = -1;
5991 ivideo->SiS_Pr.PDCA = -1;
5992 ivideo->SiS_Pr.DDCPortMixup = FALSE;
5993 #ifdef CONFIG_FB_SIS_315
5994 if(ivideo->chip >= SIS_330) {
5995 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5996 if(ivideo->chip >= SIS_661) {
5997 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
6002 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6004 pci_set_drvdata(pdev, ivideo);
6006 /* Patch special cases */
6007 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6008 switch(ivideo->nbridge->device) {
6009 #ifdef CONFIG_FB_SIS_300
6010 case PCI_DEVICE_ID_SI_730:
6011 ivideo->chip = SIS_730;
6012 strcpy(ivideo->myid, "SiS 730");
6015 #ifdef CONFIG_FB_SIS_315
6016 case PCI_DEVICE_ID_SI_651:
6017 /* ivideo->chip is ok */
6018 strcpy(ivideo->myid, "SiS 651");
6020 case PCI_DEVICE_ID_SI_740:
6021 ivideo->chip = SIS_740;
6022 strcpy(ivideo->myid, "SiS 740");
6024 case PCI_DEVICE_ID_SI_661:
6025 ivideo->chip = SIS_661;
6026 strcpy(ivideo->myid, "SiS 661");
6028 case PCI_DEVICE_ID_SI_741:
6029 ivideo->chip = SIS_741;
6030 strcpy(ivideo->myid, "SiS 741");
6032 case PCI_DEVICE_ID_SI_760:
6033 ivideo->chip = SIS_760;
6034 strcpy(ivideo->myid, "SiS 760");
6036 case PCI_DEVICE_ID_SI_761:
6037 ivideo->chip = SIS_761;
6038 strcpy(ivideo->myid, "SiS 761");
6046 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6047 strcpy(sis_fb_info->modename, ivideo->myid);
6050 ivideo->SiS_Pr.ChipType = ivideo->chip;
6052 ivideo->SiS_Pr.ivideo = (void *)ivideo;
6054 #ifdef CONFIG_FB_SIS_315
6055 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6056 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6057 ivideo->SiS_Pr.ChipType = SIS_315H;
6061 if(!ivideo->sisvga_enabled) {
6062 if(pci_enable_device(pdev)) {
6063 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6064 pci_set_drvdata(pdev, NULL);
6070 ivideo->video_base = pci_resource_start(pdev, 0);
6071 ivideo->mmio_base = pci_resource_start(pdev, 1);
6072 ivideo->mmio_size = pci_resource_len(pdev, 1);
6073 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
6074 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
6076 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
6078 #ifdef CONFIG_FB_SIS_300
6079 /* Find PCI systems for Chrontel/GPIO communication setup */
6080 if(ivideo->chip == SIS_630) {
6083 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6084 mychswtable[i].subsysCard == ivideo->subsysdevice) {
6085 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6086 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6087 "requiring Chrontel/GPIO setup\n",
6088 mychswtable[i].vendorName,
6089 mychswtable[i].cardName);
6090 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6094 } while(mychswtable[i].subsysVendor != 0);
6098 #ifdef CONFIG_FB_SIS_315
6099 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6100 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
6104 outSISIDXREG(SISSR, 0x05, 0x86);
6106 if( (!ivideo->sisvga_enabled)
6107 #if !defined(__i386__) && !defined(__x86_64__)
6108 || (sisfb_resetcard)
6111 for(i = 0x30; i <= 0x3f; i++) {
6112 outSISIDXREG(SISCR, i, 0x00);
6116 /* Find out about current video mode */
6117 ivideo->modeprechange = 0x03;
6118 inSISIDXREG(SISCR, 0x34, reg);
6120 ivideo->modeprechange = reg & 0x7f;
6121 } else if(ivideo->sisvga_enabled) {
6122 #if defined(__i386__) || defined(__x86_64__)
6123 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
6125 ivideo->modeprechange = readb(tt + 0x49);
6131 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6133 if((reg & 0x80) && (reg != 0xff)) {
6134 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6136 printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6137 "X server is active\n");
6145 /* Search and copy ROM image */
6146 ivideo->bios_abase = NULL;
6147 ivideo->SiS_Pr.VirtualRomBase = NULL;
6148 ivideo->SiS_Pr.UseROM = FALSE;
6149 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
6150 if(ivideo->sisfb_userom) {
6151 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6152 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6153 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6154 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6155 ivideo->SiS_Pr.UseROM ? "" : "not ");
6156 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6157 ivideo->SiS_Pr.UseROM = FALSE;
6158 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6159 if( (ivideo->revision_id == 2) &&
6160 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6161 ivideo->SiS_Pr.DDCPortMixup = TRUE;
6165 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6168 /* Find systems for special custom timing */
6169 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6170 sisfb_detect_custom_timing(ivideo);
6173 /* POST card in case this has not been done by the BIOS */
6174 if( (!ivideo->sisvga_enabled)
6175 #if !defined(__i386__) && !defined(__x86_64__)
6176 || (sisfb_resetcard)
6179 #ifdef CONFIG_FB_SIS_300
6180 if(ivideo->sisvga_engine == SIS_300_VGA) {
6181 if(ivideo->chip == SIS_300) {
6182 sisfb_post_sis300(pdev);
6183 ivideo->sisfb_can_post = 1;
6188 #ifdef CONFIG_FB_SIS_315
6189 if(ivideo->sisvga_engine == SIS_315_VGA) {
6191 /* if((ivideo->chip == SIS_315H) ||
6192 (ivideo->chip == SIS_315) ||
6193 (ivideo->chip == SIS_315PRO) ||
6194 (ivideo->chip == SIS_330)) {
6195 sisfb_post_sis315330(pdev);
6196 } else */ if(ivideo->chip == XGI_20) {
6197 result = sisfb_post_xgi(pdev);
6198 ivideo->sisfb_can_post = 1;
6199 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6200 result = sisfb_post_xgi(pdev);
6201 ivideo->sisfb_can_post = 1;
6203 printk(KERN_INFO "sisfb: Card is not "
6204 "POSTed and sisfb can't do this either.\n");
6207 printk(KERN_ERR "sisfb: Failed to POST card\n");
6215 ivideo->sisfb_card_posted = 1;
6217 /* Find out about RAM size */
6218 if(sisfb_get_dram_size(ivideo)) {
6219 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6225 /* Enable PCI addressing and MMIO */
6226 if((ivideo->sisfb_mode_idx < 0) ||
6227 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6228 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6229 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6230 /* Enable 2D accelerator engine */
6231 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6234 if(sisfb_pdc != 0xff) {
6235 if(ivideo->sisvga_engine == SIS_300_VGA)
6239 ivideo->SiS_Pr.PDC = sisfb_pdc;
6241 #ifdef CONFIG_FB_SIS_315
6242 if(ivideo->sisvga_engine == SIS_315_VGA) {
6243 if(sisfb_pdca != 0xff)
6244 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6248 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6249 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6250 (int)(ivideo->video_size >> 20));
6251 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6256 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6257 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6262 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6263 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6264 if(!ivideo->video_vbase) {
6265 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6270 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6271 if(!ivideo->mmio_vbase) {
6272 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6274 error_0: iounmap(ivideo->video_vbase);
6275 error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6276 error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6277 error_3: vfree(ivideo->bios_abase);
6278 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6282 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6284 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6285 pci_set_drvdata(pdev, NULL);
6286 if(!ivideo->sisvga_enabled)
6287 pci_disable_device(pdev);
6292 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6293 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6295 if(ivideo->video_offset) {
6296 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6297 ivideo->video_offset / 1024);
6300 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6301 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6304 /* Determine the size of the command queue */
6305 if(ivideo->sisvga_engine == SIS_300_VGA) {
6306 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6308 if(ivideo->chip == XGI_20) {
6309 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6311 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6315 /* Engines are no longer initialized here; this is
6316 * now done after the first mode-switch (if the
6317 * submitted var has its acceleration flags set).
6320 /* Calculate the base of the (unused) hw cursor */
6321 ivideo->hwcursor_vbase = ivideo->video_vbase
6322 + ivideo->video_size
6323 - ivideo->cmdQueueSize
6324 - ivideo->hwcursor_size;
6325 ivideo->caps |= HW_CURSOR_CAP;
6327 /* Initialize offscreen memory manager */
6328 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6329 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6332 /* Used for clearing the screen only, therefore respect our mem limit */
6333 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6334 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6338 ivideo->vbflags = 0;
6339 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6340 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6341 ivideo->defmodeidx = DEFAULT_MODE;
6344 if(ivideo->chip < XGI_20) {
6345 if(ivideo->bios_abase) {
6346 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6350 if((ivideo->sisfb_mode_idx < 0) ||
6351 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6353 sisfb_sense_crt1(ivideo);
6355 sisfb_get_VB_type(ivideo);
6357 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6358 sisfb_detect_VB_connect(ivideo);
6361 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6363 /* Decide on which CRT2 device to use */
6364 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6365 if(ivideo->sisfb_crt2type != -1) {
6366 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6367 (ivideo->vbflags & CRT2_LCD)) {
6368 ivideo->currentvbflags |= CRT2_LCD;
6369 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6370 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6373 /* Chrontel 700x TV detection often unreliable, therefore
6374 * use a different default order on such machines
6376 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6377 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6378 if(ivideo->vbflags & CRT2_LCD)
6379 ivideo->currentvbflags |= CRT2_LCD;
6380 else if(ivideo->vbflags & CRT2_TV)
6381 ivideo->currentvbflags |= CRT2_TV;
6382 else if(ivideo->vbflags & CRT2_VGA)
6383 ivideo->currentvbflags |= CRT2_VGA;
6385 if(ivideo->vbflags & CRT2_TV)
6386 ivideo->currentvbflags |= CRT2_TV;
6387 else if(ivideo->vbflags & CRT2_LCD)
6388 ivideo->currentvbflags |= CRT2_LCD;
6389 else if(ivideo->vbflags & CRT2_VGA)
6390 ivideo->currentvbflags |= CRT2_VGA;
6395 if(ivideo->vbflags & CRT2_LCD) {
6396 sisfb_detect_lcd_type(ivideo);
6399 sisfb_save_pdc_emi(ivideo);
6401 if(!ivideo->sisfb_crt1off) {
6402 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6404 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6405 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6406 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6410 if(ivideo->sisfb_mode_idx >= 0) {
6411 int bu = ivideo->sisfb_mode_idx;
6412 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6413 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6414 if(bu != ivideo->sisfb_mode_idx) {
6415 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6416 sisbios_mode[bu].xres,
6417 sisbios_mode[bu].yres,
6418 sisbios_mode[bu].bpp);
6422 if(ivideo->sisfb_mode_idx < 0) {
6423 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6425 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6428 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6431 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6436 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6438 if(ivideo->refresh_rate != 0) {
6439 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6440 ivideo->sisfb_mode_idx);
6443 if(ivideo->rate_idx == 0) {
6444 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6445 ivideo->refresh_rate = 60;
6448 if(ivideo->sisfb_thismonitor.datavalid) {
6449 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6450 ivideo->sisfb_mode_idx,
6452 ivideo->refresh_rate)) {
6453 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6454 "exceeds monitor specs!\n");
6458 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6459 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6460 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6462 sisfb_set_vparms(ivideo);
6464 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6466 /* ---------------- For 2.4: Now switch the mode ------------------ */
6468 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6469 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6470 ivideo->refresh_rate);
6472 /* Determine whether or not acceleration is to be
6473 * used. Need to know before pre/post_set_mode()
6476 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6477 if(ivideo->sisfb_accel) {
6479 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6482 /* Now switch the mode */
6483 sisfb_pre_setmode(ivideo);
6485 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
6486 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6489 iounmap(ivideo->mmio_vbase);
6493 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6495 sisfb_post_setmode(ivideo);
6497 /* Maximize regardless of sisfb_max at startup */
6498 ivideo->default_var.yres_virtual = 32767;
6500 /* Force reset of x virtual in crtc_to_var */
6501 ivideo->default_var.xres_virtual = 0;
6503 /* Copy mode timing to var */
6504 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6506 /* Find out about screen pitch */
6507 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6508 sisfb_set_pitch(ivideo);
6510 /* Init the accelerator (does nothing currently) */
6511 sisfb_initaccel(ivideo);
6513 /* Init some fbinfo entries */
6514 sis_fb_info->node = -1;
6515 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6516 sis_fb_info->fbops = &sisfb_ops;
6517 sis_fb_info->disp = &ivideo->sis_disp;
6518 sis_fb_info->blank = &sisfb_blank;
6519 sis_fb_info->switch_con = &sisfb_switch;
6520 sis_fb_info->updatevar = &sisfb_update_var;
6521 sis_fb_info->changevar = NULL;
6522 strcpy(sis_fb_info->fontname, sisfb_fontname);
6524 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6526 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6528 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6529 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6530 ivideo->refresh_rate);
6532 /* Set up the default var according to chosen default display mode */
6533 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6534 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6535 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6537 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6539 ivideo->default_var.pixclock = (u32) (1000000000 /
6540 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6542 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6543 ivideo->rate_idx, &ivideo->default_var)) {
6544 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6545 ivideo->default_var.pixclock <<= 1;
6549 if(ivideo->sisfb_ypan) {
6550 /* Maximize regardless of sisfb_max at startup */
6551 ivideo->default_var.yres_virtual =
6552 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6553 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6554 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6558 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6561 if(ivideo->sisfb_accel) {
6563 #ifdef STUPID_ACCELF_TEXT_SHIT
6564 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6567 sisfb_initaccel(ivideo);
6569 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6570 sis_fb_info->flags = FBINFO_DEFAULT |
6571 FBINFO_HWACCEL_YPAN |
6572 FBINFO_HWACCEL_XPAN |
6573 FBINFO_HWACCEL_COPYAREA |
6574 FBINFO_HWACCEL_FILLRECT |
6575 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6577 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6579 sis_fb_info->var = ivideo->default_var;
6580 sis_fb_info->fix = ivideo->sisfb_fix;
6581 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6582 sis_fb_info->fbops = &sisfb_ops;
6584 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6585 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6587 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6590 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6593 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6594 MTRR_TYPE_WRCOMB, 1);
6595 if(ivideo->mtrr < 0) {
6596 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6600 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6601 vc_resize_con(1, 1, 0);
6604 if(register_framebuffer(sis_fb_info) < 0) {
6605 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6607 iounmap(ivideo->mmio_vbase);
6611 ivideo->registered = 1;
6614 ivideo->next = card_list;
6617 #ifdef SIS_OLD_CONFIG_COMPAT
6620 /* Our ioctls are all "32/64bit compatible" */
6621 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6622 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6623 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6624 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6625 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6626 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6627 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6628 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6629 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6630 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6631 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6632 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6635 "sisfb: Error registering ioctl32 translations\n");
6637 ivideo->ioctl32registered = 1;
6641 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6642 ivideo->sisfb_accel ? "enabled" : "disabled",
6643 ivideo->sisfb_ypan ?
6644 (ivideo->sisfb_max ? "enabled (auto-max)" :
6645 "enabled (no auto-max)") :
6649 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6650 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6651 GET_FB_IDX(sis_fb_info->node),
6655 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6657 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6659 } /* if mode = "none" */
6664 /*****************************************************/
6665 /* PCI DEVICE HANDLING */
6666 /*****************************************************/
6668 static void __devexit sisfb_remove(struct pci_dev *pdev)
6670 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6671 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6672 int registered = ivideo->registered;
6673 int modechanged = ivideo->modechanged;
6675 #ifdef SIS_OLD_CONFIG_COMPAT
6676 if(ivideo->ioctl32registered) {
6678 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6679 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6680 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6681 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6682 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6683 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6684 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6685 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6686 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6687 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6688 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6689 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6692 "sisfb: Error unregistering ioctl32 translations\n");
6697 iounmap(ivideo->mmio_vbase);
6698 iounmap(ivideo->video_vbase);
6700 /* Release mem regions */
6701 release_mem_region(ivideo->video_base, ivideo->video_size);
6702 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6704 vfree(ivideo->bios_abase);
6707 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6710 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6713 /* Release MTRR region */
6714 if(ivideo->mtrr >= 0)
6715 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6718 pci_set_drvdata(pdev, NULL);
6720 /* If device was disabled when starting, disable
6723 if(!ivideo->sisvga_enabled)
6724 pci_disable_device(pdev);
6726 /* Unregister the framebuffer */
6727 if(ivideo->registered) {
6728 unregister_framebuffer(sis_fb_info);
6729 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6730 framebuffer_release(sis_fb_info);
6736 /* OK, our ivideo is gone for good from here. */
6738 /* TODO: Restore the initial mode
6739 * This sounds easy but is as good as impossible
6740 * on many machines with SiS chip and video bridge
6741 * since text modes are always set up differently
6742 * from machine to machine. Depends on the type
6743 * of integration between chipset and bridge.
6745 if(registered && modechanged)
6747 "sisfb: Restoring of text mode not supported yet\n");
6750 static struct pci_driver sisfb_driver = {
6752 .id_table = sisfb_pci_table,
6753 .probe = sisfb_probe,
6754 .remove = __devexit_p(sisfb_remove)
6757 SISINITSTATIC int __init sisfb_init(void)
6759 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6761 char *options = NULL;
6763 if(fb_get_options("sisfb", &options))
6766 sisfb_setup(options);
6769 return pci_register_driver(&sisfb_driver);
6772 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6774 module_init(sisfb_init);
6778 /*****************************************************/
6780 /*****************************************************/
6784 static char *mode = NULL;
6785 static int vesa = -1;
6786 static unsigned int rate = 0;
6787 static unsigned int crt1off = 1;
6788 static unsigned int mem = 0;
6789 static char *forcecrt2type = NULL;
6790 static int forcecrt1 = -1;
6791 static int pdc = -1;
6792 static int pdc1 = -1;
6793 static int noaccel = -1;
6794 static int noypan = -1;
6795 static int nomax = -1;
6796 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6797 static int inverse = 0;
6799 static int userom = -1;
6800 static int useoem = -1;
6801 static char *tvstandard = NULL;
6802 static int nocrt2rate = 0;
6803 static int scalelcd = -1;
6804 static char *specialtiming = NULL;
6805 static int lvdshl = -1;
6806 static int tvxposoffset = 0, tvyposoffset = 0;
6807 #if !defined(__i386__) && !defined(__x86_64__)
6808 static int resetcard = 0;
6809 static int videoram = 0;
6812 static int __init sisfb_init_module(void)
6814 sisfb_setdefaultparms();
6817 sisfb_parm_rate = rate;
6819 if((scalelcd == 0) || (scalelcd == 1))
6820 sisfb_scalelcd = scalelcd ^ 1;
6822 /* Need to check crt2 type first for fstn/dstn */
6825 sisfb_search_crt2type(forcecrt2type);
6828 sisfb_search_tvstd(tvstandard);
6831 sisfb_search_mode(mode, FALSE);
6833 sisfb_search_vesamode(vesa, FALSE);
6835 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6837 sisfb_forcecrt1 = forcecrt1;
6840 else if(forcecrt1 == 0)
6845 else if(noaccel == 0)
6850 else if(noypan == 0)
6858 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6859 if(inverse) sisfb_inverse = 1;
6863 sisfb_parm_mem = mem;
6866 sisfb_userom = userom;
6869 sisfb_useoem = useoem;
6872 sisfb_pdc = (pdc & 0x7f);
6875 sisfb_pdca = (pdc1 & 0x1f);
6877 sisfb_nocrt2rate = nocrt2rate;
6880 sisfb_search_specialtiming(specialtiming);
6882 if((lvdshl >= 0) && (lvdshl <= 3))
6883 sisfb_lvdshl = lvdshl;
6885 sisfb_tvxposoffset = tvxposoffset;
6886 sisfb_tvyposoffset = tvyposoffset;
6888 #if !defined(__i386__) && !defined(__x86_64__)
6889 sisfb_resetcard = (resetcard) ? 1 : 0;
6891 sisfb_videoram = videoram;
6894 return sisfb_init();
6897 static void __exit sisfb_remove_module(void)
6899 pci_unregister_driver(&sisfb_driver);
6900 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6903 module_init(sisfb_init_module);
6904 module_exit(sisfb_remove_module);
6906 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6907 MODULE_LICENSE("GPL");
6908 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6910 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6911 MODULE_PARM(mem, "i");
6912 MODULE_PARM(noaccel, "i");
6913 MODULE_PARM(noypan, "i");
6914 MODULE_PARM(nomax, "i");
6915 MODULE_PARM(userom, "i");
6916 MODULE_PARM(useoem, "i");
6917 MODULE_PARM(mode, "s");
6918 MODULE_PARM(vesa, "i");
6919 MODULE_PARM(rate, "i");
6920 MODULE_PARM(forcecrt1, "i");
6921 MODULE_PARM(forcecrt2type, "s");
6922 MODULE_PARM(scalelcd, "i");
6923 MODULE_PARM(pdc, "i");
6924 MODULE_PARM(pdc1, "i");
6925 MODULE_PARM(specialtiming, "s");
6926 MODULE_PARM(lvdshl, "i");
6927 MODULE_PARM(tvstandard, "s");
6928 MODULE_PARM(tvxposoffset, "i");
6929 MODULE_PARM(tvyposoffset, "i");
6930 MODULE_PARM(nocrt2rate, "i");
6931 MODULE_PARM(inverse, "i");
6932 #if !defined(__i386__) && !defined(__x86_64__)
6933 MODULE_PARM(resetcard, "i");
6934 MODULE_PARM(videoram, "i");
6938 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6939 module_param(mem, int, 0);
6940 module_param(noaccel, int, 0);
6941 module_param(noypan, int, 0);
6942 module_param(nomax, int, 0);
6943 module_param(userom, int, 0);
6944 module_param(useoem, int, 0);
6945 module_param(mode, charp, 0);
6946 module_param(vesa, int, 0);
6947 module_param(rate, int, 0);
6948 module_param(forcecrt1, int, 0);
6949 module_param(forcecrt2type, charp, 0);
6950 module_param(scalelcd, int, 0);
6951 module_param(pdc, int, 0);
6952 module_param(pdc1, int, 0);
6953 module_param(specialtiming, charp, 0);
6954 module_param(lvdshl, int, 0);
6955 module_param(tvstandard, charp, 0);
6956 module_param(tvxposoffset, int, 0);
6957 module_param(tvyposoffset, int, 0);
6958 module_param(nocrt2rate, int, 0);
6959 #if !defined(__i386__) && !defined(__x86_64__)
6960 module_param(resetcard, int, 0);
6961 module_param(videoram, int, 0);
6965 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6966 MODULE_PARM_DESC(mem,
6967 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6968 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6969 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6970 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6971 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6972 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6973 "for XFree86 4.x/X.org 6.7 and later.\n");
6975 MODULE_PARM_DESC(mem,
6976 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6977 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6978 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6979 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6980 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6981 "The value is to be specified without 'KB'.\n");
6984 MODULE_PARM_DESC(noaccel,
6985 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6988 MODULE_PARM_DESC(noypan,
6989 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6990 "will be performed by redrawing the screen. (default: 0)\n");
6992 MODULE_PARM_DESC(nomax,
6993 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
6994 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6995 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6996 "enable the user to positively specify a virtual Y size of the screen using\n"
6997 "fbset. (default: 0)\n");
6999 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7000 MODULE_PARM_DESC(mode,
7001 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7002 "1024x768x16. Other formats supported include XxY-Depth and\n"
7003 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7004 "number, it will be interpreted as a VESA mode number. (default: none if\n"
7005 "sisfb is a module; this leaves the console untouched and the driver will\n"
7006 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7007 "is in the kernel)\n");
7008 MODULE_PARM_DESC(vesa,
7009 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7010 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
7011 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7012 "0x0103 if sisfb is in the kernel)\n");
7015 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7016 MODULE_PARM_DESC(mode,
7017 "\nSelects the desired default display mode in the format XxYxDepth,\n"
7018 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
7019 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7020 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7022 MODULE_PARM_DESC(vesa,
7023 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7024 "0x117 (default: 0x0103)\n");
7027 MODULE_PARM_DESC(rate,
7028 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7029 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7030 "will be ignored (default: 60)\n");
7032 MODULE_PARM_DESC(forcecrt1,
7033 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7034 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7035 "0=CRT1 OFF) (default: [autodetected])\n");
7037 MODULE_PARM_DESC(forcecrt2type,
7038 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7039 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7040 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7041 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7042 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7043 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7044 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7045 "depends on the very hardware in use. (default: [autodetected])\n");
7047 MODULE_PARM_DESC(scalelcd,
7048 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7049 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7050 "show black bars around the image, TMDS panels will probably do the scaling\n"
7051 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7053 MODULE_PARM_DESC(pdc,
7054 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
7055 "should detect this correctly in most cases; however, sometimes this is not\n"
7056 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
7057 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7058 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7059 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
7061 #ifdef CONFIG_FB_SIS_315
7062 MODULE_PARM_DESC(pdc1,
7063 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
7064 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7065 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7066 "implemented yet.\n");
7069 MODULE_PARM_DESC(specialtiming,
7070 "\nPlease refer to documentation for more information on this option.\n");
7072 MODULE_PARM_DESC(lvdshl,
7073 "\nPlease refer to documentation for more information on this option.\n");
7075 MODULE_PARM_DESC(tvstandard,
7076 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7077 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7079 MODULE_PARM_DESC(tvxposoffset,
7080 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7083 MODULE_PARM_DESC(tvyposoffset,
7084 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7087 MODULE_PARM_DESC(nocrt2rate,
7088 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7089 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7091 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7092 MODULE_PARM_DESC(inverse,
7093 "\nSetting this to anything but 0 should invert the display colors, but this\n"
7094 "does not seem to work. (default: 0)\n");
7097 #if !defined(__i386__) && !defined(__x86_64__)
7098 #ifdef CONFIG_FB_SIS_300
7099 MODULE_PARM_DESC(resetcard,
7100 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
7101 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7102 "currently). Default: 0\n");
7104 MODULE_PARM_DESC(videoram,
7105 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7106 "some non-x86 architectures where the memory auto detection fails. Only\n"
7107 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
7111 #endif /* /MODULE */
7113 /* _GPL only for new symbols. */
7114 EXPORT_SYMBOL(sis_malloc);
7115 EXPORT_SYMBOL(sis_free);
7116 EXPORT_SYMBOL_GPL(sis_malloc_new);
7117 EXPORT_SYMBOL_GPL(sis_free_new);