2 * SiS 300/305/540/630(S)/730(S)
3 * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760
4 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
6 * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the named License,
11 * or any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
22 * Author: Thomas Winischhofer <thomas@winischhofer.net>
24 * Author of (practically wiped) code base:
26 * Copyright (C) 1999 Silicon Integrated Systems, Inc.
28 * See http://www.winischhofer.net/ for more information and updates
30 * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
31 * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
35 #include <linux/config.h>
36 #include <linux/version.h>
37 #include <linux/module.h>
38 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
39 #include <linux/moduleparam.h>
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>
49 #include <linux/delay.h>
51 #include <linux/console.h>
52 #include <linux/selection.h>
53 #include <linux/ioport.h>
54 #include <linux/init.h>
55 #include <linux/pci.h>
56 #include <linux/vmalloc.h>
57 #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 /* ------------------ Internal helper routines ----------------- */
99 sisfb_setdefaultparms(void)
109 /* Module: "None" for 2.4, default mode for 2.5+ */
110 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
113 sisfb_mode_idx = MODE_INDEX_NONE;
116 /* Static: Default mode */
119 sisfb_parm_rate = -1;
121 sisfb_forcecrt1 = -1;
127 sisfb_specialtiming = CUT_NONE;
133 sisfb_tvxposoffset = 0;
134 sisfb_tvyposoffset = 0;
136 sisfb_nocrt2rate = 0;
137 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
139 sisfb_fontname[0] = 0;
141 #if !defined(__i386__) && !defined(__x86_64__)
148 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
152 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
155 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
156 sisfb_mode_idx = MODE_INDEX_NONE;
159 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
161 sisfb_mode_idx = DEFAULT_MODE;
166 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
168 while(sisbios_mode[i++].mode_no[0] != 0) {
169 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
170 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
172 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
173 sisbios_mode[i-1].mode_no[1] == 0x56 ||
174 sisbios_mode[i-1].mode_no[1] == 0x53) continue;
176 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
177 sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
179 sisfb_mode_idx = i - 1;
184 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
188 sisfb_search_mode(char *name, BOOLEAN quiet)
191 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
192 char strbuf[16], strbuf1[20];
193 char *nameptr = name;
195 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
199 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
201 sisfb_mode_idx = DEFAULT_MODE;
205 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
206 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
208 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
210 sisfb_mode_idx = DEFAULT_MODE;
214 if(strlen(name) <= 19) {
215 strcpy(strbuf1, name);
216 for(i=0; i<strlen(strbuf1); i++) {
217 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
220 /* This does some fuzzy mode naming detection */
221 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
222 if((rate <= 32) || (depth > 32)) {
223 j = rate; rate = depth; depth = j;
225 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
227 sisfb_parm_rate = rate;
228 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
229 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
233 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
234 sprintf(strbuf, "%ux%ux8", xres, yres);
237 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
244 while(sisbios_mode[i].mode_no[0] != 0) {
245 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
247 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
248 sisbios_mode[i-1].mode_no[1] == 0x56 ||
249 sisbios_mode[i-1].mode_no[1] == 0x53) continue;
251 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
252 sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
254 sisfb_mode_idx = i - 1;
259 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
263 static void __devinit
264 sisfb_get_vga_mode_from_kernel(void)
266 #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
268 int mydepth = screen_info.lfb_depth;
270 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
272 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
273 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
274 (mydepth >= 8) && (mydepth <= 32) ) {
276 if(mydepth == 24) mydepth = 32;
278 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
279 screen_info.lfb_height,
282 printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode);
284 sisfb_search_mode(mymode, TRUE);
292 sisfb_search_crt2type(const char *name)
296 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
298 if(name == NULL) return;
300 while(sis_crt2type[i].type_no != -1) {
301 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
302 sisfb_crt2type = sis_crt2type[i].type_no;
303 sisfb_tvplug = sis_crt2type[i].tvplug_no;
304 sisfb_crt2flags = sis_crt2type[i].flags;
310 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
311 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
313 if(sisfb_crt2type < 0) {
314 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
319 sisfb_search_tvstd(const char *name)
323 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
325 if(name == NULL) return;
327 while(sis_tvtype[i].type_no != -1) {
328 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
329 sisfb_tvstd = sis_tvtype[i].type_no;
337 sisfb_search_specialtiming(const char *name)
340 BOOLEAN found = FALSE;
342 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
344 if(name == NULL) return;
346 if(!strnicmp(name, "none", 4)) {
347 sisfb_specialtiming = CUT_FORCENONE;
348 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
350 while(mycustomttable[i].chipID != 0) {
351 if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {
352 sisfb_specialtiming = mycustomttable[i].SpecialID;
354 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
355 mycustomttable[i].vendorName, mycustomttable[i].cardName,
356 mycustomttable[i].optionName);
362 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
363 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
365 while(mycustomttable[i].chipID != 0) {
366 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
367 mycustomttable[i].optionName,
368 mycustomttable[i].vendorName,
369 mycustomttable[i].cardName);
376 static BOOLEAN __devinit
377 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
379 int i, j, xres, yres, refresh, index;
382 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
383 buffer[2] != 0xff || buffer[3] != 0xff ||
384 buffer[4] != 0xff || buffer[5] != 0xff ||
385 buffer[6] != 0xff || buffer[7] != 0x00) {
386 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
390 if(buffer[0x12] != 0x01) {
391 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
396 monitor->feature = buffer[0x18];
398 if(!buffer[0x14] & 0x80) {
399 if(!(buffer[0x14] & 0x08)) {
400 printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n");
404 if(buffer[0x13] >= 0x01) {
405 /* EDID V1 rev 1 and 2: Search for monitor descriptor
410 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
411 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
412 buffer[j + 4] == 0x00) {
413 monitor->hmin = buffer[j + 7];
414 monitor->hmax = buffer[j + 8];
415 monitor->vmin = buffer[j + 5];
416 monitor->vmax = buffer[j + 6];
417 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
418 monitor->datavalid = TRUE;
425 if(!monitor->datavalid) {
426 /* Otherwise: Get a range from the list of supported
427 * Estabished Timings. This is not entirely accurate,
428 * because fixed frequency monitors are not supported
431 monitor->hmin = 65535; monitor->hmax = 0;
432 monitor->vmin = 65535; monitor->vmax = 0;
433 monitor->dclockmax = 0;
434 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
435 for(i = 0; i < 13; i++) {
436 if(emodes & sisfb_ddcsmodes[i].mask) {
437 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
438 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
439 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
440 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
441 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
445 for(i = 0; i < 8; i++) {
446 xres = (buffer[index] + 31) * 8;
447 switch(buffer[index + 1] & 0xc0) {
448 case 0xc0: yres = (xres * 9) / 16; break;
449 case 0x80: yres = (xres * 4) / 5; break;
450 case 0x40: yres = (xres * 3) / 4; break;
451 default: yres = xres; break;
453 refresh = (buffer[index + 1] & 0x3f) + 60;
454 if((xres >= 640) && (yres >= 480)) {
455 for(j = 0; j < 8; j++) {
456 if((xres == sisfb_ddcfmodes[j].x) &&
457 (yres == sisfb_ddcfmodes[j].y) &&
458 (refresh == sisfb_ddcfmodes[j].v)) {
459 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
460 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
461 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
462 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
463 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
469 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
470 monitor->datavalid = TRUE;
474 return(monitor->datavalid);
477 static void __devinit
478 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
480 USHORT temp, i, realcrtno = crtno;
483 monitor->datavalid = FALSE;
486 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
487 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
491 if((ivideo->sisfb_crt1off) && (!crtno)) return;
493 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
494 realcrtno, 0, &buffer[0]);
495 if((!temp) || (temp == 0xffff)) {
496 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
499 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
500 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
502 (temp & 0x1a) ? "" : "[none of the supported]",
503 (temp & 0x02) ? "2 " : "",
504 (temp & 0x08) ? "D&P" : "",
505 (temp & 0x10) ? "FPDI-2" : "");
507 i = 3; /* Number of retrys */
509 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
510 realcrtno, 1, &buffer[0]);
511 } while((temp) && i--);
513 if(sisfb_interpret_edid(monitor, &buffer[0])) {
514 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
515 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
516 monitor->dclockmax / 1000);
518 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
521 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
524 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
530 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
531 int mode_idx, int rate_idx, int rate)
534 unsigned int dclock, hsync;
536 if(!monitor->datavalid) return TRUE;
538 if(mode_idx < 0) return FALSE;
540 /* Skip for 320x200, 320x240, 640x400 */
541 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
552 #ifdef CONFIG_FB_SIS_315
555 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
559 if(rate < (monitor->vmin - 1)) return FALSE;
560 if(rate > (monitor->vmax + 1)) return FALSE;
562 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, &ivideo->sishw_ext,
563 sisbios_mode[mode_idx].mode_no[ivideo->mni],
564 &htotal, &vtotal, rate_idx)) {
565 dclock = (htotal * vtotal * rate) / 1000;
566 if(dclock > (monitor->dclockmax + 1000)) return FALSE;
567 hsync = dclock / htotal;
568 if(hsync < (monitor->hmin - 1)) return FALSE;
569 if(hsync > (monitor->hmax + 1)) return FALSE;
577 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
579 u16 xres=0, yres, myres;
581 #ifdef CONFIG_FB_SIS_300
582 if(ivideo->sisvga_engine == SIS_300_VGA) {
583 if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1);
586 #ifdef CONFIG_FB_SIS_315
587 if(ivideo->sisvga_engine == SIS_315_VGA) {
588 if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1);
592 myres = sisbios_mode[myindex].yres;
594 switch(vbflags & VB_DISPTYPE_DISP2) {
598 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
600 if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) {
601 if(sisbios_mode[myindex].xres > xres) return(-1);
602 if(myres > yres) return(-1);
605 if(vbflags & (VB_LVDS | VB_30xBDH)) {
606 if(sisbios_mode[myindex].xres == 320) {
607 if((myres == 240) || (myres == 480)) {
608 if(!ivideo->sisfb_fstn) {
609 if(sisbios_mode[myindex].mode_no[1] == 0x5a ||
610 sisbios_mode[myindex].mode_no[1] == 0x5b)
613 if(sisbios_mode[myindex].mode_no[1] == 0x50 ||
614 sisbios_mode[myindex].mode_no[1] == 0x56 ||
615 sisbios_mode[myindex].mode_no[1] == 0x53)
622 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
623 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
624 ivideo->SiS_Pr.SiS_CustomT, xres, yres) < 0x14) {
630 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
631 sisbios_mode[myindex].yres, 0) < 0x14) {
637 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
638 sisbios_mode[myindex].yres, 0) < 0x14) {
648 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
653 xres = sisbios_mode[mode_idx].xres;
654 yres = sisbios_mode[mode_idx].yres;
656 ivideo->rate_idx = 0;
657 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
658 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
659 if(sisfb_vrate[i].refresh == rate) {
660 ivideo->rate_idx = sisfb_vrate[i].idx;
662 } else if(sisfb_vrate[i].refresh > rate) {
663 if((sisfb_vrate[i].refresh - rate) <= 3) {
664 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
665 rate, sisfb_vrate[i].refresh);
666 ivideo->rate_idx = sisfb_vrate[i].idx;
667 ivideo->refresh_rate = sisfb_vrate[i].refresh;
668 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
669 && (sisfb_vrate[i].idx != 1)) {
670 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
671 rate, sisfb_vrate[i-1].refresh);
672 ivideo->rate_idx = sisfb_vrate[i-1].idx;
673 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
676 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
677 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
678 rate, sisfb_vrate[i].refresh);
679 ivideo->rate_idx = sisfb_vrate[i].idx;
685 if(ivideo->rate_idx > 0) {
686 return ivideo->rate_idx;
688 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
695 sisfb_bridgeisslave(struct sis_video_info *ivideo)
699 if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE;
701 inSISIDXREG(SISPART1,0x00,P1_00);
702 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
703 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
711 sisfballowretracecrt1(struct sis_video_info *ivideo)
715 inSISIDXREG(SISCR,0x17,temp);
716 if(!(temp & 0x80)) return FALSE;
718 inSISIDXREG(SISSR,0x1f,temp);
719 if(temp & 0xc0) return FALSE;
725 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
727 if(!sisfballowretracecrt1(ivideo)) return FALSE;
729 if(inSISREG(SISINPSTAT) & 0x08) return TRUE;
734 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
738 if(!sisfballowretracecrt1(ivideo)) return;
741 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
743 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
747 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
749 unsigned char temp, reg;
751 switch(ivideo->sisvga_engine) {
752 case SIS_300_VGA: reg = 0x25; break;
753 case SIS_315_VGA: reg = 0x30; break;
754 default: return FALSE;
757 inSISIDXREG(SISPART1, reg, temp);
758 if(temp & 0x02) return TRUE;
763 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
765 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
766 if(sisfb_bridgeisslave(ivideo)) {
767 return(sisfbcheckvretracecrt1(ivideo));
769 return(sisfbcheckvretracecrt2(ivideo));
772 return(sisfbcheckvretracecrt1(ivideo));
776 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
778 u8 idx, reg1, reg2, reg3, reg4;
781 (*vcount) = (*hcount) = 0;
783 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
784 ret |= (FB_VBLANK_HAVE_VSYNC |
785 FB_VBLANK_HAVE_HBLANK |
786 FB_VBLANK_HAVE_VBLANK |
787 FB_VBLANK_HAVE_VCOUNT |
788 FB_VBLANK_HAVE_HCOUNT);
789 switch(ivideo->sisvga_engine) {
790 case SIS_300_VGA: idx = 0x25; break;
792 case SIS_315_VGA: idx = 0x30; break;
794 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
795 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
796 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
797 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
798 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
799 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
800 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
801 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
802 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
803 } else if(sisfballowretracecrt1(ivideo)) {
804 ret |= (FB_VBLANK_HAVE_VSYNC |
805 FB_VBLANK_HAVE_VBLANK |
806 FB_VBLANK_HAVE_VCOUNT |
807 FB_VBLANK_HAVE_HCOUNT);
808 reg1 = inSISREG(SISINPSTAT);
809 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
810 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
811 inSISIDXREG(SISCR,0x20,reg1);
812 inSISIDXREG(SISCR,0x1b,reg1);
813 inSISIDXREG(SISCR,0x1c,reg2);
814 inSISIDXREG(SISCR,0x1d,reg3);
815 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
816 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
822 sisfb_myblank(struct sis_video_info *ivideo, int blank)
824 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
825 BOOLEAN backlight = TRUE;
828 case FB_BLANK_UNBLANK: /* on */
837 case FB_BLANK_NORMAL: /* blank */
846 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
855 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
864 case FB_BLANK_POWERDOWN: /* off */
877 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
879 if( (!ivideo->sisfb_thismonitor.datavalid) ||
880 ((ivideo->sisfb_thismonitor.datavalid) &&
881 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
883 if(ivideo->sisvga_engine == SIS_315_VGA) {
884 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
887 if(!(sisfb_bridgeisslave(ivideo))) {
888 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
889 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
895 if(ivideo->currentvbflags & CRT2_LCD) {
897 if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
899 SiS_SiS30xBLOn(&ivideo->SiS_Pr, &ivideo->sishw_ext);
901 SiS_SiS30xBLOff(&ivideo->SiS_Pr, &ivideo->sishw_ext);
903 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
904 if(ivideo->vbflags & VB_CHRONTEL) {
906 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr,&ivideo->sishw_ext);
908 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
913 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
914 (ivideo->vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
915 ((ivideo->sisvga_engine == SIS_315_VGA) &&
916 ((ivideo->vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
917 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
920 if(ivideo->sisvga_engine == SIS_300_VGA) {
921 if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
922 (!(ivideo->vbflags & VB_30xBDH))) {
923 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
925 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
926 if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
927 (!(ivideo->vbflags & VB_30xBDH))) {
928 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
932 } else if(ivideo->currentvbflags & CRT2_VGA) {
934 if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) {
935 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
943 /* ----------- FBDev related routines for all series ----------- */
946 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
948 return (var->bits_per_pixel == 8) ? 256 : 16;
952 sisfb_set_vparms(struct sis_video_info *ivideo)
954 switch(ivideo->video_bpp) {
956 ivideo->DstColor = 0x0000;
957 ivideo->SiS310_AccelDepth = 0x00000000;
958 ivideo->video_cmap_len = 256;
961 ivideo->DstColor = 0x8000;
962 ivideo->SiS310_AccelDepth = 0x00010000;
963 ivideo->video_cmap_len = 16;
966 ivideo->DstColor = 0xC000;
967 ivideo->SiS310_AccelDepth = 0x00020000;
968 ivideo->video_cmap_len = 16;
971 ivideo->video_cmap_len = 16;
972 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
979 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
981 int maxyres = ivideo->heapstart / (var->xres_virtual * (var->bits_per_pixel >> 3));
983 if(maxyres > 32767) maxyres = 32767;
989 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
991 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
992 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
993 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
994 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
995 ivideo->scrnpitchCRT1 <<= 1;
1002 sisfb_set_pitch(struct sis_video_info *ivideo)
1004 BOOLEAN isslavemode = FALSE;
1005 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1006 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1008 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
1010 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1011 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1012 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1013 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1016 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1017 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1018 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1019 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1020 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1025 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1027 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1029 switch(var->bits_per_pixel) {
1031 var->red.offset = var->green.offset = var->blue.offset = 0;
1032 var->red.length = var->green.length = var->blue.length = 6;
1035 var->red.offset = 11;
1036 var->red.length = 5;
1037 var->green.offset = 5;
1038 var->green.length = 6;
1039 var->blue.offset = 0;
1040 var->blue.length = 5;
1041 var->transp.offset = 0;
1042 var->transp.length = 0;
1045 var->red.offset = 16;
1046 var->red.length = 8;
1047 var->green.offset = 8;
1048 var->green.length = 8;
1049 var->blue.offset = 0;
1050 var->blue.length = 8;
1051 var->transp.offset = 24;
1052 var->transp.length = 8;
1058 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1060 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1061 unsigned int htotal = 0, vtotal = 0;
1062 unsigned int drate = 0, hrate = 0;
1067 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1069 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1071 pixclock = var->pixclock;
1073 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1074 vtotal += var->yres;
1076 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1077 vtotal += var->yres;
1079 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1080 vtotal += var->yres;
1082 } else vtotal += var->yres;
1084 if(!(htotal) || !(vtotal)) {
1085 DPRINTK("sisfb: Invalid 'var' information\n");
1089 if(pixclock && htotal && vtotal) {
1090 drate = 1000000000 / pixclock;
1091 hrate = (drate * 1000) / htotal;
1092 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1094 ivideo->refresh_rate = 60;
1097 old_mode = ivideo->sisfb_mode_idx;
1098 ivideo->sisfb_mode_idx = 0;
1100 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1101 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1102 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1103 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1104 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1105 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1109 ivideo->sisfb_mode_idx++;
1113 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1114 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1116 ivideo->sisfb_mode_idx = -1;
1119 if(ivideo->sisfb_mode_idx < 0) {
1120 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1121 var->yres, var->bits_per_pixel);
1122 ivideo->sisfb_mode_idx = old_mode;
1126 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1127 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1128 ivideo->refresh_rate = 60;
1131 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1132 if(ivideo->sisfb_thismonitor.datavalid) {
1133 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
1134 ivideo->rate_idx, ivideo->refresh_rate)) {
1135 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1140 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1141 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1145 sisfb_pre_setmode(ivideo);
1147 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
1148 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1152 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1154 sisfb_post_setmode(ivideo);
1156 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1157 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1158 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1160 sisfb_calc_pitch(ivideo, var);
1161 sisfb_set_pitch(ivideo);
1164 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1165 #ifdef STUPID_ACCELF_TEXT_SHIT
1166 if(var->accel_flags & FB_ACCELF_TEXT) {
1167 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1169 info->flags |= FBINFO_HWACCEL_DISABLED;
1172 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1174 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1177 sisfb_set_vparms(ivideo);
1179 ivideo->current_width = ivideo->video_width;
1180 ivideo->current_height = ivideo->video_height;
1181 ivideo->current_bpp = ivideo->video_bpp;
1182 ivideo->current_htotal = htotal;
1183 ivideo->current_vtotal = vtotal;
1184 ivideo->current_linelength = ivideo->video_linelength;
1185 ivideo->current_pixclock = var->pixclock;
1186 ivideo->current_refresh_rate = ivideo->refresh_rate;
1187 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1188 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1196 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1200 if(var->xoffset > (var->xres_virtual - var->xres)) {
1203 if(var->yoffset > (var->yres_virtual - var->yres)) {
1207 base = (var->yoffset * var->xres_virtual) + var->xoffset;
1209 /* calculate base bpp dep. */
1210 switch(var->bits_per_pixel) {
1222 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1224 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1225 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1226 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1227 if(ivideo->sisvga_engine == SIS_315_VGA) {
1228 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1230 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1231 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1232 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1233 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1234 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1235 if(ivideo->sisvga_engine == SIS_315_VGA) {
1236 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1242 /* ------------ FBDev related routines for 2.4 series ----------- */
1244 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1247 sisfb_crtc_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1249 u16 VRE, VBE, VRS, VBS, VDE, VT;
1250 u16 HRE, HBE, HRS, HBS, HDE, HT;
1251 u8 sr_data, cr_data, cr_data2, cr_data3, mr_data;
1252 int A, B, C, D, E, F, temp;
1253 unsigned int hrate, drate, maxyres;
1255 inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
1257 if(sr_data & SIS_INTERLACED_MODE)
1258 var->vmode = FB_VMODE_INTERLACED;
1260 var->vmode = FB_VMODE_NONINTERLACED;
1262 switch((sr_data & 0x1C) >> 2) {
1263 case SIS_8BPP_COLOR_MODE:
1264 var->bits_per_pixel = 8;
1266 case SIS_16BPP_COLOR_MODE:
1267 var->bits_per_pixel = 16;
1269 case SIS_32BPP_COLOR_MODE:
1270 var->bits_per_pixel = 32;
1274 sisfb_bpp_to_var(ivideo, var);
1276 inSISIDXREG(SISSR, 0x0A, sr_data);
1277 inSISIDXREG(SISCR, 0x06, cr_data);
1278 inSISIDXREG(SISCR, 0x07, cr_data2);
1280 VT = (cr_data & 0xFF) |
1281 ((u16) (cr_data2 & 0x01) << 8) |
1282 ((u16) (cr_data2 & 0x20) << 4) |
1283 ((u16) (sr_data & 0x01) << 10);
1286 inSISIDXREG(SISCR, 0x12, cr_data);
1288 VDE = (cr_data & 0xff) |
1289 ((u16) (cr_data2 & 0x02) << 7) |
1290 ((u16) (cr_data2 & 0x40) << 3) |
1291 ((u16) (sr_data & 0x02) << 9);
1294 inSISIDXREG(SISCR, 0x10, cr_data);
1296 VRS = (cr_data & 0xff) |
1297 ((u16) (cr_data2 & 0x04) << 6) |
1298 ((u16) (cr_data2 & 0x80) << 2) |
1299 ((u16) (sr_data & 0x08) << 7);
1302 inSISIDXREG(SISCR, 0x15, cr_data);
1303 inSISIDXREG(SISCR, 0x09, cr_data3);
1305 if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE;
1307 VBS = (cr_data & 0xff) |
1308 ((u16) (cr_data2 & 0x08) << 5) |
1309 ((u16) (cr_data3 & 0x20) << 4) |
1310 ((u16) (sr_data & 0x04) << 8);
1312 inSISIDXREG(SISCR, 0x16, cr_data);
1314 VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
1315 temp = VBE - ((E - 1) & 511);
1316 B = (temp > 0) ? temp : (temp + 512);
1318 inSISIDXREG(SISCR, 0x11, cr_data);
1320 VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
1321 temp = VRE - ((E + F - 1) & 31);
1322 C = (temp > 0) ? temp : (temp + 32);
1327 var->upper_margin = D;
1328 var->lower_margin = F;
1331 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1333 var->upper_margin <<= 1;
1334 var->lower_margin <<= 1;
1335 var->vsync_len <<= 1;
1336 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1338 var->upper_margin >>= 1;
1339 var->lower_margin >>= 1;
1340 var->vsync_len >>= 1;
1343 inSISIDXREG(SISSR, 0x0b, sr_data);
1344 inSISIDXREG(SISCR, 0x00, cr_data);
1346 HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
1349 inSISIDXREG(SISCR, 0x01, cr_data);
1351 HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
1354 inSISIDXREG(SISCR, 0x04, cr_data);
1356 HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
1359 inSISIDXREG(SISCR, 0x02, cr_data);
1361 HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
1363 inSISIDXREG(SISSR, 0x0c, sr_data);
1364 inSISIDXREG(SISCR, 0x03, cr_data);
1365 inSISIDXREG(SISCR, 0x05, cr_data2);
1367 HBE = (cr_data & 0x1f) |
1368 ((u16) (cr_data2 & 0x80) >> 2) |
1369 ((u16) (sr_data & 0x03) << 6);
1370 HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
1372 temp = HBE - ((E - 1) & 255);
1373 B = (temp > 0) ? temp : (temp + 256);
1375 temp = HRE - ((E + F + 3) & 63);
1376 C = (temp > 0) ? temp : (temp + 64);
1381 if(var->xres_virtual < var->xres) {
1382 var->xres_virtual = var->xres;
1385 if((var->xres == 320) &&
1386 (var->yres == 200 || var->yres == 240)) {
1387 /* Terrible hack, but the correct CRTC data for
1388 * these modes only produces a black screen...
1390 var->left_margin = (400 - 376);
1391 var->right_margin = (328 - 320);
1392 var->hsync_len = (376 - 328);
1394 var->left_margin = D * 8;
1395 var->right_margin = F * 8;
1396 var->hsync_len = C * 8;
1398 var->activate = FB_ACTIVATE_NOW;
1402 mr_data = inSISREG(SISMISCR);
1404 var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
1406 var->sync |= FB_SYNC_VERT_HIGH_ACT;
1409 var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
1411 var->sync |= FB_SYNC_HOR_HIGH_ACT;
1417 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1420 hrate = ivideo->refresh_rate * VT / 2;
1421 drate = (hrate * HT) / 1000;
1422 var->pixclock = (u32) (1000000000 / drate);
1424 if(ivideo->sisfb_ypan) {
1425 maxyres = sisfb_calc_maxyres(ivideo, var);
1426 if(ivideo->sisfb_max) {
1427 var->yres_virtual = maxyres;
1429 if(var->yres_virtual > maxyres) {
1430 var->yres_virtual = maxyres;
1433 if(var->yres_virtual <= var->yres) {
1434 var->yres_virtual = var->yres;
1437 var->yres_virtual = var->yres;
1443 sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
1444 unsigned *transp, struct fb_info *info)
1446 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1448 if(regno >= ivideo->video_cmap_len) return 1;
1450 *red = ivideo->sis_palette[regno].red;
1451 *green = ivideo->sis_palette[regno].green;
1452 *blue = ivideo->sis_palette[regno].blue;
1459 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1460 unsigned transp, struct fb_info *info)
1462 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1464 if(regno >= ivideo->video_cmap_len) return 1;
1466 ivideo->sis_palette[regno].red = red;
1467 ivideo->sis_palette[regno].green = green;
1468 ivideo->sis_palette[regno].blue = blue;
1470 switch(ivideo->video_bpp) {
1471 #ifdef FBCON_HAS_CFB8
1473 outSISREG(SISDACA, regno);
1474 outSISREG(SISDACD, (red >> 10));
1475 outSISREG(SISDACD, (green >> 10));
1476 outSISREG(SISDACD, (blue >> 10));
1477 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1478 outSISREG(SISDAC2A, regno);
1479 outSISREG(SISDAC2D, (red >> 8));
1480 outSISREG(SISDAC2D, (green >> 8));
1481 outSISREG(SISDAC2D, (blue >> 8));
1485 #ifdef FBCON_HAS_CFB16
1487 ivideo->sis_fbcon_cmap.cfb16[regno] =
1488 ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1491 #ifdef FBCON_HAS_CFB32
1496 ivideo->sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
1505 sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info)
1507 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1508 struct display *display;
1509 struct display_switch *sw;
1510 struct fb_fix_screeninfo fix;
1513 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1515 sisfb_get_fix(&fix, con, info);
1517 display->var = *var;
1518 display->screen_base = (char *)ivideo->video_vbase;
1519 display->visual = fix.visual;
1520 display->type = fix.type;
1521 display->type_aux = fix.type_aux;
1522 display->ypanstep = fix.ypanstep;
1523 display->ywrapstep = fix.ywrapstep;
1524 display->line_length = fix.line_length;
1525 display->can_soft_blank = 1;
1526 display->inverse = ivideo->sisfb_inverse;
1527 display->next_line = fix.line_length;
1531 switch(ivideo->video_bpp) {
1532 #ifdef FBCON_HAS_CFB8
1533 case 8: sw = ivideo->accel ? &fbcon_sis8 : &fbcon_cfb8;
1536 #ifdef FBCON_HAS_CFB16
1537 case 16:sw = ivideo->accel ? &fbcon_sis16 : &fbcon_cfb16;
1538 display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb16;
1541 #ifdef FBCON_HAS_CFB32
1542 case 32:sw = ivideo->accel ? &fbcon_sis32 : &fbcon_cfb32;
1543 display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb32;
1546 default:sw = &fbcon_dummy;
1549 memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw));
1550 display->dispsw = &ivideo->sisfb_sw;
1552 restore_flags(flags);
1554 if(ivideo->sisfb_ypan) {
1555 /* display->scrollmode = 0; */
1557 display->scrollmode = SCROLL_YREDRAW;
1558 ivideo->sisfb_sw.bmove = fbcon_redraw_bmove;
1563 sisfb_do_install_cmap(int con, struct fb_info *info)
1565 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1567 if(con != ivideo->currcon) return;
1569 if(fb_display[con].cmap.len) {
1570 fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
1572 int size = sisfb_get_cmap_len(&fb_display[con].var);
1573 fb_set_cmap(fb_default_cmap(size), 1, sisfb_setcolreg, info);
1578 sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1580 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1583 memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo));
1585 *var = fb_display[con].var;
1588 if(ivideo->sisfb_fstn) {
1589 if(var->xres == 320 && var->yres == 480) var->yres = 240;
1596 sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1598 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1601 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1603 if(sisfb_do_set_var(var, con == ivideo->currcon, info)) {
1604 sisfb_crtc_to_var(ivideo, var);
1608 sisfb_crtc_to_var(ivideo, var);
1610 sisfb_set_disp(con, var, info);
1612 if(info->changevar) {
1613 (*info->changevar)(con);
1616 if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) {
1620 sisfb_do_install_cmap(con, info);
1622 #if 0 /* Why was this called here? */
1623 unsigned int cols, rows;
1624 cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
1625 rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
1626 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1632 sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1634 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1635 struct display *display;
1637 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1639 if(con == ivideo->currcon) {
1641 return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
1643 } else if(display->cmap.len) {
1645 fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2);
1649 int size = sisfb_get_cmap_len(&display->var);
1650 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
1658 sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1660 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1661 struct display *display;
1664 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1666 size = sisfb_get_cmap_len(&display->var);
1667 if(display->cmap.len != size) {
1668 err = fb_alloc_cmap(&display->cmap, size, 0);
1672 if(con == ivideo->currcon) {
1673 return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
1675 fb_copy_cmap(cmap, &display->cmap, kspc ? 0 : 1);
1682 sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info)
1684 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1687 if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
1689 if((var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual) ||
1690 (var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)) {
1694 if(con == ivideo->currcon) {
1695 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
1698 fb_display[con].var.xoffset = var->xoffset;
1699 fb_display[con].var.yoffset = var->yoffset;
1705 sisfb_update_var(int con, struct fb_info *info)
1707 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1709 return(sisfb_pan_var(ivideo, &fb_display[con].var));
1713 sisfb_switch(int con, struct fb_info *info)
1715 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1718 if(fb_display[ivideo->currcon].cmap.len) {
1719 fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info);
1722 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1724 if(!memcmp(&fb_display[con].var, &fb_display[ivideo->currcon].var,
1725 sizeof(struct fb_var_screeninfo))) {
1726 ivideo->currcon = con;
1730 ivideo->currcon = con;
1732 sisfb_do_set_var(&fb_display[con].var, 1, info);
1734 sisfb_set_disp(con, &fb_display[con].var, info);
1736 sisfb_do_install_cmap(con, info);
1738 cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
1739 rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
1740 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1742 sisfb_update_var(con, info);
1748 sisfb_blank(int blank, struct fb_info *info)
1750 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1752 sisfb_myblank(ivideo, blank);
1756 /* ------------ FBDev related routines for 2.6 series ----------- */
1758 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1761 sisfb_open(struct fb_info *info, int user)
1767 sisfb_release(struct fb_info *info, int user)
1773 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1774 unsigned transp, struct fb_info *info)
1776 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1778 if(regno >= sisfb_get_cmap_len(&info->var)) return 1;
1780 switch(info->var.bits_per_pixel) {
1782 outSISREG(SISDACA, regno);
1783 outSISREG(SISDACD, (red >> 10));
1784 outSISREG(SISDACD, (green >> 10));
1785 outSISREG(SISDACD, (blue >> 10));
1786 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1787 outSISREG(SISDAC2A, regno);
1788 outSISREG(SISDAC2D, (red >> 8));
1789 outSISREG(SISDAC2D, (green >> 8));
1790 outSISREG(SISDAC2D, (blue >> 8));
1794 ((u32 *)(info->pseudo_palette))[regno] =
1795 ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1801 ((u32 *)(info->pseudo_palette))[regno] =
1802 (red << 16) | (green << 8) | (blue);
1809 sisfb_set_par(struct fb_info *info)
1813 if((err = sisfb_do_set_var(&info->var, 1, info))) {
1816 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1817 sisfb_get_fix(&info->fix, info->currcon, info);
1819 sisfb_get_fix(&info->fix, -1, info);
1825 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1827 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1828 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1829 unsigned int drate = 0, hrate = 0, maxyres;
1831 int refresh_rate, search_idx;
1832 BOOLEAN recalc_clock = FALSE;
1835 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1837 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1839 pixclock = var->pixclock;
1841 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1842 vtotal += var->yres;
1844 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1845 vtotal += var->yres;
1847 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1848 vtotal += var->yres;
1850 } else vtotal += var->yres;
1852 if(!(htotal) || !(vtotal)) {
1853 SISFAIL("sisfb: no valid timing data");
1857 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1858 (sisbios_mode[search_idx].xres <= var->xres) ) {
1859 if( (sisbios_mode[search_idx].xres == var->xres) &&
1860 (sisbios_mode[search_idx].yres == var->yres) &&
1861 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1862 if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) {
1872 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1873 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1874 (var->yres <= sisbios_mode[search_idx].yres) &&
1875 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1876 if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) {
1884 printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1885 var->xres, var->yres, var->bits_per_pixel,
1886 sisbios_mode[search_idx].xres,
1887 sisbios_mode[search_idx].yres,
1888 var->bits_per_pixel);
1889 var->xres = sisbios_mode[search_idx].xres;
1890 var->yres = sisbios_mode[search_idx].yres;
1894 printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n",
1895 var->xres, var->yres, var->bits_per_pixel);
1900 if( ((ivideo->vbflags & VB_LVDS) || /* Slave modes on LVDS and 301B-DH */
1901 ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1902 (var->bits_per_pixel == 8) ) {
1904 recalc_clock = TRUE;
1905 } else if( (ivideo->current_htotal == htotal) && /* x=x & y=y & c=c -> assume depth change */
1906 (ivideo->current_vtotal == vtotal) &&
1907 (ivideo->current_pixclock == pixclock) ) {
1908 drate = 1000000000 / pixclock;
1909 hrate = (drate * 1000) / htotal;
1910 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1911 } else if( ( (ivideo->current_htotal != htotal) || /* x!=x | y!=y & c=c -> invalid pixclock */
1912 (ivideo->current_vtotal != vtotal) ) &&
1913 (ivideo->current_pixclock == var->pixclock) ) {
1914 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1915 refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1916 } else if(ivideo->sisfb_parm_rate != -1) {
1917 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1918 refresh_rate = ivideo->sisfb_parm_rate;
1922 recalc_clock = TRUE;
1923 } else if((pixclock) && (htotal) && (vtotal)) {
1924 drate = 1000000000 / pixclock;
1925 hrate = (drate * 1000) / htotal;
1926 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1927 } else if(ivideo->current_refresh_rate) {
1928 refresh_rate = ivideo->current_refresh_rate;
1929 recalc_clock = TRUE;
1932 recalc_clock = TRUE;
1935 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1937 /* Eventually recalculate timing and clock */
1939 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1940 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1942 sisbios_mode[search_idx].mode_no[ivideo->mni],
1944 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
1945 sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex, var);
1946 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1947 var->pixclock <<= 1;
1951 if(ivideo->sisfb_thismonitor.datavalid) {
1952 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1953 myrateindex, refresh_rate)) {
1954 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1958 /* Adapt RGB settings */
1959 sisfb_bpp_to_var(ivideo, var);
1961 /* Sanity check for offsets */
1962 if(var->xoffset < 0) var->xoffset = 0;
1963 if(var->yoffset < 0) var->yoffset = 0;
1965 if(var->xres > var->xres_virtual) {
1966 var->xres_virtual = var->xres;
1969 if(ivideo->sisfb_ypan) {
1970 maxyres = sisfb_calc_maxyres(ivideo, var);
1971 if(ivideo->sisfb_max) {
1972 var->yres_virtual = maxyres;
1974 if(var->yres_virtual > maxyres) {
1975 var->yres_virtual = maxyres;
1978 if(var->yres_virtual <= var->yres) {
1979 var->yres_virtual = var->yres;
1982 if(var->yres != var->yres_virtual) {
1983 var->yres_virtual = var->yres;
1989 /* Truncate offsets to maximum if too high */
1990 if(var->xoffset > var->xres_virtual - var->xres) {
1991 var->xoffset = var->xres_virtual - var->xres - 1;
1994 if(var->yoffset > var->yres_virtual - var->yres) {
1995 var->yoffset = var->yres_virtual - var->yres - 1;
1998 /* Set everything else to 0 */
1999 var->red.msb_right =
2000 var->green.msb_right =
2001 var->blue.msb_right =
2002 var->transp.offset =
2003 var->transp.length =
2004 var->transp.msb_right = 0;
2010 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
2012 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2015 if(var->xoffset > (var->xres_virtual - var->xres)) {
2018 if(var->yoffset > (var->yres_virtual - var->yres)) {
2022 if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
2024 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
2025 var->yoffset + info->var.yres > info->var.yres_virtual) {
2029 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
2031 info->var.xoffset = var->xoffset;
2032 info->var.yoffset = var->yoffset;
2038 sisfb_blank(int blank, struct fb_info *info)
2040 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2042 return(sisfb_myblank(ivideo, blank));
2047 /* ----------- FBDev related routines for all series ---------- */
2050 sisfb_ioctl(struct inode *inode, struct file *file,
2051 unsigned int cmd, unsigned long arg,
2052 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2055 struct fb_info *info)
2057 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2058 struct sis_memreq sismemreq;
2059 struct fb_vblank sisvbblank;
2065 u32 __user *argp = (u32 __user *)arg;
2069 if(!capable(CAP_SYS_RAWIO)) {
2072 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq))) {
2075 sis_malloc(&sismemreq);
2076 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
2077 sis_free((u32)sismemreq.offset);
2083 if(!capable(CAP_SYS_RAWIO)) {
2086 if(get_user(gpu32, argp)) {
2092 case FBIOGET_VBLANK:
2093 sisvbblank.count = 0;
2094 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
2095 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank))) {
2100 case SISFB_GET_INFO_SIZE:
2101 return put_user(sizeof(sisfb_info), argp);
2103 case SISFB_GET_INFO_OLD:
2104 if(ivideo->warncount++ < 50) {
2105 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2107 case SISFB_GET_INFO: /* For communication with X driver */
2108 x.sisfb_id = SISFB_ID;
2109 x.sisfb_version = VER_MAJOR;
2110 x.sisfb_revision = VER_MINOR;
2111 x.sisfb_patchlevel = VER_LEVEL;
2112 x.chip_id = ivideo->chip_id;
2113 x.memory = ivideo->video_size / 1024;
2114 x.heapstart = ivideo->heapstart / 1024;
2115 if(ivideo->modechanged) {
2116 x.fbvidmode = ivideo->mode_no;
2118 x.fbvidmode = ivideo->modeprechange;
2120 x.sisfb_caps = ivideo->caps;
2121 x.sisfb_tqlen = 512; /* yet fixed */
2122 x.sisfb_pcibus = ivideo->pcibus;
2123 x.sisfb_pcislot = ivideo->pcislot;
2124 x.sisfb_pcifunc = ivideo->pcifunc;
2125 x.sisfb_lcdpdc = ivideo->detectedpdc;
2126 x.sisfb_lcdpdca = ivideo->detectedpdca;
2127 x.sisfb_lcda = ivideo->detectedlcda;
2128 x.sisfb_vbflags = ivideo->vbflags;
2129 x.sisfb_currentvbflags = ivideo->currentvbflags;
2130 x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
2131 x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
2132 x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
2133 x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
2134 x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
2135 x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
2136 x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
2137 x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
2138 x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
2139 x.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
2141 if(copy_to_user((void __user *)arg, &x, sizeof(x))) {
2146 case SISFB_GET_VBRSTATUS_OLD:
2147 if(ivideo->warncount++ < 50) {
2148 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2150 case SISFB_GET_VBRSTATUS:
2151 if(sisfb_CheckVBRetrace(ivideo)) {
2152 return put_user((u32)1, argp);
2154 return put_user((u32)0, argp);
2157 case SISFB_GET_AUTOMAXIMIZE_OLD:
2158 if(ivideo->warncount++ < 50) {
2159 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2161 case SISFB_GET_AUTOMAXIMIZE:
2162 if(ivideo->sisfb_max) return put_user((u32)1, argp);
2163 else return put_user((u32)0, argp);
2165 case SISFB_SET_AUTOMAXIMIZE_OLD:
2166 if(ivideo->warncount++ < 50) {
2167 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2169 case SISFB_SET_AUTOMAXIMIZE:
2170 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2173 ivideo->sisfb_max = (gpu32) ? 1 : 0;
2176 case SISFB_SET_TVPOSOFFSET:
2177 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2180 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
2181 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
2184 case SISFB_GET_TVPOSOFFSET:
2185 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
2188 case SISFB_SET_LOCK:
2189 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2192 ivideo->sisfblocked = (gpu32) ? 1 : 0;
2196 return -ENOIOCTLCMD;
2201 #ifdef CONFIG_COMPAT
2202 static long sisfb_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg, struct fb_info *info)
2206 ret = sisfb_ioctl(NULL, f, cmd, arg, info);
2213 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
2215 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2217 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2219 strcpy(fix->id, ivideo->myid);
2221 fix->smem_start = ivideo->video_base;
2222 fix->smem_len = ivideo->sisfb_mem;
2223 fix->type = FB_TYPE_PACKED_PIXELS;
2225 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
2227 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
2229 fix->line_length = ivideo->video_linelength;
2230 fix->mmio_start = ivideo->mmio_base;
2231 fix->mmio_len = ivideo->mmio_size;
2232 if(ivideo->sisvga_engine == SIS_300_VGA) {
2233 fix->accel = FB_ACCEL_SIS_GLAMOUR;
2234 } else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) {
2235 fix->accel = FB_ACCEL_SIS_XABRE;
2237 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
2243 /* ---------------- fb_ops structures ----------------- */
2245 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2246 static struct fb_ops sisfb_ops = {
2247 .owner = THIS_MODULE,
2248 .fb_get_fix = sisfb_get_fix,
2249 .fb_get_var = sisfb_get_var,
2250 .fb_set_var = sisfb_set_var,
2251 .fb_get_cmap = sisfb_get_cmap,
2252 .fb_set_cmap = sisfb_set_cmap,
2253 .fb_pan_display = sisfb_pan_display,
2254 .fb_ioctl = sisfb_ioctl
2258 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
2259 static struct fb_ops sisfb_ops = {
2260 .owner = THIS_MODULE,
2261 .fb_open = sisfb_open,
2262 .fb_release = sisfb_release,
2263 .fb_check_var = sisfb_check_var,
2264 .fb_set_par = sisfb_set_par,
2265 .fb_setcolreg = sisfb_setcolreg,
2266 .fb_pan_display = sisfb_pan_display,
2267 .fb_blank = sisfb_blank,
2268 .fb_fillrect = fbcon_sis_fillrect,
2269 .fb_copyarea = fbcon_sis_copyarea,
2270 .fb_imageblit = cfb_imageblit,
2271 .fb_cursor = soft_cursor,
2272 .fb_sync = fbcon_sis_sync,
2273 .fb_ioctl = sisfb_ioctl,
2274 #ifdef CONFIG_COMPAT
2275 .fb_compat_ioctl = sisfb_compat_ioctl,
2280 /* ---------------- Chip generation dependent routines ---------------- */
2282 static struct pci_dev * sisfb_get_northbridge(int basechipid)
2284 struct pci_dev *pdev = NULL;
2285 int nbridgenum, nbridgeidx, i;
2286 const unsigned short nbridgeids[] = {
2287 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2288 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2289 PCI_DEVICE_ID_SI_730,
2290 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2291 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2292 PCI_DEVICE_ID_SI_651,
2293 PCI_DEVICE_ID_SI_740,
2294 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760 VGA */
2295 PCI_DEVICE_ID_SI_741,
2296 PCI_DEVICE_ID_SI_660,
2297 PCI_DEVICE_ID_SI_760
2300 switch(basechipid) {
2301 #ifdef CONFIG_FB_SIS_300
2302 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2303 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2305 #ifdef CONFIG_FB_SIS_315
2306 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2307 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
2308 case SIS_660: nbridgeidx = 7; nbridgenum = 4; break;
2310 default: return NULL;
2312 for(i = 0; i < nbridgenum; i++) {
2313 if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break;
2318 static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
2320 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2324 ivideo->video_size = 0;
2326 switch(ivideo->chip) {
2327 #ifdef CONFIG_FB_SIS_300
2329 inSISIDXREG(SISSR, 0x14, reg);
2330 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2335 if(!ivideo->nbridge) return -1;
2336 pci_read_config_byte(ivideo->nbridge, 0x63, ®);
2337 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2340 #ifdef CONFIG_FB_SIS_315
2344 inSISIDXREG(SISSR, 0x14, reg);
2345 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2346 switch((reg >> 2) & 0x03) {
2349 ivideo->video_size <<= 1;
2352 ivideo->video_size += (ivideo->video_size/2);
2356 inSISIDXREG(SISSR, 0x14, reg);
2357 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2358 if(reg & 0x0c) ivideo->video_size <<= 1;
2363 inSISIDXREG(SISSR, 0x14, reg);
2364 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2368 inSISIDXREG(SISCR, 0x79, reg);
2369 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2373 inSISIDXREG(SISCR, 0x79, reg);
2374 reg = (reg & 0xf0) >> 4;
2375 if(reg) ivideo->video_size = (1 << reg) << 20;
2376 inSISIDXREG(SISCR, 0x78, reg);
2379 if(reg == 0x10) ivideo->video_size += (32 << 20);
2380 else ivideo->video_size += (64 << 20);
2390 /* -------------- video bridge device detection --------------- */
2392 static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2396 #ifdef CONFIG_FB_SIS_300
2397 if(ivideo->sisvga_engine == SIS_300_VGA) {
2398 inSISIDXREG(SISSR, 0x17, temp);
2399 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2400 /* PAL/NTSC is stored on SR16 on such machines */
2401 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2402 inSISIDXREG(SISSR, 0x16, temp);
2404 ivideo->vbflags |= TV_PAL;
2406 ivideo->vbflags |= TV_NTSC;
2412 inSISIDXREG(SISCR, 0x32, cr32);
2414 if(cr32 & SIS_CRT1) {
2415 ivideo->sisfb_crt1off = 0;
2417 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2420 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2422 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2423 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2424 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2426 /* Check given parms for hardware compatibility.
2427 * (Cannot do this in the search_xx routines since we don't
2428 * know what hardware we are running on then)
2431 if(ivideo->chip != SIS_550) {
2432 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2435 if(ivideo->sisfb_tvplug != -1) {
2436 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2437 (!(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) ) {
2438 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2439 ivideo->sisfb_tvplug = -1;
2440 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2444 if(ivideo->sisfb_tvplug != -1) {
2445 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2446 (!(ivideo->vbflags & (VB_301|VB_301B|VB_302B))) ) {
2447 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2448 ivideo->sisfb_tvplug = -1;
2449 printk(KERN_ERR "sisfb: HiVision not supported\n");
2453 if(ivideo->sisfb_tvstd != -1) {
2454 if( (!(ivideo->vbflags & VB_SISBRIDGE)) &&
2455 (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags & VB_CHRONTEL))) ) {
2456 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2457 ivideo->sisfb_tvstd = -1;
2458 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2463 /* Detect/set TV plug & type */
2464 if(ivideo->sisfb_tvplug != -1) {
2465 ivideo->vbflags |= ivideo->sisfb_tvplug;
2467 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2468 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2469 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2471 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2472 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2476 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2477 if(ivideo->sisfb_tvstd != -1) {
2478 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2479 ivideo->vbflags |= ivideo->sisfb_tvstd;
2481 if(ivideo->vbflags & TV_SCART) {
2482 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2483 ivideo->vbflags |= TV_PAL;
2485 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2486 if(ivideo->sisvga_engine == SIS_300_VGA) {
2487 inSISIDXREG(SISSR, 0x38, temp);
2488 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2489 else ivideo->vbflags |= TV_NTSC;
2490 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2491 inSISIDXREG(SISSR, 0x38, temp);
2492 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2493 else ivideo->vbflags |= TV_NTSC;
2495 inSISIDXREG(SISCR, 0x79, temp);
2496 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2497 else ivideo->vbflags |= TV_NTSC;
2502 /* Copy forceCRT1 option to CRT1off if option is given */
2503 if(ivideo->sisfb_forcecrt1 != -1) {
2504 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2508 static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo)
2510 char stdstr[] = "sisfb: Detected";
2511 char bridgestr[] = "video bridge";
2515 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2518 inSISIDXREG(SISPART4, 0x01, reg);
2520 ivideo->vbflags |= VB_301;
2521 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2522 } else if(reg < 0xc0) {
2523 ivideo->vbflags |= VB_301B;
2524 inSISIDXREG(SISPART4,0x23,reg);
2526 ivideo->vbflags |= VB_30xBDH;
2527 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2529 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2531 } else if(reg < 0xd0) {
2532 ivideo->vbflags |= VB_301C;
2533 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2534 } else if(reg < 0xe0) {
2535 ivideo->vbflags |= VB_301LV;
2536 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2537 } else if(reg <= 0xe1) {
2538 inSISIDXREG(SISPART4,0x39,reg);
2540 ivideo->vbflags |= VB_302LV;
2541 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2543 ivideo->vbflags |= VB_301C;
2544 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2546 ivideo->vbflags |= VB_302ELV;
2547 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2553 ivideo->vbflags |= VB_302B;
2554 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2558 if((!(ivideo->vbflags & VB_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2559 inSISIDXREG(SISCR, 0x37, reg);
2560 reg &= SIS_EXTERNAL_CHIP_MASK;
2562 if(ivideo->sisvga_engine == SIS_300_VGA) {
2563 #ifdef CONFIG_FB_SIS_300
2565 case SIS_EXTERNAL_CHIP_LVDS:
2566 ivideo->vbflags |= VB_LVDS;
2568 case SIS_EXTERNAL_CHIP_TRUMPION:
2569 ivideo->vbflags |= VB_TRUMPION;
2571 case SIS_EXTERNAL_CHIP_CHRONTEL:
2572 ivideo->vbflags |= VB_CHRONTEL;
2574 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2575 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2578 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 1;
2580 } else if(ivideo->chip < SIS_661) {
2581 #ifdef CONFIG_FB_SIS_315
2583 case SIS310_EXTERNAL_CHIP_LVDS:
2584 ivideo->vbflags |= VB_LVDS;
2586 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2587 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2590 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2592 } else if(ivideo->chip >= SIS_661) {
2593 #ifdef CONFIG_FB_SIS_315
2594 inSISIDXREG(SISCR, 0x38, reg);
2598 ivideo->vbflags |= VB_LVDS;
2601 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2604 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);
2607 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2610 if(ivideo->vbflags & VB_LVDS) {
2611 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2613 if(ivideo->vbflags & VB_TRUMPION) {
2614 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2616 if(ivideo->vbflags & VB_CHRONTEL) {
2617 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2619 if(ivideo->vbflags & VB_CONEXANT) {
2620 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2624 if(ivideo->vbflags & VB_SISBRIDGE) {
2625 SiS_Sense30x(ivideo);
2626 } else if(ivideo->vbflags & VB_CHRONTEL) {
2627 SiS_SenseCh(ivideo);
2631 /* ------------------ Sensing routines ------------------ */
2633 static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo)
2638 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2640 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2642 return (count == -1) ? FALSE : TRUE;
2645 static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
2647 BOOLEAN mustwait = FALSE;
2649 #ifdef CONFIG_FB_SIS_315
2655 inSISIDXREG(SISSR,0x1F,sr1F);
2656 orSISIDXREG(SISSR,0x1F,0x04);
2657 andSISIDXREG(SISSR,0x1F,0x3F);
2658 if(sr1F & 0xc0) mustwait = TRUE;
2660 #ifdef CONFIG_FB_SIS_315
2661 if(ivideo->sisvga_engine == SIS_315_VGA) {
2662 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2664 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2668 inSISIDXREG(SISCR,0x17,cr17);
2671 orSISIDXREG(SISCR,0x17,0x80);
2673 outSISIDXREG(SISSR, 0x00, 0x01);
2674 outSISIDXREG(SISSR, 0x00, 0x03);
2678 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2681 #ifdef CONFIG_FB_SIS_315
2682 if(ivideo->chip >= SIS_330) {
2683 andSISIDXREG(SISCR,0x32,~0x20);
2684 if(ivideo->chip >= SIS_340) {
2685 outSISIDXREG(SISCR, 0x57, 0x4a);
2687 outSISIDXREG(SISCR, 0x57, 0x5f);
2689 orSISIDXREG(SISCR, 0x53, 0x02);
2690 while((inSISREG(SISINPSTAT)) & 0x01) break;
2691 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2692 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2693 andSISIDXREG(SISCR, 0x53, 0xfd);
2694 andSISIDXREG(SISCR, 0x57, 0x00);
2698 if(temp == 0xffff) {
2701 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, 0, 0, NULL);
2702 } while(((temp == 0) || (temp == 0xffff)) && i--);
2704 if((temp == 0) || (temp == 0xffff)) {
2705 if(sisfb_test_DDC1(ivideo)) temp = 1;
2709 if((temp) && (temp != 0xffff)) {
2710 orSISIDXREG(SISCR,0x32,0x20);
2713 #ifdef CONFIG_FB_SIS_315
2714 if(ivideo->sisvga_engine == SIS_315_VGA) {
2715 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2719 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2721 outSISIDXREG(SISSR,0x1F,sr1F);
2724 /* Determine and detect attached devices on SiS30x */
2725 static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2727 int temp, mytest, result, i, j;
2729 for(j = 0; j < 10; j++) {
2731 for(i = 0; i < 3; i++) {
2733 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2734 temp = (type >> 8) | (mytest & 0x00ff);
2735 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2736 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2739 inSISIDXREG(SISPART4,0x03,temp);
2742 if(temp == mytest) result++;
2744 outSISIDXREG(SISPART4,0x11,0x00);
2745 andSISIDXREG(SISPART4,0x10,0xe0);
2746 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2749 if((result == 0) || (result >= 2)) break;
2754 static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
2756 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2757 u16 svhs=0, svhs_c=0;
2758 u16 cvbs=0, cvbs_c=0;
2759 u16 vga2=0, vga2_c=0;
2761 char stdstr[] = "sisfb: Detected";
2762 char tvstr[] = "TV connected to";
2764 if(ivideo->vbflags & VB_301) {
2765 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2766 inSISIDXREG(SISPART4,0x01,myflag);
2768 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2770 } else if(ivideo->vbflags & (VB_301B | VB_302B)) {
2771 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2772 } else if(ivideo->vbflags & (VB_301LV | VB_302LV)) {
2773 svhs = 0x0200; cvbs = 0x0100;
2774 } else if(ivideo->vbflags & (VB_301C | VB_302ELV)) {
2775 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2778 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2779 if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
2780 svhs_c = 0x0408; cvbs_c = 0x0808;
2784 if(ivideo->chip == SIS_300) {
2785 inSISIDXREG(SISSR,0x3b,myflag);
2786 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2789 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2790 orSISIDXREG(SISSR,0x1e,0x20);
2792 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2793 if(ivideo->vbflags & VB_301C) {
2794 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2796 orSISIDXREG(SISPART4,0x0d,0x04);
2798 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2800 inSISIDXREG(SISPART2,0x00,backupP2_00);
2801 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2803 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2804 if(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV)) {
2805 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2808 if(!(ivideo->vbflags & VB_301C)) {
2809 SISDoSense(ivideo, 0, 0);
2812 andSISIDXREG(SISCR, 0x32, ~0x14);
2814 if(vga2_c || vga2) {
2815 if(SISDoSense(ivideo, vga2, vga2_c)) {
2816 if(biosflag & 0x01) {
2817 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2818 orSISIDXREG(SISCR, 0x32, 0x04);
2820 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2821 orSISIDXREG(SISCR, 0x32, 0x10);
2826 andSISIDXREG(SISCR, 0x32, 0x3f);
2828 if(ivideo->vbflags & VB_301C) {
2829 orSISIDXREG(SISPART4,0x0d,0x04);
2832 if((ivideo->sisvga_engine == SIS_315_VGA) &&
2833 (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV))) {
2834 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2835 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2836 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2837 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2838 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2839 orSISIDXREG(SISCR,0x32,0x80);
2842 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2845 andSISIDXREG(SISCR, 0x32, ~0x03);
2847 if(!(ivideo->vbflags & TV_YPBPR)) {
2848 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2849 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2850 orSISIDXREG(SISCR, 0x32, 0x02);
2852 if((biosflag & 0x02) || (!result)) {
2853 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2854 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2855 orSISIDXREG(SISCR, 0x32, 0x01);
2860 SISDoSense(ivideo, 0, 0);
2862 outSISIDXREG(SISPART2,0x00,backupP2_00);
2863 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2864 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2866 if(ivideo->vbflags & VB_301C) {
2867 inSISIDXREG(SISPART2,0x00,biosflag);
2868 if(biosflag & 0x20) {
2869 for(myflag = 2; myflag > 0; myflag--) {
2871 outSISIDXREG(SISPART2,0x00,biosflag);
2876 outSISIDXREG(SISPART2,0x00,backupP2_00);
2879 /* Determine and detect attached TV's on Chrontel */
2880 static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
2882 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2884 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2886 #ifdef CONFIG_FB_SIS_300
2887 unsigned char test[3];
2891 if(ivideo->chip < SIS_315H) {
2893 #ifdef CONFIG_FB_SIS_300
2894 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2895 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2896 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2897 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2898 /* See Chrontel TB31 for explanation */
2899 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2900 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2901 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b0e);
2902 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2904 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2905 if(temp2 != temp1) temp1 = temp2;
2907 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2908 /* Read power status */
2909 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2910 if((temp1 & 0x03) != 0x03) {
2911 /* Power all outputs */
2912 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0B0E);
2913 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2915 /* Sense connected TV devices */
2916 for(i = 0; i < 3; i++) {
2917 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0110);
2918 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2919 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0010);
2920 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2921 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2922 if(!(temp1 & 0x08)) test[i] = 0x02;
2923 else if(!(temp1 & 0x02)) test[i] = 0x01;
2925 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2928 if(test[0] == test[1]) temp1 = test[0];
2929 else if(test[0] == test[2]) temp1 = test[0];
2930 else if(test[1] == test[2]) temp1 = test[1];
2933 "sisfb: TV detection unreliable - test results varied\n");
2937 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2938 ivideo->vbflags |= TV_SVIDEO;
2939 orSISIDXREG(SISCR, 0x32, 0x02);
2940 andSISIDXREG(SISCR, 0x32, ~0x05);
2941 } else if (temp1 == 0x01) {
2942 printk(KERN_INFO "%s CVBS output\n", stdstr);
2943 ivideo->vbflags |= TV_AVIDEO;
2944 orSISIDXREG(SISCR, 0x32, 0x01);
2945 andSISIDXREG(SISCR, 0x32, ~0x06);
2947 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2948 andSISIDXREG(SISCR, 0x32, ~0x07);
2950 } else if(temp1 == 0) {
2951 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2952 andSISIDXREG(SISCR, 0x32, ~0x07);
2954 /* Set general purpose IO for Chrontel communication */
2955 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2960 #ifdef CONFIG_FB_SIS_315
2961 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2962 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2963 SiS_SetCH701x(&ivideo->SiS_Pr, 0x2049);
2964 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2965 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2967 SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2968 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2970 SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2971 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2972 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2973 SiS_SetCH701x(&ivideo->SiS_Pr, (temp1 << 8) | 0x49);
2975 if(temp2 & 0x02) temp1 |= 0x01;
2976 if(temp2 & 0x10) temp1 |= 0x01;
2977 if(temp2 & 0x04) temp1 |= 0x02;
2978 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2981 printk(KERN_INFO "%s CVBS output\n", stdstr);
2982 ivideo->vbflags |= TV_AVIDEO;
2983 orSISIDXREG(SISCR, 0x32, 0x01);
2984 andSISIDXREG(SISCR, 0x32, ~0x06);
2987 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2988 ivideo->vbflags |= TV_SVIDEO;
2989 orSISIDXREG(SISCR, 0x32, 0x02);
2990 andSISIDXREG(SISCR, 0x32, ~0x05);
2993 printk(KERN_INFO "%s SCART output\n", stdstr);
2994 orSISIDXREG(SISCR, 0x32, 0x04);
2995 andSISIDXREG(SISCR, 0x32, ~0x03);
2998 andSISIDXREG(SISCR, 0x32, ~0x07);
3004 /* ------------------------ Heap routines -------------------------- */
3006 static u32 __devinit
3007 sisfb_getheapstart(struct sis_video_info *ivideo)
3009 u32 ret = ivideo->sisfb_parm_mem * 1024;
3010 u32 max = ivideo->video_size - ivideo->hwcursor_size;
3013 /* Calculate heap start = end of memory for console
3015 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3016 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3018 * Basically given by "mem" parameter
3020 * maximum = videosize - cmd_queue - hwcursor
3021 * (results in a heap of size 0)
3022 * default = SiS 300: depends on videosize
3023 * SiS 315/330: 32k below max
3026 if(ivideo->sisvga_engine == SIS_300_VGA) {
3027 max -= TURBO_QUEUE_AREA_SIZE;
3028 if(ivideo->video_size > 0x1000000) {
3030 } else if(ivideo->video_size > 0x800000) {
3036 max -= COMMAND_QUEUE_AREA_SIZE;
3040 if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) {
3047 static int __devinit
3048 sisfb_heap_init(struct sis_video_info *ivideo)
3052 ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo);
3054 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3055 ivideo->sisfb_heap_end = ivideo->video_vbase + ivideo->video_size;
3057 /* Initialize command queue (We use MMIO only) */
3059 #ifdef CONFIG_FB_SIS_315
3060 if(ivideo->sisvga_engine == SIS_315_VGA) {
3064 ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
3066 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
3067 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3069 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3070 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3072 temp = SIS_CMD_QUEUE_SIZE_512k;
3073 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3074 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3076 tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE);
3077 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3079 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3083 #ifdef CONFIG_FB_SIS_300
3084 if(ivideo->sisvga_engine == SIS_300_VGA) {
3085 unsigned long tqueue_pos;
3088 ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
3090 tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
3092 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3095 tq_state |= (u8)(tqueue_pos >> 8);
3096 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3098 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
3100 ivideo->caps |= TURBO_QUEUE_CAP;
3104 /* Reserve memory for the HWCursor */
3105 ivideo->sisfb_heap_end -= ivideo->hwcursor_size;
3106 ivideo->hwcursor_vbase = ivideo->sisfb_heap_end;
3107 ivideo->caps |= HW_CURSOR_CAP;
3109 ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start;
3111 if(ivideo->cardnumber == 0) {
3113 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3114 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3116 sisfb_heap.vinfo = ivideo;
3118 sisfb_heap.poha_chain = NULL;
3119 sisfb_heap.poh_freelist = NULL;
3121 poh = sisfb_poh_new_node();
3122 if(poh == NULL) return 1;
3124 poh->poh_next = &sisfb_heap.oh_free;
3125 poh->poh_prev = &sisfb_heap.oh_free;
3126 poh->size = ivideo->sisfb_heap_size;
3127 poh->offset = ivideo->heapstart;
3129 sisfb_heap.oh_free.poh_next = poh;
3130 sisfb_heap.oh_free.poh_prev = poh;
3131 sisfb_heap.oh_free.size = 0;
3132 sisfb_heap.max_freesize = poh->size;
3134 sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
3135 sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
3136 sisfb_heap.oh_used.size = SENTINEL;
3140 printk(KERN_INFO "Skipped heap initialization for secondary cards\n");
3148 sisfb_poh_new_node(void)
3155 if(sisfb_heap.poh_freelist == NULL) {
3156 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3157 if(!poha) return NULL;
3159 poha->poha_next = sisfb_heap.poha_chain;
3160 sisfb_heap.poha_chain = poha;
3162 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
3164 poh = &poha->aoh[0];
3165 for(i = cOhs - 1; i != 0; i--) {
3166 poh->poh_next = poh + 1;
3170 poh->poh_next = NULL;
3171 sisfb_heap.poh_freelist = &poha->aoh[0];
3174 poh = sisfb_heap.poh_freelist;
3175 sisfb_heap.poh_freelist = poh->poh_next;
3181 sisfb_poh_allocate(u32 size)
3187 if(size > sisfb_heap.max_freesize) {
3188 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3189 (unsigned int) size / 1024);
3193 pohThis = sisfb_heap.oh_free.poh_next;
3195 while(pohThis != &sisfb_heap.oh_free) {
3196 if (size <= pohThis->size) {
3200 pohThis = pohThis->poh_next;
3204 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3205 (unsigned int) size / 1024);
3209 if(size == pohThis->size) {
3211 sisfb_delete_node(pohThis);
3213 pohRoot = sisfb_poh_new_node();
3215 if(pohRoot == NULL) {
3219 pohRoot->offset = pohThis->offset;
3220 pohRoot->size = size;
3222 pohThis->offset += size;
3223 pohThis->size -= size;
3226 sisfb_heap.max_freesize -= size;
3228 pohThis = &sisfb_heap.oh_used;
3229 sisfb_insert_node(pohThis, pohRoot);
3235 sisfb_delete_node(SIS_OH *poh)
3240 poh_prev = poh->poh_prev;
3241 poh_next = poh->poh_next;
3243 poh_prev->poh_next = poh_next;
3244 poh_next->poh_prev = poh_prev;
3248 sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
3252 pohTemp = pohList->poh_next;
3254 pohList->poh_next = poh;
3255 pohTemp->poh_prev = poh;
3257 poh->poh_prev = pohList;
3258 poh->poh_next = pohTemp;
3262 sisfb_poh_free(u32 base)
3272 poh_freed = sisfb_heap.oh_used.poh_next;
3274 while(poh_freed != &sisfb_heap.oh_used) {
3275 if(poh_freed->offset == base) {
3280 poh_freed = poh_freed->poh_next;
3283 if(!foundNode) return(NULL);
3285 sisfb_heap.max_freesize += poh_freed->size;
3287 poh_prev = poh_next = NULL;
3288 ulUpper = poh_freed->offset + poh_freed->size;
3289 ulLower = poh_freed->offset;
3291 pohThis = sisfb_heap.oh_free.poh_next;
3293 while(pohThis != &sisfb_heap.oh_free) {
3294 if(pohThis->offset == ulUpper) {
3296 } else if((pohThis->offset + pohThis->size) == ulLower) {
3299 pohThis = pohThis->poh_next;
3302 sisfb_delete_node(poh_freed);
3304 if(poh_prev && poh_next) {
3305 poh_prev->size += (poh_freed->size + poh_next->size);
3306 sisfb_delete_node(poh_next);
3307 sisfb_free_node(poh_freed);
3308 sisfb_free_node(poh_next);
3313 poh_prev->size += poh_freed->size;
3314 sisfb_free_node(poh_freed);
3319 poh_next->size += poh_freed->size;
3320 poh_next->offset = poh_freed->offset;
3321 sisfb_free_node(poh_freed);
3325 sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
3331 sisfb_free_node(SIS_OH *poh)
3333 if(poh == NULL) return;
3335 poh->poh_next = sisfb_heap.poh_freelist;
3336 sisfb_heap.poh_freelist = poh;
3340 sis_malloc(struct sis_memreq *req)
3342 struct sis_video_info *ivideo = sisfb_heap.vinfo;
3345 if((ivideo) && (!ivideo->havenoheap)) {
3346 poh = sisfb_poh_allocate((u32)req->size);
3350 req->offset = req->size = 0;
3351 DPRINTK("sisfb: Video RAM allocation failed\n");
3353 req->offset = poh->offset;
3354 req->size = poh->size;
3355 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3356 (poh->offset + ivideo->video_vbase));
3360 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3365 struct sis_video_info *ivideo = sisfb_heap.vinfo;
3368 if((!ivideo) || (ivideo->havenoheap)) return;
3370 poh = sisfb_poh_free((u32)base);
3373 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3374 (unsigned int) base);
3378 /* --------------------- SetMode routines ------------------------- */
3381 sisfb_pre_setmode(struct sis_video_info *ivideo)
3383 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3386 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3388 inSISIDXREG(SISCR, 0x31, cr31);
3392 cr33 = ivideo->rate_idx & 0x0F;
3394 #ifdef CONFIG_FB_SIS_315
3395 if(ivideo->sisvga_engine == SIS_315_VGA) {
3396 if(ivideo->chip >= SIS_661) {
3397 inSISIDXREG(SISCR, 0x38, cr38);
3398 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3401 inSISIDXREG(SISCR, tvregnum, cr38);
3402 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3406 #ifdef CONFIG_FB_SIS_300
3407 if(ivideo->sisvga_engine == SIS_300_VGA) {
3409 inSISIDXREG(SISCR, tvregnum, cr38);
3413 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3414 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3416 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3419 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3420 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) {
3421 #ifdef CONFIG_FB_SIS_315
3422 if(ivideo->chip >= SIS_661) {
3424 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3425 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3426 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3427 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3429 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3430 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3431 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3433 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3434 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3435 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3437 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3440 } else if((ivideo->vbflags & TV_HIVISION) && (ivideo->vbflags & (VB_301|VB_301B|VB_302B))) {
3441 if(ivideo->chip >= SIS_661) {
3447 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3450 ivideo->currentvbflags |= TV_HIVISION;
3451 } else if(ivideo->vbflags & TV_SCART) {
3452 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3455 ivideo->currentvbflags |= TV_SCART;
3457 if(ivideo->vbflags & TV_SVIDEO) {
3458 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3459 ivideo->currentvbflags |= TV_SVIDEO;
3461 if(ivideo->vbflags & TV_AVIDEO) {
3462 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3463 ivideo->currentvbflags |= TV_AVIDEO;
3466 cr31 |= SIS_DRIVER_MODE;
3468 if(ivideo->vbflags & (TV_AVIDEO|TV_SVIDEO)) {
3469 if(ivideo->vbflags & TV_PAL) {
3470 cr31 |= 0x01; cr35 |= 0x01;
3471 ivideo->currentvbflags |= TV_PAL;
3472 if(ivideo->vbflags & TV_PALM) {
3473 cr38 |= 0x40; cr35 |= 0x04;
3474 ivideo->currentvbflags |= TV_PALM;
3475 } else if(ivideo->vbflags & TV_PALN) {
3476 cr38 |= 0x80; cr35 |= 0x08;
3477 ivideo->currentvbflags |= TV_PALN;
3480 cr31 &= ~0x01; cr35 &= ~0x01;
3481 ivideo->currentvbflags |= TV_NTSC;
3482 if(ivideo->vbflags & TV_NTSCJ) {
3483 cr38 |= 0x40; cr35 |= 0x02;
3484 ivideo->currentvbflags |= TV_NTSCJ;
3491 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3492 cr31 |= SIS_DRIVER_MODE;
3493 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3494 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3498 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3499 cr31 |= SIS_DRIVER_MODE;
3500 if(ivideo->sisfb_nocrt2rate) {
3501 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3503 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3507 default: /* disable CRT2 */
3509 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3512 outSISIDXREG(SISCR, 0x30, cr30);
3513 outSISIDXREG(SISCR, 0x33, cr33);
3515 if(ivideo->chip >= SIS_661) {
3516 #ifdef CONFIG_FB_SIS_315
3517 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3518 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3519 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3520 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3522 } else if(ivideo->chip != SIS_300) {
3523 outSISIDXREG(SISCR, tvregnum, cr38);
3525 outSISIDXREG(SISCR, 0x31, cr31);
3527 if(ivideo->accel) sisfb_syncaccel(ivideo);
3529 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3532 /* Fix SR11 for 661 and later */
3533 #ifdef CONFIG_FB_SIS_315
3535 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3539 if(ivideo->chip >= SIS_661) {
3540 inSISIDXREG(SISSR,0x11,tmpreg);
3542 inSISIDXREG(SISSR,0x3e,tmpreg);
3543 tmpreg = (tmpreg + 1) & 0xff;
3544 outSISIDXREG(SISSR,0x3e,tmpreg);
3545 inSISIDXREG(SISSR,0x11,tmpreg);
3548 andSISIDXREG(SISSR,0x11,0x0f);
3554 static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3556 if(val > 32) val = 32;
3557 if(val < -32) val = -32;
3558 ivideo->tvxpos = val;
3560 if(ivideo->sisfblocked) return;
3561 if(!ivideo->modechanged) return;
3563 if(ivideo->currentvbflags & CRT2_TV) {
3565 if(ivideo->vbflags & VB_CHRONTEL) {
3567 int x = ivideo->tvx;
3569 switch(ivideo->chronteltype) {
3573 outSISIDXREG(SISSR,0x05,0x86);
3574 SiS_SetCH700x(&ivideo->SiS_Pr, (((x & 0xff) << 8) | 0x0a));
3575 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD);
3578 /* Not supported by hardware */
3582 } else if(ivideo->vbflags & VB_SISBRIDGE) {
3584 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3585 unsigned short temp;
3587 p2_1f = ivideo->p2_1f;
3588 p2_20 = ivideo->p2_20;
3589 p2_2b = ivideo->p2_2b;
3590 p2_42 = ivideo->p2_42;
3591 p2_43 = ivideo->p2_43;
3593 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3595 p2_1f = temp & 0xff;
3596 p2_20 = (temp & 0xf00) >> 4;
3597 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3598 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3600 p2_43 = temp & 0xff;
3601 p2_42 = (temp & 0xf00) >> 4;
3602 outSISIDXREG(SISPART2,0x1f,p2_1f);
3603 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3604 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3605 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3606 outSISIDXREG(SISPART2,0x43,p2_43);
3611 static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3613 if(val > 32) val = 32;
3614 if(val < -32) val = -32;
3615 ivideo->tvypos = val;
3617 if(ivideo->sisfblocked) return;
3618 if(!ivideo->modechanged) return;
3620 if(ivideo->currentvbflags & CRT2_TV) {
3622 if(ivideo->vbflags & VB_CHRONTEL) {
3624 int y = ivideo->tvy;
3626 switch(ivideo->chronteltype) {
3630 outSISIDXREG(SISSR,0x05,0x86);
3631 SiS_SetCH700x(&ivideo->SiS_Pr, (((y & 0xff) << 8) | 0x0b));
3632 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, ((y & 0x0100) | 0x08),0xFE);
3635 /* Not supported by hardware */
3639 } else if(ivideo->vbflags & VB_SISBRIDGE) {
3643 p2_01 = ivideo->p2_01;
3644 p2_02 = ivideo->p2_02;
3648 while((p2_01 <= 0) || (p2_02 <= 0)) {
3652 outSISIDXREG(SISPART2,0x01,p2_01);
3653 outSISIDXREG(SISPART2,0x02,p2_02);
3659 sisfb_post_setmode(struct sis_video_info *ivideo)
3661 BOOLEAN crt1isoff = FALSE;
3662 BOOLEAN doit = TRUE;
3663 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3666 #ifdef CONFIG_FB_SIS_315
3670 outSISIDXREG(SISSR,0x05,0x86);
3672 #ifdef CONFIG_FB_SIS_315
3673 sisfb_fixup_SR11(ivideo);
3676 /* Now we actually HAVE changed the display mode */
3677 ivideo->modechanged = 1;
3679 /* We can't switch off CRT1 if bridge is in slave mode */
3680 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
3681 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3682 } else ivideo->sisfb_crt1off = 0;
3684 #ifdef CONFIG_FB_SIS_300
3685 if(ivideo->sisvga_engine == SIS_300_VGA) {
3686 if((ivideo->sisfb_crt1off) && (doit)) {
3693 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3696 #ifdef CONFIG_FB_SIS_315
3697 if(ivideo->sisvga_engine == SIS_315_VGA) {
3698 if((ivideo->sisfb_crt1off) && (doit)) {
3708 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3709 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3714 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3715 ivideo->currentvbflags |= VB_SINGLE_MODE;
3717 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3718 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3719 ivideo->currentvbflags |= VB_MIRROR_MODE;
3721 ivideo->currentvbflags |= VB_SINGLE_MODE;
3725 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3727 if(ivideo->currentvbflags & CRT2_TV) {
3728 if(ivideo->vbflags & VB_SISBRIDGE) {
3729 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3730 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3731 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3732 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3733 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3734 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3735 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3736 } else if(ivideo->vbflags & VB_CHRONTEL) {
3737 if(ivideo->chronteltype == 1) {
3738 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3739 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3740 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3741 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3746 if(ivideo->tvxpos) {
3747 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3749 if(ivideo->tvypos) {
3750 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3753 if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) { /* Set filter for SiS301 */
3755 unsigned char filter_tb = 0;
3757 switch (ivideo->video_width) {
3759 filter_tb = (ivideo->vbflags & TV_NTSC) ? 4 : 12;
3762 filter_tb = (ivideo->vbflags & TV_NTSC) ? 5 : 13;
3765 filter_tb = (ivideo->vbflags & TV_NTSC) ? 6 : 14;
3769 filter_tb = (ivideo->vbflags & TV_NTSC) ? 7 : 15;
3772 ivideo->sisfb_filter = -1;
3776 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
3778 if(ivideo->vbflags & TV_NTSC) {
3780 andSISIDXREG(SISPART2, 0x3a, 0x1f);
3782 if (ivideo->vbflags & TV_SVIDEO) {
3784 andSISIDXREG(SISPART2, 0x30, 0xdf);
3786 } else if (ivideo->vbflags & TV_AVIDEO) {
3788 orSISIDXREG(SISPART2, 0x30, 0x20);
3790 switch (ivideo->video_width) {
3792 outSISIDXREG(SISPART2, 0x35, 0xEB);
3793 outSISIDXREG(SISPART2, 0x36, 0x04);
3794 outSISIDXREG(SISPART2, 0x37, 0x25);
3795 outSISIDXREG(SISPART2, 0x38, 0x18);
3798 outSISIDXREG(SISPART2, 0x35, 0xEE);
3799 outSISIDXREG(SISPART2, 0x36, 0x0C);
3800 outSISIDXREG(SISPART2, 0x37, 0x22);
3801 outSISIDXREG(SISPART2, 0x38, 0x08);
3805 outSISIDXREG(SISPART2, 0x35, 0xEB);
3806 outSISIDXREG(SISPART2, 0x36, 0x15);
3807 outSISIDXREG(SISPART2, 0x37, 0x25);
3808 outSISIDXREG(SISPART2, 0x38, 0xF6);
3813 } else if(ivideo->vbflags & TV_PAL) {
3815 andSISIDXREG(SISPART2, 0x3A, 0x1F);
3817 if (ivideo->vbflags & TV_SVIDEO) {
3819 andSISIDXREG(SISPART2, 0x30, 0xDF);
3821 } else if (ivideo->vbflags & TV_AVIDEO) {
3823 orSISIDXREG(SISPART2, 0x30, 0x20);
3825 switch (ivideo->video_width) {
3827 outSISIDXREG(SISPART2, 0x35, 0xF1);
3828 outSISIDXREG(SISPART2, 0x36, 0xF7);
3829 outSISIDXREG(SISPART2, 0x37, 0x1F);
3830 outSISIDXREG(SISPART2, 0x38, 0x32);
3833 outSISIDXREG(SISPART2, 0x35, 0xF3);
3834 outSISIDXREG(SISPART2, 0x36, 0x00);
3835 outSISIDXREG(SISPART2, 0x37, 0x1D);
3836 outSISIDXREG(SISPART2, 0x38, 0x20);
3840 outSISIDXREG(SISPART2, 0x35, 0xFC);
3841 outSISIDXREG(SISPART2, 0x36, 0xFB);
3842 outSISIDXREG(SISPART2, 0x37, 0x14);
3843 outSISIDXREG(SISPART2, 0x38, 0x2A);
3849 if((ivideo->sisfb_filter >= 0) && (ivideo->sisfb_filter <= 7)) {
3850 outSISIDXREG(SISPART2,0x35,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][0]));
3851 outSISIDXREG(SISPART2,0x36,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][1]));
3852 outSISIDXREG(SISPART2,0x37,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][2]));
3853 outSISIDXREG(SISPART2,0x38,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][3]));
3860 SISINITSTATIC int __init sisfb_setup(char *options)
3864 sisfb_setdefaultparms();
3866 printk(KERN_DEBUG "sisfb: Options %s\n", options);
3868 if(!options || !(*options)) {
3872 while((this_opt = strsep(&options, ",")) != NULL) {
3874 if(!(*this_opt)) continue;
3876 if(!strnicmp(this_opt, "off", 3)) {
3878 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3879 /* Need to check crt2 type first for fstn/dstn */
3880 sisfb_search_crt2type(this_opt + 14);
3881 } else if(!strnicmp(this_opt, "tvmode:",7)) {
3882 sisfb_search_tvstd(this_opt + 7);
3883 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3884 sisfb_search_tvstd(this_opt + 7);
3885 } else if(!strnicmp(this_opt, "mode:", 5)) {
3886 sisfb_search_mode(this_opt + 5, FALSE);
3887 } else if(!strnicmp(this_opt, "vesa:", 5)) {
3888 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
3889 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
3890 } else if(!strnicmp(this_opt, "inverse", 7)) {
3892 /* fb_invert_cmaps(); */
3893 } else if(!strnicmp(this_opt, "font:", 5)) {
3894 if(strlen(this_opt + 5) < 40) {
3895 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
3896 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
3899 } else if(!strnicmp(this_opt, "rate:", 5)) {
3900 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
3901 } else if(!strnicmp(this_opt, "filter:", 7)) {
3902 sisfb_filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
3903 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3904 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
3905 } else if(!strnicmp(this_opt, "mem:",4)) {
3906 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
3907 } else if(!strnicmp(this_opt, "pdc:", 4)) {
3908 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
3909 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
3910 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
3911 } else if(!strnicmp(this_opt, "noaccel", 7)) {
3913 } else if(!strnicmp(this_opt, "accel", 5)) {
3915 } else if(!strnicmp(this_opt, "noypan", 6)) {
3917 } else if(!strnicmp(this_opt, "ypan", 4)) {
3919 } else if(!strnicmp(this_opt, "nomax", 5)) {
3921 } else if(!strnicmp(this_opt, "max", 3)) {
3923 } else if(!strnicmp(this_opt, "userom:", 7)) {
3924 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
3925 } else if(!strnicmp(this_opt, "useoem:", 7)) {
3926 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
3927 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
3928 sisfb_nocrt2rate = 1;
3929 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
3930 unsigned long temp = 2;
3931 temp = simple_strtoul(this_opt + 9, NULL, 0);
3932 if((temp == 0) || (temp == 1)) {
3933 sisfb_scalelcd = temp ^ 1;
3935 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
3937 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3938 if((temp >= -32) && (temp <= 32)) {
3939 sisfb_tvxposoffset = temp;
3941 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
3943 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3944 if((temp >= -32) && (temp <= 32)) {
3945 sisfb_tvyposoffset = temp;
3947 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
3948 sisfb_search_specialtiming(this_opt + 14);
3949 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
3951 temp = simple_strtoul(this_opt + 7, NULL, 0);
3952 if((temp >= 0) && (temp <= 3)) {
3953 sisfb_lvdshl = temp;
3955 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
3956 sisfb_search_mode(this_opt, TRUE);
3957 #if !defined(__i386__) && !defined(__x86_64__)
3958 } else if(!strnicmp(this_opt, "resetcard", 9)) {
3959 sisfb_resetcard = 1;
3960 } else if(!strnicmp(this_opt, "videoram:", 9)) {
3961 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
3964 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
3975 static UCHAR * __devinit sis_find_rom(struct pci_dev *pdev)
3977 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3982 SIS_IOTYPE1 *rom_base, *rom;
3984 if(!(myrombase = vmalloc(65536))) return NULL;
3986 #if defined(__i386__) || defined(__x86_64__)
3988 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
3990 rom_base = ioremap(temp, 0x10000);
3991 if(!rom_base) continue;
3993 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) {
3998 romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
3999 if(romptr > (0x10000 - 8)) {
4004 rom = rom_base + romptr;
4006 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4007 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) {
4012 pciid = readb(rom + 4) | (readb(rom + 5) << 8);
4013 if(pciid != 0x1039) {
4018 pciid = readb(rom + 6) | (readb(rom + 7) << 8);
4019 if(pciid == ivideo->chip_id) {
4020 memcpy_fromio(myrombase, rom_base, 65536);
4030 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4031 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4032 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4034 rom_base = ioremap(ivideo->video_base, 65536);
4036 if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) {
4037 romptr = (u16)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4038 if(romptr <= (0x10000 - 8)) {
4039 rom = rom_base + romptr;
4040 if((readb(rom) == 'P') && (readb(rom + 1) == 'C') &&
4041 (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) {
4042 pciid = readb(rom + 4) | (readb(rom + 5) << 8);
4043 if(pciid == 0x1039) {
4044 pciid = readb(rom + 6) | (readb(rom + 7) << 8);
4045 if(pciid == ivideo->chip_id) {
4046 memcpy_fromio(myrombase, rom_base, 65536);
4048 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4057 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4065 #ifdef CONFIG_FB_SIS_300
4066 static int __devinit
4067 sisfb_chkbuswidth300(struct pci_dev *pdev, SIS_IOTYPE1 *FBAddress)
4069 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4074 andSISIDXREG(SISSR,0x15,0xFB);
4075 orSISIDXREG(SISSR,0x15,0x04);
4076 outSISIDXREG(SISSR,0x13,0x00);
4077 outSISIDXREG(SISSR,0x14,0xBF);
4079 for(i=0; i<2; i++) {
4081 for(j=0; j<4; j++) {
4082 writew(temp, FBAddress);
4083 if(readw(FBAddress) == temp) break;
4084 orSISIDXREG(SISSR,0x3c,0x01);
4085 inSISIDXREG(SISSR,0x05,reg);
4086 inSISIDXREG(SISSR,0x05,reg);
4087 andSISIDXREG(SISSR,0x3c,0xfe);
4088 inSISIDXREG(SISSR,0x05,reg);
4089 inSISIDXREG(SISSR,0x05,reg);
4094 writel(0x01234567L, FBAddress);
4095 writel(0x456789ABL, (FBAddress+4));
4096 writel(0x89ABCDEFL, (FBAddress+8));
4097 writel(0xCDEF0123L, (FBAddress+12));
4098 inSISIDXREG(SISSR,0x3b,reg);
4100 if(readl((FBAddress+12)) == 0xCDEF0123L) return(4); /* Channel A 128bit */
4102 if(readl((FBAddress+4)) == 0x456789ABL) return(2); /* Channel B 64bit */
4103 return(1); /* 32bit */
4106 static void __devinit
4107 sisfb_setramsize300(struct pci_dev *pdev)
4109 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4110 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4112 USHORT sr13, sr14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0;
4113 int PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
4114 int RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
4115 int PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k;
4116 const USHORT SiS_DRAMType[17][5] = {
4117 {0x0C,0x0A,0x02,0x40,0x39},
4118 {0x0D,0x0A,0x01,0x40,0x48},
4119 {0x0C,0x09,0x02,0x20,0x35},
4120 {0x0D,0x09,0x01,0x20,0x44},
4121 {0x0C,0x08,0x02,0x10,0x31},
4122 {0x0D,0x08,0x01,0x10,0x40},
4123 {0x0C,0x0A,0x01,0x20,0x34},
4124 {0x0C,0x09,0x01,0x08,0x32},
4125 {0x0B,0x08,0x02,0x08,0x21},
4126 {0x0C,0x08,0x01,0x08,0x30},
4127 {0x0A,0x08,0x02,0x04,0x11},
4128 {0x0B,0x0A,0x01,0x10,0x28},
4129 {0x09,0x08,0x02,0x02,0x01},
4130 {0x0B,0x09,0x01,0x08,0x24},
4131 {0x0B,0x08,0x01,0x04,0x20},
4132 {0x0A,0x08,0x01,0x02,0x10},
4133 {0x09,0x08,0x01,0x01,0x00}
4136 buswidth = sisfb_chkbuswidth300(pdev, FBAddr);
4140 for(i = 6; i >= 0; i--) {
4142 PseudoRankCapacity = 1 << i;
4143 for(j = 4; j >= 1; j--) {
4145 PseudoTotalCapacity = PseudoRankCapacity * j;
4146 PseudoAdrPinCount = 15 - j;
4147 if(PseudoTotalCapacity <= 64) {
4148 for(k = 0; k <= 16; k++) {
4150 RankCapacity = buswidth * SiS_DRAMType[k][3];
4151 AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
4152 if(RankCapacity == PseudoRankCapacity)
4153 if(AdrPinCount <= PseudoAdrPinCount) {
4154 if(j == 3) { /* Rank No */
4155 BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
4156 BankNumMid = RankCapacity * MB2Bank * 1 - 1;
4158 BankNumHigh = RankCapacity * MB2Bank * j - 1;
4159 BankNumMid = RankCapacity * MB2Bank * j / 2 - 1;
4161 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4162 PhysicalAdrHigh = BankNumHigh;
4163 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4164 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4166 andSISIDXREG(SISSR,0x15,0xFB); /* Test */
4167 orSISIDXREG(SISSR,0x15,0x04); /* Test */
4168 TotalCapacity = SiS_DRAMType[k][3] * buswidth;
4169 sr13 = SiS_DRAMType[k][4];
4170 if(buswidth == 4) sr14 = (TotalCapacity - 1) | 0x80;
4171 if(buswidth == 2) sr14 = (TotalCapacity - 1) | 0x40;
4172 if(buswidth == 1) sr14 = (TotalCapacity - 1) | 0x00;
4173 outSISIDXREG(SISSR,0x13,sr13);
4174 outSISIDXREG(SISSR,0x14,sr14);
4175 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4176 /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */
4177 writew(((USHORT)PhysicalAdrHigh), Addr);
4178 Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh;
4179 /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */
4180 writew(((USHORT)BankNumMid), Addr);
4181 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage;
4182 /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */
4183 writew(((USHORT)PhysicalAdrHalfPage), Addr);
4184 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage;
4185 /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */
4186 writew(((USHORT)PhysicalAdrOtherPage), Addr);
4188 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4189 data = readw(Addr); /* *((USHORT *)(Addr)); */
4190 if(data == PhysicalAdrHigh) Done = 1;
4198 static void __devinit sisfb_post_sis300(struct pci_dev *pdev)
4200 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4201 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4202 u16 index, rindex, memtype = 0;
4204 outSISIDXREG(SISSR,0x05,0x86);
4206 if(ivideo->sishw_ext.UseROM) {
4207 if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80) {
4208 memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4210 inSISIDXREG(SISSR,0x3a,memtype);
4215 if(ivideo->revision_id <= 0x13) {
4216 v1 = 0x44; v2 = 0x42; v3 = 0x80;
4217 v4 = 0x44; v5 = 0x42; v6 = 0x80;
4219 v1 = 0x68; v2 = 0x43; v3 = 0x80; /* Assume 125Mhz MCLK */
4220 v4 = 0x68; v5 = 0x43; v6 = 0x80; /* Assume 125Mhz ECLK */
4221 if(ivideo->sishw_ext.UseROM) {
4222 index = memtype * 5;
4223 rindex = index + 0x54;
4224 v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4225 v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4226 v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4227 rindex = index + 0x7c;
4228 v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4229 v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4230 v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4233 outSISIDXREG(SISSR,0x28,v1);
4234 outSISIDXREG(SISSR,0x29,v2);
4235 outSISIDXREG(SISSR,0x2a,v3);
4236 outSISIDXREG(SISSR,0x2e,v4);
4237 outSISIDXREG(SISSR,0x2f,v5);
4238 outSISIDXREG(SISSR,0x30,v6);
4240 if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0xa4];
4241 outSISIDXREG(SISSR,0x07,v1); /* DAC speed */
4242 outSISIDXREG(SISSR,0x11,0x0f); /* DDC, power save */
4243 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4244 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4245 if(ivideo->sishw_ext.UseROM) {
4247 v1 = ivideo->sishw_ext.pjVirtualRomBase[memtype];
4248 v2 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 8];
4249 v3 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 16];
4250 v4 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 24];
4251 v5 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 32];
4252 v6 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 40];
4253 v7 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 48];
4254 v8 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 56];
4256 if(ivideo->revision_id >= 0x80) v3 &= 0xfd;
4257 outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4258 outSISIDXREG(SISSR,0x16,v2);
4259 outSISIDXREG(SISSR,0x17,v3);
4260 outSISIDXREG(SISSR,0x18,v4);
4261 outSISIDXREG(SISSR,0x19,v5);
4262 outSISIDXREG(SISSR,0x1a,v6);
4263 outSISIDXREG(SISSR,0x1b,v7);
4264 outSISIDXREG(SISSR,0x1c,v8); /* ---- */
4265 andSISIDXREG(SISSR,0x15,0xfb);
4266 orSISIDXREG(SISSR,0x15,0x04);
4267 if(ivideo->sishw_ext.UseROM) {
4268 if(ivideo->sishw_ext.pjVirtualRomBase[0x53] & 0x02) {
4269 orSISIDXREG(SISSR,0x19,0x20);
4272 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4273 if(ivideo->revision_id >= 0x80) v1 |= 0x01;
4274 outSISIDXREG(SISSR,0x1f,v1);
4275 outSISIDXREG(SISSR,0x20,0xa0); /* linear & relocated io */
4276 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4277 if(ivideo->sishw_ext.UseROM) {
4278 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe8];
4279 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe9];
4280 v3 = ivideo->sishw_ext.pjVirtualRomBase[0xea];
4282 outSISIDXREG(SISSR,0x23,v1);
4283 outSISIDXREG(SISSR,0x24,v2);
4284 outSISIDXREG(SISSR,0x25,v3);
4285 outSISIDXREG(SISSR,0x21,0x84);
4286 outSISIDXREG(SISSR,0x22,0x00);
4287 outSISIDXREG(SISCR,0x37,0x00);
4288 orSISIDXREG(SISPART1,0x24,0x01); /* unlock crt2 */
4289 outSISIDXREG(SISPART1,0x00,0x00);
4290 v1 = 0x40; v2 = 0x11;
4291 if(ivideo->sishw_ext.UseROM) {
4292 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xec];
4293 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xeb];
4295 outSISIDXREG(SISPART1,0x02,v1);
4296 if(ivideo->revision_id >= 0x80) v2 &= ~0x01;
4297 inSISIDXREG(SISPART4,0x00,reg);
4298 if((reg == 1) || (reg == 2)) {
4299 outSISIDXREG(SISCR,0x37,0x02);
4300 outSISIDXREG(SISPART2,0x00,0x1c);
4301 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4302 if(ivideo->sishw_ext.UseROM) {
4303 v4 = ivideo->sishw_ext.pjVirtualRomBase[0xf5];
4304 v5 = ivideo->sishw_ext.pjVirtualRomBase[0xf6];
4305 v6 = ivideo->sishw_ext.pjVirtualRomBase[0xf7];
4307 outSISIDXREG(SISPART4,0x0d,v4);
4308 outSISIDXREG(SISPART4,0x0e,v5);
4309 outSISIDXREG(SISPART4,0x10,v6);
4310 outSISIDXREG(SISPART4,0x0f,0x3f);
4311 inSISIDXREG(SISPART4,0x01,reg);
4313 inSISIDXREG(SISPART4,0x23,reg);
4316 outSISIDXREG(SISPART4,0x23,reg);
4321 outSISIDXREG(SISSR,0x32,v2);
4322 andSISIDXREG(SISPART1,0x24,0xfe); /* Lock CRT2 */
4323 inSISIDXREG(SISSR,0x16,reg);
4325 outSISIDXREG(SISCR,0x35,reg);
4326 outSISIDXREG(SISCR,0x83,0x00);
4327 #if !defined(__i386__) && !defined(__x86_64__)
4328 if(sisfb_videoram) {
4329 outSISIDXREG(SISSR,0x13,0x28); /* ? */
4330 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4331 outSISIDXREG(SISSR,0x14,reg);
4334 /* Need to map max FB size for finding out about RAM size */
4335 ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000);
4336 if(ivideo->video_vbase) {
4337 sisfb_setramsize300(pdev);
4338 iounmap(ivideo->video_vbase);
4340 printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4341 outSISIDXREG(SISSR,0x13,0x28); /* ? */
4342 outSISIDXREG(SISSR,0x14,0x47); /* 8MB, 64bit default */
4344 #if !defined(__i386__) && !defined(__x86_64__)
4347 if(ivideo->sishw_ext.UseROM) {
4348 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe6];
4349 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe7];
4351 inSISIDXREG(SISSR,0x3a,reg);
4352 if((reg & 0x30) == 0x30) {
4353 v1 = 0x04; /* PCI */
4356 v1 = 0x14; /* AGP */
4360 outSISIDXREG(SISSR,0x21,v1);
4361 outSISIDXREG(SISSR,0x22,v2);
4365 #ifdef CONFIG_FB_SIS_315
4366 static void __devinit sisfb_post_sis315330(struct pci_dev *pdev)
4368 #ifdef YET_TO_BE_DONE
4369 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4370 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4371 u16 index, rindex, memtype = 0;
4372 u32 reg1_32, reg2_32, reg3_32;
4376 /* outSISIDXREG(0x3c4,0x05,0x86); */
4377 outSISIDXREG(SISSR,0x05,0x86);
4379 /* Enable relocated i/o ports */
4380 /* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */
4381 setSISIDXREG(SISSR,0x20,~0x10,0x20);
4384 for(i = 0; i < 0x22; i++) {
4385 outSISIDXREG(SISSR,(0x06 + i),0x00);
4388 if( is 330) v1 = 0x0b;
4389 for(i = 0; i < v1; i++) {
4390 outSISIDXREG(SISSR,(0x31 + i),0x00);
4392 for(i = 0; i < 0x10; i++) {
4393 outSISIDXREG(SISCR,(0x30 + i),0x00);
4397 reg = inSISREG(SISMISCR);
4398 outSISIDXREG(SISSR,0x28,0x81);
4399 outSISIDXREG(SISSR,0x2A,0x00);
4400 outSISIDXREG(SISSR,0x29,0xE1);
4401 outSISREG(SISMISCW,(reg | 0x0c));
4402 outSISIDXREG(SISSR,0x2B,0x81);
4403 outSISIDXREG(SISSR,0x2D,0x00);
4404 outSISIDXREG(SISSR,0x2C,0xE1);
4405 outSISIDXREG(SISSR,0x2E,0x81);
4406 outSISIDXREG(SISSR,0x30,0x00);
4407 outSISIDXREG(SISSR,0x2F,0xE1);
4408 SiS_DDC2Delay(....);
4409 outSISREG(SISMISCW,reg);
4411 /* Get memory type */
4412 if(ivideo->sishw_ext.UseROM) {
4413 if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80)) {
4414 memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4416 inSISIDXREG(SISSR,0x3a,memtype);
4420 if(memtype <= 1) memtype = 0;
4422 inSISIDXREG(SISCR,0x5F,reg);
4425 case 0x00: memtype = 1; break;
4426 case 0x10: memtype = 3; break;
4427 case 0x20: memtype = 3; break;
4428 default: memtype = 2;
4435 v1 = 0x3b; v2 = 0x22; v3 = 0x01; /* Assume 143Mhz MCLK */
4436 v4 = 0x5c; v5 = 0x23; v6 = 0x01; /* Assume 166Mhz ECLK */
4437 if(ivideo->sishw_ext.UseROM) {
4438 index = memtype * 5;
4439 rindex = index + 0x54;
4440 v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4441 v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4442 v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4443 rindex = index + 0x68;
4444 v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4445 v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4446 v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4448 outSISIDXREG(SISSR,0x28,v1);
4449 outSISIDXREG(SISSR,0x29,v2);
4450 outSISIDXREG(SISSR,0x2a,v3);
4452 inSISIDXREG(SISSR,0x3a,reg);
4458 outSISIDXREG(SISSR,0x2e,v4);
4459 outSISIDXREG(SISSR,0x2f,v5);
4460 outSISIDXREG(SISSR,0x30,v6);
4462 /* End of comp with 330 */
4465 if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0x7c];
4466 outSISIDXREG(SISSR,0x07,v1);
4467 outSISIDXREG(SISSR,0x11,0x0f);
4469 v1 = 0x00; v2 = 0x0f; v3 = 0xba; v4 = 0xa9;
4470 v5 = 0xa0; v6 = 0x00; v7 = 0x30;
4471 if(ivideo->sishw_ext.UseROM) {
4472 index = memtype + 0x7d;
4473 v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4474 v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4475 v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4476 v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4477 v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4478 v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
4479 v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
4481 outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0x7d step 4) */
4482 outSISIDXREG(SISSR,0x16,v2);
4483 outSISIDXREG(SISSR,0x17,v3);
4484 outSISIDXREG(SISSR,0x18,v4);
4485 outSISIDXREG(SISSR,0x19,v5);
4486 outSISIDXREG(SISSR,0x1a,v6);
4487 outSISIDXREG(SISSR,0x1b,v7);
4488 outSISIDXREG(SISSR,0x1c,v8); /* ---- */
4490 v1 = 0x77; v2 = 0x77; v3 = 0x00; v4 = 0x5b; v5 = 0x00;
4491 if(ivideo->sishw_ext.UseROM) {
4492 index = memtype + 0xa2;
4493 v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4494 v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4495 v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4496 v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4497 v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4499 outSISIDXREG(SISCR,0x40,v1);
4500 outSISIDXREG(SISCR,0x41,v2);
4501 outSISIDXREG(SISCR,0x42,v3);
4502 outSISIDXREG(SISCR,0x43,v4);
4503 outSISIDXREG(SISCR,0x44,v5);
4508 if(ivideo->sishw_ext.UseROM) {
4509 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4511 outSISIDXREG(SISCR,0x59,v1);
4513 v1 = 0x; v2 = 0x; v3 = 0x; v4 = 0x;
4514 v5 = 0x; v6 = 0x; v7 = 0x; v8 = 0x;
4515 if(ivideo->sishw_ext.UseROM) {
4516 index = memtype + 0xbe;
4517 v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4518 v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4519 v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4520 v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4521 v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4522 v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
4523 v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
4524 v8 = ivideo->sishw_ext.pjVirtualRomBase[index + 28];
4526 outSISIDXREG(SISCR,0x68,v1);
4527 outSISIDXREG(SISCR,0x69,v2);
4528 outSISIDXREG(SISCR,0x6a,v3);
4529 outSISIDXREG(SISCR,0x6b,v4);
4530 outSISIDXREG(SISCR,0x6c,v5);
4531 outSISIDXREG(SISCR,0x6d,v6);
4532 outSISIDXREG(SISCR,0x6e,v7);
4533 outSISIDXREG(SISCR,0x6f,v8);
4536 inSISIDXREG(SISSR,0x3b,reg);
4539 inSISIDXREG(SISCR,0x5F,reg);
4543 outSISIDXREG(SISCR,0x48,v1);
4544 outSISIDXREG(SISCR,0x4c,0x20);
4549 if(ivideo->sishw_ext.UseROM) {
4550 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4552 outSISIDXREG(SISCR,0x59,v1);
4559 outSISIDXREG(SISCR,0x48,0x23);
4561 andSISIDXREG(SISSR,0x16,0x0f);
4563 orSISIDXREG(SISSR,0x16,0x80);
4566 if(ivideo->sishw_ext.UseROM) {
4567 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x81 + memtype];
4569 if(!(v1 & 0x10)) v2 = 0xc0;
4571 orSISIDXREG(SISSR,0x16,v2);
4572 andSISIDXREG(SISSR,0x16,0x0f);
4573 if(!(v1 & 0x10)) v2 = 0x80;
4575 orSISIDXREG(SISSR,0x16,v2);
4579 const u8 sr3cseq1[] = { 0xc0,0xe0,0xf0,0xe0,0xf0,0xa0,0xb0,0xa0,0xb0,0x90,0xd0 };
4580 const u8 sr3cseq2[] = { 0xc0,0xa0,0xb0,0xa0,0xb0,0xe0,0xf0,0xa0,0xb0,0x90,0xd0 };
4581 for(i = 0; i < 11; i++) {
4582 outSISIDXREG(SISSR,0x3c,sr3cseq1[i]);
4584 outSISIDXREG(SISSR,0x3d,0x00);
4585 outSISIDXREG(SISSR,0x3d,0x04);
4586 SiS_DDC2Delay(0x200);
4587 v1 = inSISIDXREG(SISCR,0xEC);
4588 v2 = inSISIDXREG(SISCR,0xED);
4589 reg1_32 = (v2 << 8) | v1;
4590 outSISIDXREG(SISSR,0x3D,0x00);
4591 for(i = 0; i < 11; i++) {
4592 outSISIDXREG(SISSR,0x3c,sr3cseq2[i]);
4594 outSISIDXREG(SISSR,0x3d,0x00);
4595 outSISIDXREG(SISSR,0x3d,0x04);
4596 SiS_DDC2Delay(0x200);
4597 v1 = inSISIDXREG(SISCR,0xEC);
4598 v2 = inSISIDXREG(SISCR,0xED);
4599 reg2_32 = (v2 << 8) | v1;
4600 outSISIDXREG(SISSR,0x3D,0x00);
4601 reg3_32 = reg2_32 << 1;
4605 if(reg3_32 > reg1_32) v1 = 0x10;
4606 outSISIDXREG(SISCR,0x59,v1);
4612 if(ivideo->sishw_ext.UseROM) {
4613 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x99];
4615 outSISIDXREG(SISSR,0x1f,v1);
4617 outSISIDXREG(SISSR,0x20,0x20);
4619 v1 = 0xf6; v2 = 0x0d; v3 = 0x33;
4620 if(ivideo->sishw_ext.UseROM) {
4621 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9c];
4622 v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9d];
4623 v3 = ivideo->sishw_ext.pjVirtualRomBase[0x9e];
4625 outSISIDXREG(SISSR,0x23,v1);
4626 outSISIDXREG(SISSR,0x24,v2);
4627 outSISIDXREG(SISSR,0x25,v3);
4629 outSISIDXREG(SISSR,0x21,0x84);
4630 outSISIDXREG(SISSR,0x22,0x00);
4631 outSISIDXREG(SISSR,0x27,0x1f);
4633 v1 = 0x00; v2 = 0x00;
4634 if(ivideo->sishw_ext.UseROM) {
4635 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9F];
4636 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xA1];
4638 outSISIDXREG(SISSR,0x31,v1);
4639 outSISIDXREG(SISSR,0x33,v2);
4642 if(ivideo->sishw_ext.UseROM) {
4643 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xA0];
4645 v2 = inSISIDXREG(SISPART4,0x00);
4646 if((v2 != 1) && (v2 != 2)) v1 &= 0xef;
4647 outSISIDXREG(SISSR,0x32,v1);
4650 pci_read_config_long(pdev, 0x50, ®1_32);
4654 v1 = 0xAA; v2 = 0x33;
4655 if(ivideo->sishw_ext.UseROM) {
4656 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF7];
4657 v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9E];
4660 v1 = 0x88; v2 = 0x03;
4661 if(ivideo->sishw_ext.UseROM) {
4662 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF8];
4663 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xF6];
4666 outSISIDXREG(SISCR,0x49,v1);
4667 outSISIDXREG(SISSR,0x25,v2);
4669 v1 = inSISIDXREG(SISPART4,0x00);
4670 if((v1 == 1) || (v1 == 2)) {
4671 orSISIDXREG(SISPART1,0x2F,0x01); /* Unlock CRT2 */
4672 outSISIDXREG(SISPART1,0x00,0x00);
4674 if(ivideo->sishw_ext.UseROM) {
4675 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb6];
4677 outSISIDXREG(SISPART1,0x02,v1);
4678 outSISIDXREG(SISPART1,0x2E,0x08);
4679 outSISIDXREG(SISPART2,0x00,0x1c);
4680 v1 = 0x40; v2 = 0x00; v3 = 0x80;
4681 if(ivideo->sishw_ext.UseROM) {
4682 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb7];
4683 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xb8];
4684 v3 = ivideo->sishw_ext.pjVirtualRomBase[0xbb];
4686 outSISIDXREG(SISPART4,0x0d,v1);
4687 outSISIDXREG(SISPART4,0x0e,v2);
4688 outSISIDXREG(SISPART4,0x10,v3);
4689 outSISIDXREG(SISPART4,0x0F,0x3F);
4691 inSISIDXREG(SISPART4,0x01,reg);
4693 inSISIDXREG(SISPART4,0x23,reg);
4696 outSISIDXREG(SISPART4,0x23,reg);
4699 outSISIDXREG(SISCR,0x37,0x02); /* Why? */
4701 outSISIDXREG(SISCR,0x83,0x00);
4702 outSISIDXREG(SISCR,0x90,0x00);
4703 andSISIDXREG(SISSR,0x5B,0xDF);
4704 outSISIDXREG(SISVID,0x00,0x86);
4705 outSISIDXREG(SISVID,0x32,0x00);
4706 outSISIDXREG(SISVID,0x30,0x00);
4707 outSISIDXREG(SISVID,0x32,0x01);
4708 outSISIDXREG(SISVID,0x30,0x00);
4709 orSISIDXREG(SISCR,0x63,0x80);
4715 orSISIDXREG(SISSR,0x16,0x0f);
4716 orSISIDXREG(SISSR,0x18,0xA9);
4717 orSISIDXREG(SISSR,0x19,0xA0);
4718 orSISIDXREG(SISSR,0x1B,0x30);
4719 andSISIDXREG(SISSR,0x17,0xF8);
4720 orSISIDXREG(SISSR,0x19,0x03);
4721 andSIDIDXREG(SISSR,0x13,0x00);
4723 /* Need to map max FB size for finding out about RAM size */
4724 ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000);
4725 if(ivideo->video_vbase) {
4726 /* Find out about bus width */
4728 outSISIDXREG(SISSR,0x14,0x02);
4729 andSISIDXREG(SISSR,0x16,0x0F);
4730 orSISIDXREG(SISSR,0x16,0x80);
4740 /* Find out about size */
4743 iounmap(ivideo->video_vbase);
4745 printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4746 outSISIDXREG(SISSR,0x14,0x??); /* 8MB, 64bit default */
4749 /* AGP (Missing: Checks for VIA and AMD hosts) */
4750 v1 = 0xA5; v2 = 0xFB;
4751 if(ivideo->sishw_ext.UseROM) {
4752 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9A];
4753 v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9B];
4755 outSISIDXREG(SISSR,0x21,v1);
4756 outSISIDXREG(SISSR,0x22,v2);
4764 int __devinit sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
4766 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
4767 struct sis_video_info *ivideo = NULL;
4768 struct fb_info *sis_fb_info = NULL;
4771 int sisvga_enabled = 0, i;
4773 if(sisfb_off) return -ENXIO;
4775 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
4776 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
4777 if(!sis_fb_info) return -ENOMEM;
4779 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
4780 if(!sis_fb_info) return -ENOMEM;
4781 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
4782 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
4785 ivideo = (struct sis_video_info *)sis_fb_info->par;
4786 ivideo->memyselfandi = sis_fb_info;
4788 if(card_list == NULL) {
4789 ivideo->cardnumber = 0;
4791 struct sis_video_info *countvideo = card_list;
4792 ivideo->cardnumber = 1;
4793 while((countvideo = countvideo->next) != NULL) ivideo->cardnumber++;
4796 strncpy(ivideo->myid, chipinfo->chip_name, 30);
4798 ivideo->warncount = 0;
4799 ivideo->chip_id = pdev->device;
4800 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
4801 ivideo->sishw_ext.jChipRevision = ivideo->revision_id;
4802 pci_read_config_word(pdev, PCI_COMMAND, ®16);
4803 sisvga_enabled = reg16 & 0x01;
4804 ivideo->pcibus = pdev->bus->number;
4805 ivideo->pcislot = PCI_SLOT(pdev->devfn);
4806 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
4807 ivideo->subsysvendor = pdev->subsystem_vendor;
4808 ivideo->subsysdevice = pdev->subsystem_device;
4811 if(sisfb_mode_idx == -1) {
4812 sisfb_get_vga_mode_from_kernel();
4816 ivideo->chip = chipinfo->chip;
4817 ivideo->sisvga_engine = chipinfo->vgaengine;
4818 ivideo->hwcursor_size = chipinfo->hwcursor_size;
4819 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
4820 ivideo->mni = chipinfo->mni;
4822 ivideo->detectedpdc = 0xff;
4823 ivideo->detectedpdca = 0xff;
4824 ivideo->detectedlcda = 0xff;
4826 ivideo->sisfb_thismonitor.datavalid = FALSE;
4828 ivideo->sisfb_parm_mem = sisfb_parm_mem;
4829 ivideo->sisfb_accel = sisfb_accel;
4830 ivideo->sisfb_ypan = sisfb_ypan;
4831 ivideo->sisfb_max = sisfb_max;
4832 ivideo->sisfb_userom = sisfb_userom;
4833 ivideo->sisfb_useoem = sisfb_useoem;
4834 ivideo->sisfb_mode_idx = sisfb_mode_idx;
4835 ivideo->sisfb_parm_rate = sisfb_parm_rate;
4836 ivideo->sisfb_crt1off = sisfb_crt1off;
4837 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
4838 ivideo->sisfb_crt2type = sisfb_crt2type;
4839 ivideo->sisfb_crt2flags = sisfb_crt2flags;
4840 /* pdc(a), scalelcd, special timing, lvdshl handled below */
4841 ivideo->sisfb_dstn = sisfb_dstn;
4842 ivideo->sisfb_fstn = sisfb_fstn;
4843 ivideo->sisfb_tvplug = sisfb_tvplug;
4844 ivideo->sisfb_tvstd = sisfb_tvstd;
4845 ivideo->tvxpos = sisfb_tvxposoffset;
4846 ivideo->tvypos = sisfb_tvyposoffset;
4847 ivideo->sisfb_filter = sisfb_filter;
4848 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
4849 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4850 ivideo->sisfb_inverse = sisfb_inverse;
4853 ivideo->refresh_rate = 0;
4854 if(ivideo->sisfb_parm_rate != -1) {
4855 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
4858 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
4859 ivideo->SiS_Pr.CenterScreen = -1;
4860 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
4861 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
4863 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
4864 ivideo->SiS_Pr.SiS_CHOverScan = -1;
4865 ivideo->SiS_Pr.SiS_ChSW = FALSE;
4866 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
4867 ivideo->SiS_Pr.HaveEMI = FALSE;
4868 ivideo->SiS_Pr.HaveEMILCD = FALSE;
4869 ivideo->SiS_Pr.OverruleEMI = FALSE;
4870 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
4871 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
4872 ivideo->SiS_Pr.PDC = -1;
4873 ivideo->SiS_Pr.PDCA = -1;
4874 #ifdef CONFIG_FB_SIS_315
4875 if(ivideo->chip >= SIS_330) {
4876 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
4877 if(ivideo->chip >= SIS_661) {
4878 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
4883 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
4885 pci_set_drvdata(pdev, ivideo);
4887 /* Patch special cases */
4888 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
4889 switch(ivideo->nbridge->device) {
4890 #ifdef CONFIG_FB_SIS_300
4891 case PCI_DEVICE_ID_SI_730:
4892 ivideo->chip = SIS_730;
4893 strcpy(ivideo->myid, "SiS 730");
4896 #ifdef CONFIG_FB_SIS_315
4897 case PCI_DEVICE_ID_SI_651:
4898 /* ivideo->chip is ok */
4899 strcpy(ivideo->myid, "SiS 651");
4901 case PCI_DEVICE_ID_SI_740:
4902 ivideo->chip = SIS_740;
4903 strcpy(ivideo->myid, "SiS 740");
4905 case PCI_DEVICE_ID_SI_661:
4906 ivideo->chip = SIS_661;
4907 strcpy(ivideo->myid, "SiS 661");
4909 case PCI_DEVICE_ID_SI_741:
4910 ivideo->chip = SIS_741;
4911 strcpy(ivideo->myid, "SiS 741");
4913 case PCI_DEVICE_ID_SI_760:
4914 ivideo->chip = SIS_760;
4915 strcpy(ivideo->myid, "SiS 760");
4921 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4922 strcpy(sis_fb_info->modename, ivideo->myid);
4925 ivideo->sishw_ext.jChipType = ivideo->chip;
4927 #ifdef CONFIG_FB_SIS_315
4928 if((ivideo->sishw_ext.jChipType == SIS_315PRO) ||
4929 (ivideo->sishw_ext.jChipType == SIS_315)) {
4930 ivideo->sishw_ext.jChipType = SIS_315H;
4934 ivideo->video_base = pci_resource_start(pdev, 0);
4935 ivideo->mmio_base = pci_resource_start(pdev, 1);
4936 ivideo->mmio_size = pci_resource_len(pdev, 1);
4937 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
4938 ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
4940 if(!sisvga_enabled) {
4941 if(pci_enable_device(pdev)) {
4942 pci_set_drvdata(pdev, NULL);
4948 SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress);
4950 #ifdef CONFIG_FB_SIS_300
4951 /* Find PCI systems for Chrontel/GPIO communication setup */
4952 if(ivideo->chip == SIS_630) {
4955 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
4956 mychswtable[i].subsysCard == ivideo->subsysdevice) {
4957 ivideo->SiS_Pr.SiS_ChSW = TRUE;
4958 printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
4959 mychswtable[i].vendorName, mychswtable[i].cardName);
4963 } while(mychswtable[i].subsysVendor != 0);
4967 outSISIDXREG(SISSR, 0x05, 0x86);
4969 if( (!sisvga_enabled)
4970 #if !defined(__i386__) && !defined(__x86_64__)
4971 || (sisfb_resetcard)
4974 for(i = 0x30; i <= 0x3f; i++) {
4975 outSISIDXREG(SISCR,i,0x00);
4979 /* Find out about current video mode */
4980 ivideo->modeprechange = 0x03;
4981 inSISIDXREG(SISCR,0x34,reg);
4983 ivideo->modeprechange = reg & 0x7f;
4984 } else if(sisvga_enabled) {
4985 #if defined(__i386__) || defined(__x86_64__)
4986 unsigned char SIS_IOTYPE2 *tt = ioremap(0, 0x1000);
4988 ivideo->modeprechange = readb(tt + 0x449);
4994 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4996 if((reg & 0x80) && (reg != 0xff)) {
4997 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) {
4998 printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
4999 pci_set_drvdata(pdev, NULL);
5007 ivideo->sishw_ext.bIntegratedMMEnabled = TRUE;
5008 #ifdef CONFIG_FB_SIS_300
5009 if(ivideo->sisvga_engine == SIS_300_VGA) {
5010 if(ivideo->chip != SIS_300) {
5011 inSISIDXREG(SISSR, 0x1a, reg);
5013 ivideo->sishw_ext.bIntegratedMMEnabled = FALSE;
5019 ivideo->bios_abase = NULL;
5020 if(ivideo->sisfb_userom) {
5021 ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
5022 ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase;
5023 if(ivideo->sishw_ext.pjVirtualRomBase) {
5024 printk(KERN_INFO "sisfb: Video ROM found and copied\n");
5025 ivideo->sishw_ext.UseROM = TRUE;
5027 ivideo->sishw_ext.UseROM = FALSE;
5028 printk(KERN_INFO "sisfb: Video ROM not found\n");
5031 ivideo->sishw_ext.pjVirtualRomBase = NULL;
5032 ivideo->sishw_ext.UseROM = FALSE;
5033 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
5036 /* Find systems for special custom timing */
5037 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
5039 unsigned char *biosver = NULL;
5040 unsigned char *biosdate = NULL;
5044 if(ivideo->sishw_ext.UseROM) {
5045 biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
5046 biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
5047 for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
5052 if( (mycustomttable[i].chipID == ivideo->chip) &&
5053 ((!strlen(mycustomttable[i].biosversion)) ||
5054 (ivideo->sishw_ext.UseROM &&
5055 (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
5056 ((!strlen(mycustomttable[i].biosdate)) ||
5057 (ivideo->sishw_ext.UseROM &&
5058 (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
5059 ((!mycustomttable[i].bioschksum) ||
5060 (ivideo->sishw_ext.UseROM &&
5061 (mycustomttable[i].bioschksum == chksum))) &&
5062 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
5063 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
5065 for(j = 0; j < 5; j++) {
5066 if(mycustomttable[i].biosFootprintAddr[j]) {
5067 if(ivideo->sishw_ext.UseROM) {
5068 if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
5069 mycustomttable[i].biosFootprintData[j]) {
5072 } else footprint = FALSE;
5076 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
5077 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
5078 mycustomttable[i].vendorName,
5079 mycustomttable[i].cardName);
5080 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
5081 mycustomttable[i].optionName);
5086 } while(mycustomttable[i].chipID);
5089 #ifdef CONFIG_FB_SIS_300
5090 if(ivideo->sisvga_engine == SIS_300_VGA) {
5091 if( (!sisvga_enabled)
5092 #if !defined(__i386__) && !defined(__x86_64__)
5093 || (sisfb_resetcard)
5096 if(ivideo->chip == SIS_300) {
5097 sisfb_post_sis300(pdev);
5103 #ifdef CONFIG_FB_SIS_315
5104 if(ivideo->sisvga_engine == SIS_315_VGA) {
5105 if( (!sisvga_enabled)
5106 #if !defined(__i386__) && !defined(__x86_64__)
5107 || (sisfb_resetcard)
5110 if((ivideo->chip == SIS_315H) ||
5111 (ivideo->chip == SIS_315) ||
5112 (ivideo->chip == SIS_315PRO) ||
5113 (ivideo->chip == SIS_330)) {
5114 sisfb_post_sis315330(pdev);
5120 if(sisfb_get_dram_size(ivideo)) {
5121 printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
5122 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5123 pci_set_drvdata(pdev, NULL);
5128 if((ivideo->sisfb_mode_idx < 0) ||
5129 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5130 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
5131 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
5132 /* Enable 2D accelerator engine */
5133 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
5136 if(sisfb_pdc != 0xff) {
5137 if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
5138 else sisfb_pdc &= 0x1f;
5139 ivideo->SiS_Pr.PDC = sisfb_pdc;
5141 #ifdef CONFIG_FB_SIS_315
5142 if(ivideo->sisvga_engine == SIS_315_VGA) {
5143 if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
5147 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
5148 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
5149 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
5150 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5151 pci_set_drvdata(pdev, NULL);
5156 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
5157 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
5158 release_mem_region(ivideo->video_base, ivideo->video_size);
5159 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5160 pci_set_drvdata(pdev, NULL);
5165 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
5166 ivideo->sishw_ext.pjVideoMemoryAddress = ivideo->video_vbase;
5167 if(!ivideo->video_vbase) {
5168 printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
5169 release_mem_region(ivideo->video_base, ivideo->video_size);
5170 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5171 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5172 pci_set_drvdata(pdev, NULL);
5177 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
5178 if(!ivideo->mmio_vbase) {
5179 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
5180 iounmap(ivideo->video_vbase);
5181 release_mem_region(ivideo->video_base, ivideo->video_size);
5182 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5183 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5184 pci_set_drvdata(pdev, NULL);
5189 printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n",
5190 ivideo->video_base, (ULONG)ivideo->video_vbase, ivideo->video_size / 1024);
5192 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
5193 ivideo->mmio_base, (ULONG)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
5195 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
5196 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
5199 /* Used for clearing the screen only, therefore respect our mem limit */
5200 ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
5204 ivideo->vbflags = 0;
5205 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
5206 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
5207 ivideo->defmodeidx = DEFAULT_MODE;
5209 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
5211 if((ivideo->sisfb_mode_idx < 0) ||
5212 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5214 sisfb_sense_crt1(ivideo);
5216 sisfb_get_VB_type(ivideo);
5218 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5219 sisfb_detect_VB_connect(ivideo);
5222 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
5224 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5225 if(ivideo->sisfb_crt2type != -1) {
5226 if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
5227 ivideo->currentvbflags |= CRT2_LCD;
5228 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
5229 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
5232 /* Chrontel 700x TV detection often unreliable, therefore use a
5233 * different default order on such machines
5235 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
5236 if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5237 else if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
5238 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5240 if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
5241 else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5242 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5247 if(ivideo->vbflags & CRT2_LCD) {
5248 inSISIDXREG(SISCR, 0x36, reg);
5250 if(ivideo->sisvga_engine == SIS_300_VGA) {
5251 ivideo->CRT2LCDType = sis300paneltype[reg];
5252 } else if(ivideo->chip >= SIS_661) {
5253 ivideo->CRT2LCDType = sis661paneltype[reg];
5255 ivideo->CRT2LCDType = sis310paneltype[reg];
5256 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
5257 if((ivideo->CRT2LCDType != LCD_640x480_2) &&
5258 (ivideo->CRT2LCDType != LCD_640x480_3)) {
5259 ivideo->CRT2LCDType = LCD_320x480;
5263 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
5264 /* For broken BIOSes: Assume 1024x768, RGB18 */
5265 ivideo->CRT2LCDType = LCD_1024x768;
5266 setSISIDXREG(SISCR,0x36,0xf0,0x02);
5267 setSISIDXREG(SISCR,0x37,0xee,0x01);
5268 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
5270 for(i = 0; i < SIS_LCD_NUMBER; i++) {
5271 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
5272 ivideo->lcdxres = sis_lcd_data[i].xres;
5273 ivideo->lcdyres = sis_lcd_data[i].yres;
5274 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
5278 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
5279 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
5280 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
5281 ivideo->lcdxres = 848; ivideo->lcdyres = 480; ivideo->lcddefmodeidx = 47;
5283 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
5284 ivideo->lcdxres, ivideo->lcdyres);
5287 #ifdef CONFIG_FB_SIS_300
5288 /* Save the current PanelDelayCompensation if the LCD is currently used */
5289 if(ivideo->sisvga_engine == SIS_300_VGA) {
5290 if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
5292 inSISIDXREG(SISCR,0x30,tmp);
5294 /* Currently on LCD? If yes, read current pdc */
5295 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
5296 ivideo->detectedpdc &= 0x3c;
5297 if(ivideo->SiS_Pr.PDC == -1) {
5298 /* Let option override detection */
5299 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5301 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
5302 ivideo->detectedpdc);
5304 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5305 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
5306 ivideo->SiS_Pr.PDC);
5312 #ifdef CONFIG_FB_SIS_315
5313 if(ivideo->sisvga_engine == SIS_315_VGA) {
5315 /* Try to find about LCDA */
5316 if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
5318 inSISIDXREG(SISPART1,0x13,tmp);
5320 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
5321 ivideo->detectedlcda = 0x03;
5326 if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
5328 inSISIDXREG(SISCR,0x30,tmp);
5329 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5330 /* Currently on LCD? If yes, read current pdc */
5332 inSISIDXREG(SISPART1,0x2D,pdc);
5333 ivideo->detectedpdc = (pdc & 0x0f) << 1;
5334 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
5335 inSISIDXREG(SISPART1,0x35,pdc);
5336 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
5337 inSISIDXREG(SISPART1,0x20,pdc);
5338 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
5339 if(ivideo->newrom) {
5340 /* New ROM invalidates other PDC resp. */
5341 if(ivideo->detectedlcda != 0xff) {
5342 ivideo->detectedpdc = 0xff;
5344 ivideo->detectedpdca = 0xff;
5347 if(ivideo->SiS_Pr.PDC == -1) {
5348 if(ivideo->detectedpdc != 0xff) {
5349 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5352 if(ivideo->SiS_Pr.PDCA == -1) {
5353 if(ivideo->detectedpdca != 0xff) {
5354 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
5357 if(ivideo->detectedpdc != 0xff) {
5359 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
5360 ivideo->detectedpdc);
5362 if(ivideo->detectedpdca != 0xff) {
5364 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
5365 ivideo->detectedpdca);
5370 if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
5371 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
5372 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
5373 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
5374 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
5375 ivideo->SiS_Pr.HaveEMI = TRUE;
5376 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5377 ivideo->SiS_Pr.HaveEMILCD = TRUE;
5382 /* Let user override detected PDCs (all bridges) */
5383 if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
5384 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5385 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
5386 ivideo->SiS_Pr.PDC);
5388 if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
5389 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
5390 ivideo->SiS_Pr.PDCA);
5397 if(!ivideo->sisfb_crt1off) {
5398 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
5400 if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
5401 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
5402 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
5406 if(ivideo->sisfb_mode_idx >= 0) {
5407 int bu = ivideo->sisfb_mode_idx;
5408 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
5409 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
5410 if(bu != ivideo->sisfb_mode_idx) {
5411 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
5412 sisbios_mode[bu].xres,
5413 sisbios_mode[bu].yres,
5414 sisbios_mode[bu].bpp);
5418 if(ivideo->sisfb_mode_idx < 0) {
5419 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
5421 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
5424 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
5427 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
5432 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
5434 if(ivideo->refresh_rate != 0) {
5435 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
5438 if(ivideo->rate_idx == 0) {
5439 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
5440 ivideo->refresh_rate = 60;
5443 if(ivideo->sisfb_thismonitor.datavalid) {
5444 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
5445 ivideo->rate_idx, ivideo->refresh_rate)) {
5446 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
5450 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
5451 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
5452 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
5454 sisfb_set_vparms(ivideo);
5456 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5458 /* ---------------- For 2.4: Now switch the mode ------------------ */
5460 printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
5461 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5462 ivideo->refresh_rate);
5464 sisfb_pre_setmode(ivideo);
5466 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
5467 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
5469 iounmap(ivideo->video_vbase);
5470 iounmap(ivideo->mmio_vbase);
5471 release_mem_region(ivideo->video_base, ivideo->video_size);
5472 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5473 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5474 pci_set_drvdata(pdev, NULL);
5479 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
5481 sisfb_post_setmode(ivideo);
5483 /* Maximize regardless of sisfb_max at startup */
5484 ivideo->default_var.yres_virtual = 32767;
5486 /* Force reset of x virtual in crtc_to_var */
5487 ivideo->default_var.xres_virtual = 0;
5489 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
5491 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5492 sisfb_set_pitch(ivideo);
5495 if(ivideo->sisfb_accel) {
5497 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5499 sisfb_initaccel(ivideo);
5501 sis_fb_info->node = -1;
5502 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5503 sis_fb_info->fbops = &sisfb_ops;
5504 sis_fb_info->disp = &ivideo->sis_disp;
5505 sis_fb_info->blank = &sisfb_blank;
5506 sis_fb_info->switch_con = &sisfb_switch;
5507 sis_fb_info->updatevar = &sisfb_update_var;
5508 sis_fb_info->changevar = NULL;
5509 strcpy(sis_fb_info->fontname, sisfb_fontname);
5511 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
5513 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
5515 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
5516 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5517 ivideo->refresh_rate);
5519 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
5520 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
5521 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
5523 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
5525 ivideo->default_var.pixclock = (u32) (1000000000 /
5526 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5527 ivideo->mode_no, ivideo->rate_idx));
5529 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5530 ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
5531 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
5532 ivideo->default_var.pixclock <<= 1;
5536 if(ivideo->sisfb_ypan) {
5537 /* Maximize regardless of sisfb_max at startup */
5538 ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var);
5539 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
5540 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
5544 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5547 if(ivideo->sisfb_accel) {
5549 #ifdef STUPID_ACCELF_TEXT_SHIT
5550 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5553 sisfb_initaccel(ivideo);
5555 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
5556 sis_fb_info->flags = FBINFO_DEFAULT |
5557 FBINFO_HWACCEL_YPAN |
5558 FBINFO_HWACCEL_XPAN |
5559 FBINFO_HWACCEL_COPYAREA |
5560 FBINFO_HWACCEL_FILLRECT |
5561 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
5563 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5565 sis_fb_info->var = ivideo->default_var;
5566 sis_fb_info->fix = ivideo->sisfb_fix;
5567 sis_fb_info->screen_base = ivideo->video_vbase;
5568 sis_fb_info->fbops = &sisfb_ops;
5570 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
5571 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
5573 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
5576 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
5579 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
5580 MTRR_TYPE_WRCOMB, 1);
5582 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
5586 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5587 vc_resize_con(1, 1, 0);
5590 if(register_framebuffer(sis_fb_info) < 0) {
5591 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
5592 iounmap(ivideo->video_vbase);
5593 iounmap(ivideo->mmio_vbase);
5594 release_mem_region(ivideo->video_base, ivideo->video_size);
5595 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5596 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5597 pci_set_drvdata(pdev, NULL);
5602 ivideo->registered = 1;
5605 ivideo->next = card_list;
5608 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
5609 ivideo->sisfb_accel ? "enabled" : "disabled",
5610 ivideo->sisfb_ypan ?
5611 (ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
5614 printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n",
5615 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5616 GET_FB_IDX(sis_fb_info->node),
5620 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
5622 printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
5624 } /* if mode = "none" */
5629 /*****************************************************/
5630 /* PCI DEVICE HANDLING */
5631 /*****************************************************/
5633 static void __devexit sisfb_remove(struct pci_dev *pdev)
5635 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5636 struct fb_info *sis_fb_info = ivideo->memyselfandi;
5637 int registered = ivideo->registered;
5640 iounmap(ivideo->video_vbase);
5641 iounmap(ivideo->mmio_vbase);
5642 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5644 /* Release mem regions */
5645 release_mem_region(ivideo->video_base, ivideo->video_size);
5646 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5649 /* Release MTRR region */
5651 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
5655 /* Unregister the framebuffer */
5656 if(ivideo->registered) {
5657 unregister_framebuffer(sis_fb_info);
5658 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5659 framebuffer_release(sis_fb_info);
5665 pci_set_drvdata(pdev, NULL);
5667 /* TODO: Restore the initial mode
5668 * This sounds easy but is as good as impossible
5669 * on many machines with SiS chip and video bridge
5670 * since text modes are always set up differently
5671 * from machine to machine. Depends on the type
5672 * of integration between chipset and bridge.
5675 printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
5679 static struct pci_driver sisfb_driver = {
5681 .id_table = sisfb_pci_table,
5682 .probe = sisfb_probe,
5683 .remove = __devexit_p(sisfb_remove)
5686 SISINITSTATIC int __init sisfb_init(void)
5688 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5690 char *options = NULL;
5692 if(fb_get_options("sisfb", &options))
5694 sisfb_setup(options);
5697 return(pci_module_init(&sisfb_driver));
5700 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5702 module_init(sisfb_init);
5706 /*****************************************************/
5708 /*****************************************************/
5712 static char *mode = NULL;
5713 static int vesa = -1;
5714 static unsigned int rate = 0;
5715 static unsigned int crt1off = 1;
5716 static unsigned int mem = 0;
5717 static char *forcecrt2type = NULL;
5718 static int forcecrt1 = -1;
5719 static int pdc = -1;
5720 static int pdc1 = -1;
5721 static int noaccel = -1;
5722 static int noypan = -1;
5723 static int nomax = -1;
5724 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5725 static int inverse = 0;
5727 static int userom = -1;
5728 static int useoem = -1;
5729 static char *tvstandard = NULL;
5730 static int nocrt2rate = 0;
5731 static int scalelcd = -1;
5732 static char *specialtiming = NULL;
5733 static int lvdshl = -1;
5734 static int tvxposoffset = 0, tvyposoffset = 0;
5735 static int filter = -1;
5736 #if !defined(__i386__) && !defined(__x86_64__)
5737 static int resetcard = 0;
5738 static int videoram = 0;
5741 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
5742 MODULE_LICENSE("GPL");
5743 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
5745 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5746 MODULE_PARM(mem, "i");
5747 MODULE_PARM(noaccel, "i");
5748 MODULE_PARM(noypan, "i");
5749 MODULE_PARM(nomax, "i");
5750 MODULE_PARM(userom, "i");
5751 MODULE_PARM(useoem, "i");
5752 MODULE_PARM(mode, "s");
5753 MODULE_PARM(vesa, "i");
5754 MODULE_PARM(rate, "i");
5755 MODULE_PARM(forcecrt1, "i");
5756 MODULE_PARM(forcecrt2type, "s");
5757 MODULE_PARM(scalelcd, "i");
5758 MODULE_PARM(pdc, "i");
5759 MODULE_PARM(pdc1, "i");
5760 MODULE_PARM(specialtiming, "s");
5761 MODULE_PARM(lvdshl, "i");
5762 MODULE_PARM(tvstandard, "s");
5763 MODULE_PARM(tvxposoffset, "i");
5764 MODULE_PARM(tvyposoffset, "i");
5765 MODULE_PARM(filter, "i");
5766 MODULE_PARM(nocrt2rate, "i");
5767 MODULE_PARM(inverse, "i");
5768 #if !defined(__i386__) && !defined(__x86_64__)
5769 MODULE_PARM(resetcard, "i");
5770 MODULE_PARM(videoram, "i");
5774 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5775 module_param(mem, int, 0);
5776 module_param(noaccel, int, 0);
5777 module_param(noypan, int, 0);
5778 module_param(nomax, int, 0);
5779 module_param(userom, int, 0);
5780 module_param(useoem, int, 0);
5781 module_param(mode, charp, 0);
5782 module_param(vesa, int, 0);
5783 module_param(rate, int, 0);
5784 module_param(forcecrt1, int, 0);
5785 module_param(forcecrt2type, charp, 0);
5786 module_param(scalelcd, int, 0);
5787 module_param(pdc, int, 0);
5788 module_param(pdc1, int, 0);
5789 module_param(specialtiming, charp, 0);
5790 module_param(lvdshl, int, 0);
5791 module_param(tvstandard, charp, 0);
5792 module_param(tvxposoffset, int, 0);
5793 module_param(tvyposoffset, int, 0);
5794 module_param(filter, int, 0);
5795 module_param(nocrt2rate, int, 0);
5796 #if !defined(__i386__) && !defined(__x86_64__)
5797 module_param(resetcard, int, 0);
5798 module_param(videoram, int, 0);
5802 MODULE_PARM_DESC(mem,
5803 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
5804 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
5805 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
5806 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
5807 "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
5808 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
5809 "for XFree86 4.x/X.org 6.7 and later.\n");
5811 MODULE_PARM_DESC(noaccel,
5812 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
5815 MODULE_PARM_DESC(noypan,
5816 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
5817 "will be performed by redrawing the screen. (default: 0)\n");
5819 MODULE_PARM_DESC(nomax,
5820 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
5821 "memory for the virtual screen in order to optimize scrolling performance. If\n"
5822 "this is set to anything other than 0, sisfb will not do this and thereby \n"
5823 "enable the user to positively specify a virtual Y size of the screen using\n"
5824 "fbset. (default: 0)\n");
5826 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5827 MODULE_PARM_DESC(mode,
5828 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
5829 "1024x768x16. Other formats supported include XxY-Depth and\n"
5830 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5831 "number, it will be interpreted as a VESA mode number. (default: none if\n"
5832 "sisfb is a module; this leaves the console untouched and the driver will\n"
5833 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
5834 "is in the kernel)\n");
5835 MODULE_PARM_DESC(vesa,
5836 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
5837 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
5838 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
5839 "0x0103 if sisfb is in the kernel)\n");
5842 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5843 MODULE_PARM_DESC(mode,
5844 "\nSelects the desired default display mode in the format XxYxDepth,\n"
5845 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
5846 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5847 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
5849 MODULE_PARM_DESC(vesa,
5850 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
5851 "0x117 (default: 0x0103)\n");
5854 MODULE_PARM_DESC(rate,
5855 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
5856 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
5857 "will be ignored (default: 60)\n");
5859 MODULE_PARM_DESC(forcecrt1,
5860 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
5861 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
5862 "0=CRT1 OFF) (default: [autodetected])\n");
5864 MODULE_PARM_DESC(forcecrt2type,
5865 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
5866 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
5867 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
5868 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
5869 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
5870 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
5871 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
5872 "depends on the very hardware in use. (default: [autodetected])\n");
5874 MODULE_PARM_DESC(scalelcd,
5875 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
5876 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
5877 "show black bars around the image, TMDS panels will probably do the scaling\n"
5878 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
5880 MODULE_PARM_DESC(pdc,
5881 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
5882 "should detect this correctly in most cases; however, sometimes this is not\n"
5883 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
5884 "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
5885 "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
5886 "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
5888 #ifdef CONFIG_FB_SIS_315
5889 MODULE_PARM_DESC(pdc1,
5890 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
5891 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
5892 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
5893 "implemented yet.\n");
5896 MODULE_PARM_DESC(specialtiming,
5897 "\nPlease refer to documentation for more information on this option.\n");
5899 MODULE_PARM_DESC(lvdshl,
5900 "\nPlease refer to documentation for more information on this option.\n");
5902 MODULE_PARM_DESC(tvstandard,
5903 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
5904 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
5906 MODULE_PARM_DESC(tvxposoffset,
5907 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
5910 MODULE_PARM_DESC(tvyposoffset,
5911 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
5914 MODULE_PARM_DESC(filter,
5915 "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
5916 "(Possible values 0-7, default: [no filter])\n");
5918 MODULE_PARM_DESC(nocrt2rate,
5919 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
5920 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
5922 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5923 MODULE_PARM_DESC(inverse,
5924 "\nSetting this to anything but 0 should invert the display colors, but this\n"
5925 "does not seem to work. (default: 0)\n");
5928 #if !defined(__i386__) && !defined(__x86_64__)
5929 #ifdef CONFIG_FB_SIS_300
5930 MODULE_PARM_DESC(resetcard,
5931 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
5932 "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
5935 MODULE_PARM_DESC(videoram,
5936 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
5937 "some non-x86 architectures where the memory auto detection fails. Only\n"
5938 "relevant if resetcard is set, too. Default: [auto-detect]\n");
5942 int __init sisfb_init_module(void)
5944 sisfb_setdefaultparms();
5946 if(rate) sisfb_parm_rate = rate;
5948 if((scalelcd == 0) || (scalelcd == 1)) {
5949 sisfb_scalelcd = scalelcd ^ 1;
5952 /* Need to check crt2 type first for fstn/dstn */
5955 sisfb_search_crt2type(forcecrt2type);
5958 sisfb_search_tvstd(tvstandard);
5961 sisfb_search_mode(mode, FALSE);
5963 sisfb_search_vesamode(vesa, FALSE);
5965 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
5967 sisfb_forcecrt1 = forcecrt1;
5968 if(forcecrt1 == 1) sisfb_crt1off = 0;
5969 else if(forcecrt1 == 0) sisfb_crt1off = 1;
5971 if(noaccel == 1) sisfb_accel = 0;
5972 else if(noaccel == 0) sisfb_accel = 1;
5974 if(noypan == 1) sisfb_ypan = 0;
5975 else if(noypan == 0) sisfb_ypan = 1;
5977 if(nomax == 1) sisfb_max = 0;
5978 else if(nomax == 0) sisfb_max = 1;
5980 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5981 if(inverse) sisfb_inverse = 1;
5984 if(mem) sisfb_parm_mem = mem;
5986 if(userom != -1) sisfb_userom = userom;
5987 if(useoem != -1) sisfb_useoem = useoem;
5989 if(pdc != -1) sisfb_pdc = (pdc & 0x7f);
5990 if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
5992 sisfb_nocrt2rate = nocrt2rate;
5995 sisfb_search_specialtiming(specialtiming);
5997 if((lvdshl >= 0) && (lvdshl <= 3)) sisfb_lvdshl = lvdshl;
5999 if(filter != -1) sisfb_filter = filter;
6001 sisfb_tvxposoffset = tvxposoffset;
6002 sisfb_tvyposoffset = tvyposoffset;
6004 #if !defined(__i386__) && !defined(__x86_64__)
6005 sisfb_resetcard = (resetcard) ? 1 : 0;
6006 if(videoram) sisfb_videoram = videoram;
6009 return(sisfb_init());
6012 static void __exit sisfb_remove_module(void)
6014 pci_unregister_driver(&sisfb_driver);
6015 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6018 module_init(sisfb_init_module);
6019 module_exit(sisfb_remove_module);
6021 #endif /* /MODULE */
6023 EXPORT_SYMBOL(sis_malloc);
6024 EXPORT_SYMBOL(sis_free);