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/smp_lock.h>
54 #include <linux/ioport.h>
55 #include <linux/init.h>
56 #include <linux/pci.h>
57 #include <linux/vmalloc.h>
58 #include <linux/vt_kern.h>
59 #include <linux/capability.h>
61 #include <linux/types.h>
62 #include <asm/uaccess.h>
68 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
69 #include <video/fbcon.h>
70 #include <video/fbcon-cfb8.h>
71 #include <video/fbcon-cfb16.h>
72 #include <video/fbcon-cfb24.h>
73 #include <video/fbcon-cfb32.h>
79 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
80 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
81 #error "This version of sisfb requires at least 2.6.3"
85 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
87 extern struct display_switch fbcon_sis8;
89 #ifdef FBCON_HAS_CFB16
90 extern struct display_switch fbcon_sis16;
92 #ifdef FBCON_HAS_CFB32
93 extern struct display_switch fbcon_sis32;
97 /* ------------------ Internal helper routines ----------------- */
100 sisfb_setdefaultparms(void)
110 /* Module: "None" for 2.4, default mode for 2.5+ */
111 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
114 sisfb_mode_idx = MODE_INDEX_NONE;
117 /* Static: Default mode */
120 sisfb_parm_rate = -1;
122 sisfb_forcecrt1 = -1;
128 sisfb_specialtiming = CUT_NONE;
134 sisfb_tvxposoffset = 0;
135 sisfb_tvyposoffset = 0;
137 sisfb_nocrt2rate = 0;
138 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
140 sisfb_fontname[0] = 0;
142 #if !defined(__i386__) && !defined(__x86_64__)
148 static void __devinit
149 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
153 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
156 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
157 sisfb_mode_idx = MODE_INDEX_NONE;
160 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
162 sisfb_mode_idx = DEFAULT_MODE;
167 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
169 while(sisbios_mode[i++].mode_no[0] != 0) {
170 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
171 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
173 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
174 sisbios_mode[i-1].mode_no[1] == 0x56 ||
175 sisbios_mode[i-1].mode_no[1] == 0x53) continue;
177 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
178 sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
180 sisfb_mode_idx = i - 1;
185 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
189 sisfb_search_mode(char *name, BOOLEAN quiet)
192 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
193 char strbuf[16], strbuf1[20];
194 char *nameptr = name;
196 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
200 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
202 sisfb_mode_idx = DEFAULT_MODE;
206 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
207 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
209 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
211 sisfb_mode_idx = DEFAULT_MODE;
215 if(strlen(name) <= 19) {
216 strcpy(strbuf1, name);
217 for(i=0; i<strlen(strbuf1); i++) {
218 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
221 /* This does some fuzzy mode naming detection */
222 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
223 if((rate <= 32) || (depth > 32)) {
224 j = rate; rate = depth; depth = j;
226 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
228 sisfb_parm_rate = rate;
229 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
230 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
234 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
235 sprintf(strbuf, "%ux%ux8", xres, yres);
238 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
245 while(sisbios_mode[i].mode_no[0] != 0) {
246 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
248 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
249 sisbios_mode[i-1].mode_no[1] == 0x56 ||
250 sisbios_mode[i-1].mode_no[1] == 0x53) continue;
252 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
253 sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
255 sisfb_mode_idx = i - 1;
260 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
264 static void __devinit
265 sisfb_get_vga_mode_from_kernel(void)
267 #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
269 int mydepth = screen_info.lfb_depth;
271 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
273 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
274 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
275 (mydepth >= 8) && (mydepth <= 32) ) {
277 if(mydepth == 24) mydepth = 32;
279 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
280 screen_info.lfb_height,
283 printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode);
285 sisfb_search_mode(mymode, TRUE);
293 sisfb_search_crt2type(const char *name)
297 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
299 if(name == NULL) return;
301 while(sis_crt2type[i].type_no != -1) {
302 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
303 sisfb_crt2type = sis_crt2type[i].type_no;
304 sisfb_tvplug = sis_crt2type[i].tvplug_no;
305 sisfb_crt2flags = sis_crt2type[i].flags;
311 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
312 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
314 if(sisfb_crt2type < 0) {
315 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
320 sisfb_search_tvstd(const char *name)
324 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
326 if(name == NULL) return;
328 while(sis_tvtype[i].type_no != -1) {
329 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
330 sisfb_tvstd = sis_tvtype[i].type_no;
338 sisfb_search_specialtiming(const char *name)
341 BOOLEAN found = FALSE;
343 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
345 if(name == NULL) return;
347 if(!strnicmp(name, "none", 4)) {
348 sisfb_specialtiming = CUT_FORCENONE;
349 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
351 while(mycustomttable[i].chipID != 0) {
352 if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {
353 sisfb_specialtiming = mycustomttable[i].SpecialID;
355 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
356 mycustomttable[i].vendorName, mycustomttable[i].cardName,
357 mycustomttable[i].optionName);
363 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
364 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
366 while(mycustomttable[i].chipID != 0) {
367 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
368 mycustomttable[i].optionName,
369 mycustomttable[i].vendorName,
370 mycustomttable[i].cardName);
377 static BOOLEAN __devinit
378 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
380 int i, j, xres, yres, refresh, index;
383 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
384 buffer[2] != 0xff || buffer[3] != 0xff ||
385 buffer[4] != 0xff || buffer[5] != 0xff ||
386 buffer[6] != 0xff || buffer[7] != 0x00) {
387 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
391 if(buffer[0x12] != 0x01) {
392 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
397 monitor->feature = buffer[0x18];
399 if(!buffer[0x14] & 0x80) {
400 if(!(buffer[0x14] & 0x08)) {
401 printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n");
405 if(buffer[0x13] >= 0x01) {
406 /* EDID V1 rev 1 and 2: Search for monitor descriptor
411 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
412 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
413 buffer[j + 4] == 0x00) {
414 monitor->hmin = buffer[j + 7];
415 monitor->hmax = buffer[j + 8];
416 monitor->vmin = buffer[j + 5];
417 monitor->vmax = buffer[j + 6];
418 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
419 monitor->datavalid = TRUE;
426 if(!monitor->datavalid) {
427 /* Otherwise: Get a range from the list of supported
428 * Estabished Timings. This is not entirely accurate,
429 * because fixed frequency monitors are not supported
432 monitor->hmin = 65535; monitor->hmax = 0;
433 monitor->vmin = 65535; monitor->vmax = 0;
434 monitor->dclockmax = 0;
435 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
436 for(i = 0; i < 13; i++) {
437 if(emodes & sisfb_ddcsmodes[i].mask) {
438 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
439 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
440 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
441 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
442 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
446 for(i = 0; i < 8; i++) {
447 xres = (buffer[index] + 31) * 8;
448 switch(buffer[index + 1] & 0xc0) {
449 case 0xc0: yres = (xres * 9) / 16; break;
450 case 0x80: yres = (xres * 4) / 5; break;
451 case 0x40: yres = (xres * 3) / 4; break;
452 default: yres = xres; break;
454 refresh = (buffer[index + 1] & 0x3f) + 60;
455 if((xres >= 640) && (yres >= 480)) {
456 for(j = 0; j < 8; j++) {
457 if((xres == sisfb_ddcfmodes[j].x) &&
458 (yres == sisfb_ddcfmodes[j].y) &&
459 (refresh == sisfb_ddcfmodes[j].v)) {
460 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
461 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
462 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
463 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
464 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
470 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
471 monitor->datavalid = TRUE;
475 return(monitor->datavalid);
478 static void __devinit
479 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
481 USHORT temp, i, realcrtno = crtno;
484 monitor->datavalid = FALSE;
487 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
488 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
492 if((ivideo->sisfb_crt1off) && (!crtno)) return;
494 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
495 realcrtno, 0, &buffer[0]);
496 if((!temp) || (temp == 0xffff)) {
497 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
500 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
501 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
503 (temp & 0x1a) ? "" : "[none of the supported]",
504 (temp & 0x02) ? "2 " : "",
505 (temp & 0x08) ? "D&P" : "",
506 (temp & 0x10) ? "FPDI-2" : "");
508 i = 3; /* Number of retrys */
510 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
511 realcrtno, 1, &buffer[0]);
512 } while((temp) && i--);
514 if(sisfb_interpret_edid(monitor, &buffer[0])) {
515 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
516 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
517 monitor->dclockmax / 1000);
519 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
522 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
525 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
531 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
532 int mode_idx, int rate_idx, int rate)
535 unsigned int dclock, hsync;
537 if(!monitor->datavalid) return TRUE;
539 if(mode_idx < 0) return FALSE;
541 /* Skip for 320x200, 320x240, 640x400 */
542 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
553 #ifdef CONFIG_FB_SIS_315
556 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
560 if(rate < (monitor->vmin - 1)) return FALSE;
561 if(rate > (monitor->vmax + 1)) return FALSE;
563 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, &ivideo->sishw_ext,
564 sisbios_mode[mode_idx].mode_no[ivideo->mni],
565 &htotal, &vtotal, rate_idx)) {
566 dclock = (htotal * vtotal * rate) / 1000;
567 if(dclock > (monitor->dclockmax + 1000)) return FALSE;
568 hsync = dclock / htotal;
569 if(hsync < (monitor->hmin - 1)) return FALSE;
570 if(hsync > (monitor->hmax + 1)) return FALSE;
578 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
580 u16 xres=0, yres, myres;
582 #ifdef CONFIG_FB_SIS_300
583 if(ivideo->sisvga_engine == SIS_300_VGA) {
584 if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1);
587 #ifdef CONFIG_FB_SIS_315
588 if(ivideo->sisvga_engine == SIS_315_VGA) {
589 if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1);
593 myres = sisbios_mode[myindex].yres;
595 switch(vbflags & VB_DISPTYPE_DISP2) {
599 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
601 if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) {
602 if(sisbios_mode[myindex].xres > xres) return(-1);
603 if(myres > yres) return(-1);
606 if(vbflags & (VB_LVDS | VB_30xBDH)) {
607 if(sisbios_mode[myindex].xres == 320) {
608 if((myres == 240) || (myres == 480)) {
609 if(!ivideo->sisfb_fstn) {
610 if(sisbios_mode[myindex].mode_no[1] == 0x5a ||
611 sisbios_mode[myindex].mode_no[1] == 0x5b)
614 if(sisbios_mode[myindex].mode_no[1] == 0x50 ||
615 sisbios_mode[myindex].mode_no[1] == 0x56 ||
616 sisbios_mode[myindex].mode_no[1] == 0x53)
623 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
624 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
625 ivideo->SiS_Pr.SiS_CustomT, xres, yres) < 0x14) {
631 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
632 sisbios_mode[myindex].yres, 0) < 0x14) {
638 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
639 sisbios_mode[myindex].yres, 0) < 0x14) {
649 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
654 xres = sisbios_mode[mode_idx].xres;
655 yres = sisbios_mode[mode_idx].yres;
657 ivideo->rate_idx = 0;
658 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
659 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
660 if(sisfb_vrate[i].refresh == rate) {
661 ivideo->rate_idx = sisfb_vrate[i].idx;
663 } else if(sisfb_vrate[i].refresh > rate) {
664 if((sisfb_vrate[i].refresh - rate) <= 3) {
665 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
666 rate, sisfb_vrate[i].refresh);
667 ivideo->rate_idx = sisfb_vrate[i].idx;
668 ivideo->refresh_rate = sisfb_vrate[i].refresh;
669 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
670 && (sisfb_vrate[i].idx != 1)) {
671 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
672 rate, sisfb_vrate[i-1].refresh);
673 ivideo->rate_idx = sisfb_vrate[i-1].idx;
674 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
677 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
678 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
679 rate, sisfb_vrate[i].refresh);
680 ivideo->rate_idx = sisfb_vrate[i].idx;
686 if(ivideo->rate_idx > 0) {
687 return ivideo->rate_idx;
689 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
696 sisfb_bridgeisslave(struct sis_video_info *ivideo)
700 if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE;
702 inSISIDXREG(SISPART1,0x00,P1_00);
703 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
704 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
712 sisfballowretracecrt1(struct sis_video_info *ivideo)
716 inSISIDXREG(SISCR,0x17,temp);
717 if(!(temp & 0x80)) return FALSE;
719 inSISIDXREG(SISSR,0x1f,temp);
720 if(temp & 0xc0) return FALSE;
726 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
728 if(!sisfballowretracecrt1(ivideo)) return FALSE;
730 if(inSISREG(SISINPSTAT) & 0x08) return TRUE;
735 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
739 if(!sisfballowretracecrt1(ivideo)) return;
742 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
744 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
748 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
750 unsigned char temp, reg;
752 switch(ivideo->sisvga_engine) {
753 case SIS_300_VGA: reg = 0x25; break;
754 case SIS_315_VGA: reg = 0x30; break;
755 default: return FALSE;
758 inSISIDXREG(SISPART1, reg, temp);
759 if(temp & 0x02) return TRUE;
764 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
766 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
767 if(sisfb_bridgeisslave(ivideo)) {
768 return(sisfbcheckvretracecrt1(ivideo));
770 return(sisfbcheckvretracecrt2(ivideo));
773 return(sisfbcheckvretracecrt1(ivideo));
777 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
779 u8 idx, reg1, reg2, reg3, reg4;
782 (*vcount) = (*hcount) = 0;
784 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
785 ret |= (FB_VBLANK_HAVE_VSYNC |
786 FB_VBLANK_HAVE_HBLANK |
787 FB_VBLANK_HAVE_VBLANK |
788 FB_VBLANK_HAVE_VCOUNT |
789 FB_VBLANK_HAVE_HCOUNT);
790 switch(ivideo->sisvga_engine) {
791 case SIS_300_VGA: idx = 0x25; break;
793 case SIS_315_VGA: idx = 0x30; break;
795 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
796 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
797 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
798 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
799 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
800 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
801 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
802 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
803 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
804 } else if(sisfballowretracecrt1(ivideo)) {
805 ret |= (FB_VBLANK_HAVE_VSYNC |
806 FB_VBLANK_HAVE_VBLANK |
807 FB_VBLANK_HAVE_VCOUNT |
808 FB_VBLANK_HAVE_HCOUNT);
809 reg1 = inSISREG(SISINPSTAT);
810 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
811 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
812 inSISIDXREG(SISCR,0x20,reg1);
813 inSISIDXREG(SISCR,0x1b,reg1);
814 inSISIDXREG(SISCR,0x1c,reg2);
815 inSISIDXREG(SISCR,0x1d,reg3);
816 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
817 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
823 sisfb_myblank(struct sis_video_info *ivideo, int blank)
825 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
826 BOOLEAN backlight = TRUE;
829 case FB_BLANK_UNBLANK: /* on */
838 case FB_BLANK_NORMAL: /* blank */
847 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
856 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
865 case FB_BLANK_POWERDOWN: /* off */
878 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
880 if( (!ivideo->sisfb_thismonitor.datavalid) ||
881 ((ivideo->sisfb_thismonitor.datavalid) &&
882 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
884 if(ivideo->sisvga_engine == SIS_315_VGA) {
885 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
888 if(!(sisfb_bridgeisslave(ivideo))) {
889 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
890 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
896 if(ivideo->currentvbflags & CRT2_LCD) {
898 if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
900 SiS_SiS30xBLOn(&ivideo->SiS_Pr, &ivideo->sishw_ext);
902 SiS_SiS30xBLOff(&ivideo->SiS_Pr, &ivideo->sishw_ext);
904 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
905 if(ivideo->vbflags & VB_CHRONTEL) {
907 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr,&ivideo->sishw_ext);
909 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
914 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
915 (ivideo->vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
916 ((ivideo->sisvga_engine == SIS_315_VGA) &&
917 ((ivideo->vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
918 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
921 if(ivideo->sisvga_engine == SIS_300_VGA) {
922 if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
923 (!(ivideo->vbflags & VB_30xBDH))) {
924 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
926 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
927 if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
928 (!(ivideo->vbflags & VB_30xBDH))) {
929 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
933 } else if(ivideo->currentvbflags & CRT2_VGA) {
935 if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) {
936 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
944 /* ----------- FBDev related routines for all series ----------- */
947 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
949 return (var->bits_per_pixel == 8) ? 256 : 16;
953 sisfb_set_vparms(struct sis_video_info *ivideo)
955 switch(ivideo->video_bpp) {
957 ivideo->DstColor = 0x0000;
958 ivideo->SiS310_AccelDepth = 0x00000000;
959 ivideo->video_cmap_len = 256;
962 ivideo->DstColor = 0x8000;
963 ivideo->SiS310_AccelDepth = 0x00010000;
964 ivideo->video_cmap_len = 16;
967 ivideo->DstColor = 0xC000;
968 ivideo->SiS310_AccelDepth = 0x00020000;
969 ivideo->video_cmap_len = 16;
972 ivideo->video_cmap_len = 16;
973 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
980 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
982 int maxyres = ivideo->heapstart / (var->xres_virtual * (var->bits_per_pixel >> 3));
984 if(maxyres > 32767) maxyres = 32767;
990 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
992 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
993 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
994 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
995 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
996 ivideo->scrnpitchCRT1 <<= 1;
1003 sisfb_set_pitch(struct sis_video_info *ivideo)
1005 BOOLEAN isslavemode = FALSE;
1006 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1007 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1009 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
1011 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1012 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1013 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1014 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1017 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1018 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1019 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1020 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1021 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1026 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1028 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1030 switch(var->bits_per_pixel) {
1032 var->red.offset = var->green.offset = var->blue.offset = 0;
1033 var->red.length = var->green.length = var->blue.length = 6;
1036 var->red.offset = 11;
1037 var->red.length = 5;
1038 var->green.offset = 5;
1039 var->green.length = 6;
1040 var->blue.offset = 0;
1041 var->blue.length = 5;
1042 var->transp.offset = 0;
1043 var->transp.length = 0;
1046 var->red.offset = 16;
1047 var->red.length = 8;
1048 var->green.offset = 8;
1049 var->green.length = 8;
1050 var->blue.offset = 0;
1051 var->blue.length = 8;
1052 var->transp.offset = 24;
1053 var->transp.length = 8;
1059 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1061 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1062 unsigned int htotal = 0, vtotal = 0;
1063 unsigned int drate = 0, hrate = 0;
1068 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1070 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1072 pixclock = var->pixclock;
1074 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1075 vtotal += var->yres;
1077 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1078 vtotal += var->yres;
1080 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1081 vtotal += var->yres;
1083 } else vtotal += var->yres;
1085 if(!(htotal) || !(vtotal)) {
1086 DPRINTK("sisfb: Invalid 'var' information\n");
1090 if(pixclock && htotal && vtotal) {
1091 drate = 1000000000 / pixclock;
1092 hrate = (drate * 1000) / htotal;
1093 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1095 ivideo->refresh_rate = 60;
1098 old_mode = ivideo->sisfb_mode_idx;
1099 ivideo->sisfb_mode_idx = 0;
1101 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1102 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1103 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1104 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1105 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1106 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1110 ivideo->sisfb_mode_idx++;
1114 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1115 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1117 ivideo->sisfb_mode_idx = -1;
1120 if(ivideo->sisfb_mode_idx < 0) {
1121 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1122 var->yres, var->bits_per_pixel);
1123 ivideo->sisfb_mode_idx = old_mode;
1127 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1128 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1129 ivideo->refresh_rate = 60;
1132 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1133 if(ivideo->sisfb_thismonitor.datavalid) {
1134 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
1135 ivideo->rate_idx, ivideo->refresh_rate)) {
1136 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1141 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1142 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1146 sisfb_pre_setmode(ivideo);
1148 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
1149 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1153 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1155 sisfb_post_setmode(ivideo);
1157 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1158 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1159 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1161 sisfb_calc_pitch(ivideo, var);
1162 sisfb_set_pitch(ivideo);
1165 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1166 #ifdef STUPID_ACCELF_TEXT_SHIT
1167 if(var->accel_flags & FB_ACCELF_TEXT) {
1168 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1170 info->flags |= FBINFO_HWACCEL_DISABLED;
1173 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1175 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1178 sisfb_set_vparms(ivideo);
1180 ivideo->current_width = ivideo->video_width;
1181 ivideo->current_height = ivideo->video_height;
1182 ivideo->current_bpp = ivideo->video_bpp;
1183 ivideo->current_htotal = htotal;
1184 ivideo->current_vtotal = vtotal;
1185 ivideo->current_linelength = ivideo->video_linelength;
1186 ivideo->current_pixclock = var->pixclock;
1187 ivideo->current_refresh_rate = ivideo->refresh_rate;
1188 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1189 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1197 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1201 if(var->xoffset > (var->xres_virtual - var->xres)) {
1204 if(var->yoffset > (var->yres_virtual - var->yres)) {
1208 base = (var->yoffset * var->xres_virtual) + var->xoffset;
1210 /* calculate base bpp dep. */
1211 switch(var->bits_per_pixel) {
1223 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1225 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1226 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1227 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1228 if(ivideo->sisvga_engine == SIS_315_VGA) {
1229 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1231 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1232 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1233 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1234 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1235 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1236 if(ivideo->sisvga_engine == SIS_315_VGA) {
1237 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1243 /* ------------ FBDev related routines for 2.4 series ----------- */
1245 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1248 sisfb_crtc_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1250 u16 VRE, VBE, VRS, VBS, VDE, VT;
1251 u16 HRE, HBE, HRS, HBS, HDE, HT;
1252 u8 sr_data, cr_data, cr_data2, cr_data3, mr_data;
1253 int A, B, C, D, E, F, temp;
1254 unsigned int hrate, drate, maxyres;
1256 inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
1258 if(sr_data & SIS_INTERLACED_MODE)
1259 var->vmode = FB_VMODE_INTERLACED;
1261 var->vmode = FB_VMODE_NONINTERLACED;
1263 switch((sr_data & 0x1C) >> 2) {
1264 case SIS_8BPP_COLOR_MODE:
1265 var->bits_per_pixel = 8;
1267 case SIS_16BPP_COLOR_MODE:
1268 var->bits_per_pixel = 16;
1270 case SIS_32BPP_COLOR_MODE:
1271 var->bits_per_pixel = 32;
1275 sisfb_bpp_to_var(ivideo, var);
1277 inSISIDXREG(SISSR, 0x0A, sr_data);
1278 inSISIDXREG(SISCR, 0x06, cr_data);
1279 inSISIDXREG(SISCR, 0x07, cr_data2);
1281 VT = (cr_data & 0xFF) |
1282 ((u16) (cr_data2 & 0x01) << 8) |
1283 ((u16) (cr_data2 & 0x20) << 4) |
1284 ((u16) (sr_data & 0x01) << 10);
1287 inSISIDXREG(SISCR, 0x12, cr_data);
1289 VDE = (cr_data & 0xff) |
1290 ((u16) (cr_data2 & 0x02) << 7) |
1291 ((u16) (cr_data2 & 0x40) << 3) |
1292 ((u16) (sr_data & 0x02) << 9);
1295 inSISIDXREG(SISCR, 0x10, cr_data);
1297 VRS = (cr_data & 0xff) |
1298 ((u16) (cr_data2 & 0x04) << 6) |
1299 ((u16) (cr_data2 & 0x80) << 2) |
1300 ((u16) (sr_data & 0x08) << 7);
1303 inSISIDXREG(SISCR, 0x15, cr_data);
1304 inSISIDXREG(SISCR, 0x09, cr_data3);
1306 if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE;
1308 VBS = (cr_data & 0xff) |
1309 ((u16) (cr_data2 & 0x08) << 5) |
1310 ((u16) (cr_data3 & 0x20) << 4) |
1311 ((u16) (sr_data & 0x04) << 8);
1313 inSISIDXREG(SISCR, 0x16, cr_data);
1315 VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
1316 temp = VBE - ((E - 1) & 511);
1317 B = (temp > 0) ? temp : (temp + 512);
1319 inSISIDXREG(SISCR, 0x11, cr_data);
1321 VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
1322 temp = VRE - ((E + F - 1) & 31);
1323 C = (temp > 0) ? temp : (temp + 32);
1328 var->upper_margin = D;
1329 var->lower_margin = F;
1332 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1334 var->upper_margin <<= 1;
1335 var->lower_margin <<= 1;
1336 var->vsync_len <<= 1;
1337 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1339 var->upper_margin >>= 1;
1340 var->lower_margin >>= 1;
1341 var->vsync_len >>= 1;
1344 inSISIDXREG(SISSR, 0x0b, sr_data);
1345 inSISIDXREG(SISCR, 0x00, cr_data);
1347 HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
1350 inSISIDXREG(SISCR, 0x01, cr_data);
1352 HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
1355 inSISIDXREG(SISCR, 0x04, cr_data);
1357 HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
1360 inSISIDXREG(SISCR, 0x02, cr_data);
1362 HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
1364 inSISIDXREG(SISSR, 0x0c, sr_data);
1365 inSISIDXREG(SISCR, 0x03, cr_data);
1366 inSISIDXREG(SISCR, 0x05, cr_data2);
1368 HBE = (cr_data & 0x1f) |
1369 ((u16) (cr_data2 & 0x80) >> 2) |
1370 ((u16) (sr_data & 0x03) << 6);
1371 HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
1373 temp = HBE - ((E - 1) & 255);
1374 B = (temp > 0) ? temp : (temp + 256);
1376 temp = HRE - ((E + F + 3) & 63);
1377 C = (temp > 0) ? temp : (temp + 64);
1382 if(var->xres_virtual < var->xres) {
1383 var->xres_virtual = var->xres;
1386 if((var->xres == 320) &&
1387 (var->yres == 200 || var->yres == 240)) {
1388 /* Terrible hack, but the correct CRTC data for
1389 * these modes only produces a black screen...
1391 var->left_margin = (400 - 376);
1392 var->right_margin = (328 - 320);
1393 var->hsync_len = (376 - 328);
1395 var->left_margin = D * 8;
1396 var->right_margin = F * 8;
1397 var->hsync_len = C * 8;
1399 var->activate = FB_ACTIVATE_NOW;
1403 mr_data = inSISREG(SISMISCR);
1405 var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
1407 var->sync |= FB_SYNC_VERT_HIGH_ACT;
1410 var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
1412 var->sync |= FB_SYNC_HOR_HIGH_ACT;
1418 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1421 hrate = ivideo->refresh_rate * VT / 2;
1422 drate = (hrate * HT) / 1000;
1423 var->pixclock = (u32) (1000000000 / drate);
1425 if(ivideo->sisfb_ypan) {
1426 maxyres = sisfb_calc_maxyres(ivideo, var);
1427 if(ivideo->sisfb_max) {
1428 var->yres_virtual = maxyres;
1430 if(var->yres_virtual > maxyres) {
1431 var->yres_virtual = maxyres;
1434 if(var->yres_virtual <= var->yres) {
1435 var->yres_virtual = var->yres;
1438 var->yres_virtual = var->yres;
1444 sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
1445 unsigned *transp, struct fb_info *info)
1447 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1449 if(regno >= ivideo->video_cmap_len) return 1;
1451 *red = ivideo->sis_palette[regno].red;
1452 *green = ivideo->sis_palette[regno].green;
1453 *blue = ivideo->sis_palette[regno].blue;
1460 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1461 unsigned transp, struct fb_info *info)
1463 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1465 if(regno >= ivideo->video_cmap_len) return 1;
1467 ivideo->sis_palette[regno].red = red;
1468 ivideo->sis_palette[regno].green = green;
1469 ivideo->sis_palette[regno].blue = blue;
1471 switch(ivideo->video_bpp) {
1472 #ifdef FBCON_HAS_CFB8
1474 outSISREG(SISDACA, regno);
1475 outSISREG(SISDACD, (red >> 10));
1476 outSISREG(SISDACD, (green >> 10));
1477 outSISREG(SISDACD, (blue >> 10));
1478 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1479 outSISREG(SISDAC2A, regno);
1480 outSISREG(SISDAC2D, (red >> 8));
1481 outSISREG(SISDAC2D, (green >> 8));
1482 outSISREG(SISDAC2D, (blue >> 8));
1486 #ifdef FBCON_HAS_CFB16
1488 ivideo->sis_fbcon_cmap.cfb16[regno] =
1489 ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1492 #ifdef FBCON_HAS_CFB32
1497 ivideo->sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
1506 sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info)
1508 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1509 struct display *display;
1510 struct display_switch *sw;
1511 struct fb_fix_screeninfo fix;
1514 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1516 sisfb_get_fix(&fix, con, info);
1518 display->var = *var;
1519 display->screen_base = (char *)ivideo->video_vbase;
1520 display->visual = fix.visual;
1521 display->type = fix.type;
1522 display->type_aux = fix.type_aux;
1523 display->ypanstep = fix.ypanstep;
1524 display->ywrapstep = fix.ywrapstep;
1525 display->line_length = fix.line_length;
1526 display->can_soft_blank = 1;
1527 display->inverse = ivideo->sisfb_inverse;
1528 display->next_line = fix.line_length;
1532 switch(ivideo->video_bpp) {
1533 #ifdef FBCON_HAS_CFB8
1534 case 8: sw = ivideo->accel ? &fbcon_sis8 : &fbcon_cfb8;
1537 #ifdef FBCON_HAS_CFB16
1538 case 16:sw = ivideo->accel ? &fbcon_sis16 : &fbcon_cfb16;
1539 display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb16;
1542 #ifdef FBCON_HAS_CFB32
1543 case 32:sw = ivideo->accel ? &fbcon_sis32 : &fbcon_cfb32;
1544 display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb32;
1547 default:sw = &fbcon_dummy;
1550 memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw));
1551 display->dispsw = &ivideo->sisfb_sw;
1553 restore_flags(flags);
1555 if(ivideo->sisfb_ypan) {
1556 /* display->scrollmode = 0; */
1558 display->scrollmode = SCROLL_YREDRAW;
1559 ivideo->sisfb_sw.bmove = fbcon_redraw_bmove;
1564 sisfb_do_install_cmap(int con, struct fb_info *info)
1566 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1568 if(con != ivideo->currcon) return;
1570 if(fb_display[con].cmap.len) {
1571 fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
1573 int size = sisfb_get_cmap_len(&fb_display[con].var);
1574 fb_set_cmap(fb_default_cmap(size), 1, sisfb_setcolreg, info);
1579 sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1581 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1584 memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo));
1586 *var = fb_display[con].var;
1589 if(ivideo->sisfb_fstn) {
1590 if(var->xres == 320 && var->yres == 480) var->yres = 240;
1597 sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1599 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1602 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1604 if(sisfb_do_set_var(var, con == ivideo->currcon, info)) {
1605 sisfb_crtc_to_var(ivideo, var);
1609 sisfb_crtc_to_var(ivideo, var);
1611 sisfb_set_disp(con, var, info);
1613 if(info->changevar) {
1614 (*info->changevar)(con);
1617 if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) {
1621 sisfb_do_install_cmap(con, info);
1623 #if 0 /* Why was this called here? */
1624 unsigned int cols, rows;
1625 cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
1626 rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
1627 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1633 sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1635 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1636 struct display *display;
1638 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1640 if(con == ivideo->currcon) {
1642 return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
1644 } else if(display->cmap.len) {
1646 fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2);
1650 int size = sisfb_get_cmap_len(&display->var);
1651 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
1659 sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1661 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1662 struct display *display;
1665 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1667 size = sisfb_get_cmap_len(&display->var);
1668 if(display->cmap.len != size) {
1669 err = fb_alloc_cmap(&display->cmap, size, 0);
1673 if(con == ivideo->currcon) {
1674 return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
1676 fb_copy_cmap(cmap, &display->cmap, kspc ? 0 : 1);
1683 sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info)
1685 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1688 if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
1690 if((var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual) ||
1691 (var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)) {
1695 if(con == ivideo->currcon) {
1696 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
1699 fb_display[con].var.xoffset = var->xoffset;
1700 fb_display[con].var.yoffset = var->yoffset;
1706 sisfb_update_var(int con, struct fb_info *info)
1708 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1710 return(sisfb_pan_var(ivideo, &fb_display[con].var));
1714 sisfb_switch(int con, struct fb_info *info)
1716 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1719 if(fb_display[ivideo->currcon].cmap.len) {
1720 fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info);
1723 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1725 if(!memcmp(&fb_display[con].var, &fb_display[ivideo->currcon].var,
1726 sizeof(struct fb_var_screeninfo))) {
1727 ivideo->currcon = con;
1731 ivideo->currcon = con;
1733 sisfb_do_set_var(&fb_display[con].var, 1, info);
1735 sisfb_set_disp(con, &fb_display[con].var, info);
1737 sisfb_do_install_cmap(con, info);
1739 cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
1740 rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
1741 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1743 sisfb_update_var(con, info);
1749 sisfb_blank(int blank, struct fb_info *info)
1751 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1753 sisfb_myblank(ivideo, blank);
1757 /* ------------ FBDev related routines for 2.6 series ----------- */
1759 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1762 sisfb_open(struct fb_info *info, int user)
1768 sisfb_release(struct fb_info *info, int user)
1774 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1775 unsigned transp, struct fb_info *info)
1777 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1779 if(regno >= sisfb_get_cmap_len(&info->var)) return 1;
1781 switch(info->var.bits_per_pixel) {
1783 outSISREG(SISDACA, regno);
1784 outSISREG(SISDACD, (red >> 10));
1785 outSISREG(SISDACD, (green >> 10));
1786 outSISREG(SISDACD, (blue >> 10));
1787 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1788 outSISREG(SISDAC2A, regno);
1789 outSISREG(SISDAC2D, (red >> 8));
1790 outSISREG(SISDAC2D, (green >> 8));
1791 outSISREG(SISDAC2D, (blue >> 8));
1795 ((u32 *)(info->pseudo_palette))[regno] =
1796 ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1802 ((u32 *)(info->pseudo_palette))[regno] =
1803 (red << 16) | (green << 8) | (blue);
1810 sisfb_set_par(struct fb_info *info)
1814 if((err = sisfb_do_set_var(&info->var, 1, info))) {
1817 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1818 sisfb_get_fix(&info->fix, info->currcon, info);
1820 sisfb_get_fix(&info->fix, -1, info);
1826 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1828 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1829 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1830 unsigned int drate = 0, hrate = 0, maxyres;
1832 int refresh_rate, search_idx;
1833 BOOLEAN recalc_clock = FALSE;
1836 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1838 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1840 pixclock = var->pixclock;
1842 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1843 vtotal += var->yres;
1845 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1846 vtotal += var->yres;
1848 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1849 vtotal += var->yres;
1851 } else vtotal += var->yres;
1853 if(!(htotal) || !(vtotal)) {
1854 SISFAIL("sisfb: no valid timing data");
1858 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1859 (sisbios_mode[search_idx].xres <= var->xres) ) {
1860 if( (sisbios_mode[search_idx].xres == var->xres) &&
1861 (sisbios_mode[search_idx].yres == var->yres) &&
1862 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1863 if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) {
1873 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1874 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1875 (var->yres <= sisbios_mode[search_idx].yres) &&
1876 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1877 if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) {
1885 printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1886 var->xres, var->yres, var->bits_per_pixel,
1887 sisbios_mode[search_idx].xres,
1888 sisbios_mode[search_idx].yres,
1889 var->bits_per_pixel);
1890 var->xres = sisbios_mode[search_idx].xres;
1891 var->yres = sisbios_mode[search_idx].yres;
1895 printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n",
1896 var->xres, var->yres, var->bits_per_pixel);
1901 if( ((ivideo->vbflags & VB_LVDS) || /* Slave modes on LVDS and 301B-DH */
1902 ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1903 (var->bits_per_pixel == 8) ) {
1905 recalc_clock = TRUE;
1906 } else if( (ivideo->current_htotal == htotal) && /* x=x & y=y & c=c -> assume depth change */
1907 (ivideo->current_vtotal == vtotal) &&
1908 (ivideo->current_pixclock == pixclock) ) {
1909 drate = 1000000000 / pixclock;
1910 hrate = (drate * 1000) / htotal;
1911 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1912 } else if( ( (ivideo->current_htotal != htotal) || /* x!=x | y!=y & c=c -> invalid pixclock */
1913 (ivideo->current_vtotal != vtotal) ) &&
1914 (ivideo->current_pixclock == var->pixclock) ) {
1915 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1916 refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1917 } else if(ivideo->sisfb_parm_rate != -1) {
1918 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1919 refresh_rate = ivideo->sisfb_parm_rate;
1923 recalc_clock = TRUE;
1924 } else if((pixclock) && (htotal) && (vtotal)) {
1925 drate = 1000000000 / pixclock;
1926 hrate = (drate * 1000) / htotal;
1927 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1928 } else if(ivideo->current_refresh_rate) {
1929 refresh_rate = ivideo->current_refresh_rate;
1930 recalc_clock = TRUE;
1933 recalc_clock = TRUE;
1936 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1938 /* Eventually recalculate timing and clock */
1940 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1941 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1943 sisbios_mode[search_idx].mode_no[ivideo->mni],
1945 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
1946 sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex, var);
1947 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1948 var->pixclock <<= 1;
1952 if(ivideo->sisfb_thismonitor.datavalid) {
1953 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1954 myrateindex, refresh_rate)) {
1955 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1959 /* Adapt RGB settings */
1960 sisfb_bpp_to_var(ivideo, var);
1962 /* Sanity check for offsets */
1963 if(var->xoffset < 0) var->xoffset = 0;
1964 if(var->yoffset < 0) var->yoffset = 0;
1966 if(var->xres > var->xres_virtual) {
1967 var->xres_virtual = var->xres;
1970 if(ivideo->sisfb_ypan) {
1971 maxyres = sisfb_calc_maxyres(ivideo, var);
1972 if(ivideo->sisfb_max) {
1973 var->yres_virtual = maxyres;
1975 if(var->yres_virtual > maxyres) {
1976 var->yres_virtual = maxyres;
1979 if(var->yres_virtual <= var->yres) {
1980 var->yres_virtual = var->yres;
1983 if(var->yres != var->yres_virtual) {
1984 var->yres_virtual = var->yres;
1990 /* Truncate offsets to maximum if too high */
1991 if(var->xoffset > var->xres_virtual - var->xres) {
1992 var->xoffset = var->xres_virtual - var->xres - 1;
1995 if(var->yoffset > var->yres_virtual - var->yres) {
1996 var->yoffset = var->yres_virtual - var->yres - 1;
1999 /* Set everything else to 0 */
2000 var->red.msb_right =
2001 var->green.msb_right =
2002 var->blue.msb_right =
2003 var->transp.offset =
2004 var->transp.length =
2005 var->transp.msb_right = 0;
2011 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
2013 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2016 if(var->xoffset > (var->xres_virtual - var->xres)) {
2019 if(var->yoffset > (var->yres_virtual - var->yres)) {
2023 if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
2025 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
2026 var->yoffset + info->var.yres > info->var.yres_virtual) {
2030 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
2032 info->var.xoffset = var->xoffset;
2033 info->var.yoffset = var->yoffset;
2039 sisfb_blank(int blank, struct fb_info *info)
2041 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2043 return(sisfb_myblank(ivideo, blank));
2048 /* ----------- FBDev related routines for all series ---------- */
2051 sisfb_ioctl(struct inode *inode, struct file *file,
2052 unsigned int cmd, unsigned long arg,
2053 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2056 struct fb_info *info)
2058 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2059 struct sis_memreq sismemreq;
2060 struct fb_vblank sisvbblank;
2066 u32 __user *argp = (u32 __user *)arg;
2070 if(!capable(CAP_SYS_RAWIO)) {
2073 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq))) {
2076 sis_malloc(&sismemreq);
2077 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
2078 sis_free((u32)sismemreq.offset);
2084 if(!capable(CAP_SYS_RAWIO)) {
2087 if(get_user(gpu32, argp)) {
2093 case FBIOGET_VBLANK:
2094 sisvbblank.count = 0;
2095 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
2096 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank))) {
2101 case SISFB_GET_INFO_SIZE:
2102 return put_user(sizeof(sisfb_info), argp);
2104 case SISFB_GET_INFO_OLD:
2105 if(ivideo->warncount++ < 50) {
2106 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2108 case SISFB_GET_INFO: /* For communication with X driver */
2109 x.sisfb_id = SISFB_ID;
2110 x.sisfb_version = VER_MAJOR;
2111 x.sisfb_revision = VER_MINOR;
2112 x.sisfb_patchlevel = VER_LEVEL;
2113 x.chip_id = ivideo->chip_id;
2114 x.memory = ivideo->video_size / 1024;
2115 x.heapstart = ivideo->heapstart / 1024;
2116 if(ivideo->modechanged) {
2117 x.fbvidmode = ivideo->mode_no;
2119 x.fbvidmode = ivideo->modeprechange;
2121 x.sisfb_caps = ivideo->caps;
2122 x.sisfb_tqlen = 512; /* yet fixed */
2123 x.sisfb_pcibus = ivideo->pcibus;
2124 x.sisfb_pcislot = ivideo->pcislot;
2125 x.sisfb_pcifunc = ivideo->pcifunc;
2126 x.sisfb_lcdpdc = ivideo->detectedpdc;
2127 x.sisfb_lcdpdca = ivideo->detectedpdca;
2128 x.sisfb_lcda = ivideo->detectedlcda;
2129 x.sisfb_vbflags = ivideo->vbflags;
2130 x.sisfb_currentvbflags = ivideo->currentvbflags;
2131 x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
2132 x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
2133 x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
2134 x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
2135 x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
2136 x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
2137 x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
2138 x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
2139 x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
2140 x.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
2142 if(copy_to_user((void __user *)arg, &x, sizeof(x))) {
2147 case SISFB_GET_VBRSTATUS_OLD:
2148 if(ivideo->warncount++ < 50) {
2149 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2151 case SISFB_GET_VBRSTATUS:
2152 if(sisfb_CheckVBRetrace(ivideo)) {
2153 return put_user((u32)1, argp);
2155 return put_user((u32)0, argp);
2158 case SISFB_GET_AUTOMAXIMIZE_OLD:
2159 if(ivideo->warncount++ < 50) {
2160 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2162 case SISFB_GET_AUTOMAXIMIZE:
2163 if(ivideo->sisfb_max) return put_user((u32)1, argp);
2164 else return put_user((u32)0, argp);
2166 case SISFB_SET_AUTOMAXIMIZE_OLD:
2167 if(ivideo->warncount++ < 50) {
2168 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2170 case SISFB_SET_AUTOMAXIMIZE:
2171 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2174 ivideo->sisfb_max = (gpu32) ? 1 : 0;
2177 case SISFB_SET_TVPOSOFFSET:
2178 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2181 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
2182 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
2185 case SISFB_GET_TVPOSOFFSET:
2186 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
2189 case SISFB_SET_LOCK:
2190 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2193 ivideo->sisfblocked = (gpu32) ? 1 : 0;
2197 return -ENOIOCTLCMD;
2202 #ifdef CONFIG_COMPAT
2203 static long sisfb_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg, struct fb_info *info)
2207 ret = sisfb_ioctl(NULL, f, cmd, arg, info);
2214 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
2216 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2218 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2220 strcpy(fix->id, ivideo->myid);
2222 fix->smem_start = ivideo->video_base;
2223 fix->smem_len = ivideo->sisfb_mem;
2224 fix->type = FB_TYPE_PACKED_PIXELS;
2226 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
2228 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
2230 fix->line_length = ivideo->video_linelength;
2231 fix->mmio_start = ivideo->mmio_base;
2232 fix->mmio_len = ivideo->mmio_size;
2233 if(ivideo->sisvga_engine == SIS_300_VGA) {
2234 fix->accel = FB_ACCEL_SIS_GLAMOUR;
2235 } else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) {
2236 fix->accel = FB_ACCEL_SIS_XABRE;
2238 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
2244 /* ---------------- fb_ops structures ----------------- */
2246 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2247 static struct fb_ops sisfb_ops = {
2248 .owner = THIS_MODULE,
2249 .fb_get_fix = sisfb_get_fix,
2250 .fb_get_var = sisfb_get_var,
2251 .fb_set_var = sisfb_set_var,
2252 .fb_get_cmap = sisfb_get_cmap,
2253 .fb_set_cmap = sisfb_set_cmap,
2254 .fb_pan_display = sisfb_pan_display,
2255 .fb_ioctl = sisfb_ioctl
2259 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
2260 static struct fb_ops sisfb_ops = {
2261 .owner = THIS_MODULE,
2262 .fb_open = sisfb_open,
2263 .fb_release = sisfb_release,
2264 .fb_check_var = sisfb_check_var,
2265 .fb_set_par = sisfb_set_par,
2266 .fb_setcolreg = sisfb_setcolreg,
2267 .fb_pan_display = sisfb_pan_display,
2268 .fb_blank = sisfb_blank,
2269 .fb_fillrect = fbcon_sis_fillrect,
2270 .fb_copyarea = fbcon_sis_copyarea,
2271 .fb_imageblit = cfb_imageblit,
2272 .fb_cursor = soft_cursor,
2273 .fb_sync = fbcon_sis_sync,
2274 .fb_ioctl = sisfb_ioctl,
2275 #ifdef CONFIG_COMPAT
2276 .fb_compat_ioctl = sisfb_compat_ioctl,
2281 /* ---------------- Chip generation dependent routines ---------------- */
2283 static struct pci_dev * sisfb_get_northbridge(int basechipid)
2285 struct pci_dev *pdev = NULL;
2286 int nbridgenum, nbridgeidx, i;
2287 const unsigned short nbridgeids[] = {
2288 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2289 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2290 PCI_DEVICE_ID_SI_730,
2291 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2292 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2293 PCI_DEVICE_ID_SI_651,
2294 PCI_DEVICE_ID_SI_740,
2295 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760 VGA */
2296 PCI_DEVICE_ID_SI_741,
2297 PCI_DEVICE_ID_SI_660,
2298 PCI_DEVICE_ID_SI_760
2301 switch(basechipid) {
2302 #ifdef CONFIG_FB_SIS_300
2303 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2304 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2306 #ifdef CONFIG_FB_SIS_315
2307 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2308 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
2309 case SIS_660: nbridgeidx = 7; nbridgenum = 4; break;
2311 default: return NULL;
2313 for(i = 0; i < nbridgenum; i++) {
2314 if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break;
2319 static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
2321 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2325 ivideo->video_size = 0;
2327 switch(ivideo->chip) {
2328 #ifdef CONFIG_FB_SIS_300
2330 inSISIDXREG(SISSR, 0x14, reg);
2331 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2336 if(!ivideo->nbridge) return -1;
2337 pci_read_config_byte(ivideo->nbridge, 0x63, ®);
2338 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2341 #ifdef CONFIG_FB_SIS_315
2345 inSISIDXREG(SISSR, 0x14, reg);
2346 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2347 switch((reg >> 2) & 0x03) {
2350 ivideo->video_size <<= 1;
2353 ivideo->video_size += (ivideo->video_size/2);
2357 inSISIDXREG(SISSR, 0x14, reg);
2358 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2359 if(reg & 0x0c) ivideo->video_size <<= 1;
2364 inSISIDXREG(SISSR, 0x14, reg);
2365 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2369 inSISIDXREG(SISCR, 0x79, reg);
2370 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2374 inSISIDXREG(SISCR, 0x79, reg);
2375 reg = (reg & 0xf0) >> 4;
2376 if(reg) ivideo->video_size = (1 << reg) << 20;
2377 inSISIDXREG(SISCR, 0x78, reg);
2380 if(reg == 0x10) ivideo->video_size += (32 << 20);
2381 else ivideo->video_size += (64 << 20);
2391 /* -------------- video bridge device detection --------------- */
2393 static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2397 #ifdef CONFIG_FB_SIS_300
2398 if(ivideo->sisvga_engine == SIS_300_VGA) {
2399 inSISIDXREG(SISSR, 0x17, temp);
2400 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2401 /* PAL/NTSC is stored on SR16 on such machines */
2402 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2403 inSISIDXREG(SISSR, 0x16, temp);
2405 ivideo->vbflags |= TV_PAL;
2407 ivideo->vbflags |= TV_NTSC;
2413 inSISIDXREG(SISCR, 0x32, cr32);
2415 if(cr32 & SIS_CRT1) {
2416 ivideo->sisfb_crt1off = 0;
2418 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2421 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2423 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2424 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2425 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2427 /* Check given parms for hardware compatibility.
2428 * (Cannot do this in the search_xx routines since we don't
2429 * know what hardware we are running on then)
2432 if(ivideo->chip != SIS_550) {
2433 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2436 if(ivideo->sisfb_tvplug != -1) {
2437 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2438 (!(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) ) {
2439 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2440 ivideo->sisfb_tvplug = -1;
2441 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2445 if(ivideo->sisfb_tvplug != -1) {
2446 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2447 (!(ivideo->vbflags & (VB_301|VB_301B|VB_302B))) ) {
2448 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2449 ivideo->sisfb_tvplug = -1;
2450 printk(KERN_ERR "sisfb: HiVision not supported\n");
2454 if(ivideo->sisfb_tvstd != -1) {
2455 if( (!(ivideo->vbflags & VB_SISBRIDGE)) &&
2456 (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags & VB_CHRONTEL))) ) {
2457 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2458 ivideo->sisfb_tvstd = -1;
2459 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2464 /* Detect/set TV plug & type */
2465 if(ivideo->sisfb_tvplug != -1) {
2466 ivideo->vbflags |= ivideo->sisfb_tvplug;
2468 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2469 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2470 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2472 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2473 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2477 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2478 if(ivideo->sisfb_tvstd != -1) {
2479 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2480 ivideo->vbflags |= ivideo->sisfb_tvstd;
2482 if(ivideo->vbflags & TV_SCART) {
2483 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2484 ivideo->vbflags |= TV_PAL;
2486 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2487 if(ivideo->sisvga_engine == SIS_300_VGA) {
2488 inSISIDXREG(SISSR, 0x38, temp);
2489 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2490 else ivideo->vbflags |= TV_NTSC;
2491 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2492 inSISIDXREG(SISSR, 0x38, temp);
2493 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2494 else ivideo->vbflags |= TV_NTSC;
2496 inSISIDXREG(SISCR, 0x79, temp);
2497 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2498 else ivideo->vbflags |= TV_NTSC;
2503 /* Copy forceCRT1 option to CRT1off if option is given */
2504 if(ivideo->sisfb_forcecrt1 != -1) {
2505 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2509 static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo)
2511 char stdstr[] = "sisfb: Detected";
2512 char bridgestr[] = "video bridge";
2516 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2519 inSISIDXREG(SISPART4, 0x01, reg);
2521 ivideo->vbflags |= VB_301;
2522 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2523 } else if(reg < 0xc0) {
2524 ivideo->vbflags |= VB_301B;
2525 inSISIDXREG(SISPART4,0x23,reg);
2527 ivideo->vbflags |= VB_30xBDH;
2528 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2530 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2532 } else if(reg < 0xd0) {
2533 ivideo->vbflags |= VB_301C;
2534 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2535 } else if(reg < 0xe0) {
2536 ivideo->vbflags |= VB_301LV;
2537 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2538 } else if(reg <= 0xe1) {
2539 inSISIDXREG(SISPART4,0x39,reg);
2541 ivideo->vbflags |= VB_302LV;
2542 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2544 ivideo->vbflags |= VB_301C;
2545 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2547 ivideo->vbflags |= VB_302ELV;
2548 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2554 ivideo->vbflags |= VB_302B;
2555 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2559 if((!(ivideo->vbflags & VB_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2560 inSISIDXREG(SISCR, 0x37, reg);
2561 reg &= SIS_EXTERNAL_CHIP_MASK;
2563 if(ivideo->sisvga_engine == SIS_300_VGA) {
2564 #ifdef CONFIG_FB_SIS_300
2566 case SIS_EXTERNAL_CHIP_LVDS:
2567 ivideo->vbflags |= VB_LVDS;
2569 case SIS_EXTERNAL_CHIP_TRUMPION:
2570 ivideo->vbflags |= VB_TRUMPION;
2572 case SIS_EXTERNAL_CHIP_CHRONTEL:
2573 ivideo->vbflags |= VB_CHRONTEL;
2575 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2576 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2579 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 1;
2581 } else if(ivideo->chip < SIS_661) {
2582 #ifdef CONFIG_FB_SIS_315
2584 case SIS310_EXTERNAL_CHIP_LVDS:
2585 ivideo->vbflags |= VB_LVDS;
2587 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2588 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2591 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2593 } else if(ivideo->chip >= SIS_661) {
2594 #ifdef CONFIG_FB_SIS_315
2595 inSISIDXREG(SISCR, 0x38, reg);
2599 ivideo->vbflags |= VB_LVDS;
2602 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2605 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);
2608 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2611 if(ivideo->vbflags & VB_LVDS) {
2612 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2614 if(ivideo->vbflags & VB_TRUMPION) {
2615 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2617 if(ivideo->vbflags & VB_CHRONTEL) {
2618 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2620 if(ivideo->vbflags & VB_CONEXANT) {
2621 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2625 if(ivideo->vbflags & VB_SISBRIDGE) {
2626 SiS_Sense30x(ivideo);
2627 } else if(ivideo->vbflags & VB_CHRONTEL) {
2628 SiS_SenseCh(ivideo);
2632 /* ------------------ Sensing routines ------------------ */
2634 static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo)
2639 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2641 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2643 return (count == -1) ? FALSE : TRUE;
2646 static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
2648 BOOLEAN mustwait = FALSE;
2650 #ifdef CONFIG_FB_SIS_315
2656 inSISIDXREG(SISSR,0x1F,sr1F);
2657 orSISIDXREG(SISSR,0x1F,0x04);
2658 andSISIDXREG(SISSR,0x1F,0x3F);
2659 if(sr1F & 0xc0) mustwait = TRUE;
2661 #ifdef CONFIG_FB_SIS_315
2662 if(ivideo->sisvga_engine == SIS_315_VGA) {
2663 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2665 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2669 inSISIDXREG(SISCR,0x17,cr17);
2672 orSISIDXREG(SISCR,0x17,0x80);
2674 outSISIDXREG(SISSR, 0x00, 0x01);
2675 outSISIDXREG(SISSR, 0x00, 0x03);
2679 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2682 #ifdef CONFIG_FB_SIS_315
2683 if(ivideo->chip >= SIS_330) {
2684 andSISIDXREG(SISCR,0x32,~0x20);
2685 if(ivideo->chip >= SIS_340) {
2686 outSISIDXREG(SISCR, 0x57, 0x4a);
2688 outSISIDXREG(SISCR, 0x57, 0x5f);
2690 orSISIDXREG(SISCR, 0x53, 0x02);
2691 while((inSISREG(SISINPSTAT)) & 0x01) break;
2692 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2693 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2694 andSISIDXREG(SISCR, 0x53, 0xfd);
2695 andSISIDXREG(SISCR, 0x57, 0x00);
2699 if(temp == 0xffff) {
2702 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, 0, 0, NULL);
2703 } while(((temp == 0) || (temp == 0xffff)) && i--);
2705 if((temp == 0) || (temp == 0xffff)) {
2706 if(sisfb_test_DDC1(ivideo)) temp = 1;
2710 if((temp) && (temp != 0xffff)) {
2711 orSISIDXREG(SISCR,0x32,0x20);
2714 #ifdef CONFIG_FB_SIS_315
2715 if(ivideo->sisvga_engine == SIS_315_VGA) {
2716 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2720 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2722 outSISIDXREG(SISSR,0x1F,sr1F);
2725 /* Determine and detect attached devices on SiS30x */
2726 static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2728 int temp, mytest, result, i, j;
2730 for(j = 0; j < 10; j++) {
2732 for(i = 0; i < 3; i++) {
2734 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2735 temp = (type >> 8) | (mytest & 0x00ff);
2736 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2737 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2740 inSISIDXREG(SISPART4,0x03,temp);
2743 if(temp == mytest) result++;
2745 outSISIDXREG(SISPART4,0x11,0x00);
2746 andSISIDXREG(SISPART4,0x10,0xe0);
2747 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2750 if((result == 0) || (result >= 2)) break;
2755 static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
2757 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2758 u16 svhs=0, svhs_c=0;
2759 u16 cvbs=0, cvbs_c=0;
2760 u16 vga2=0, vga2_c=0;
2762 char stdstr[] = "sisfb: Detected";
2763 char tvstr[] = "TV connected to";
2765 if(ivideo->vbflags & VB_301) {
2766 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2767 inSISIDXREG(SISPART4,0x01,myflag);
2769 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2771 } else if(ivideo->vbflags & (VB_301B | VB_302B)) {
2772 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2773 } else if(ivideo->vbflags & (VB_301LV | VB_302LV)) {
2774 svhs = 0x0200; cvbs = 0x0100;
2775 } else if(ivideo->vbflags & (VB_301C | VB_302ELV)) {
2776 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2779 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2780 if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
2781 svhs_c = 0x0408; cvbs_c = 0x0808;
2785 if(ivideo->chip == SIS_300) {
2786 inSISIDXREG(SISSR,0x3b,myflag);
2787 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2790 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2791 orSISIDXREG(SISSR,0x1e,0x20);
2793 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2794 if(ivideo->vbflags & VB_301C) {
2795 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2797 orSISIDXREG(SISPART4,0x0d,0x04);
2799 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2801 inSISIDXREG(SISPART2,0x00,backupP2_00);
2802 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2804 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2805 if(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV)) {
2806 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2809 if(!(ivideo->vbflags & VB_301C)) {
2810 SISDoSense(ivideo, 0, 0);
2813 andSISIDXREG(SISCR, 0x32, ~0x14);
2815 if(vga2_c || vga2) {
2816 if(SISDoSense(ivideo, vga2, vga2_c)) {
2817 if(biosflag & 0x01) {
2818 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2819 orSISIDXREG(SISCR, 0x32, 0x04);
2821 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2822 orSISIDXREG(SISCR, 0x32, 0x10);
2827 andSISIDXREG(SISCR, 0x32, 0x3f);
2829 if(ivideo->vbflags & VB_301C) {
2830 orSISIDXREG(SISPART4,0x0d,0x04);
2833 if((ivideo->sisvga_engine == SIS_315_VGA) &&
2834 (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV))) {
2835 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2836 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2837 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2838 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2839 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2840 orSISIDXREG(SISCR,0x32,0x80);
2843 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2846 andSISIDXREG(SISCR, 0x32, ~0x03);
2848 if(!(ivideo->vbflags & TV_YPBPR)) {
2849 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2850 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2851 orSISIDXREG(SISCR, 0x32, 0x02);
2853 if((biosflag & 0x02) || (!result)) {
2854 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2855 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2856 orSISIDXREG(SISCR, 0x32, 0x01);
2861 SISDoSense(ivideo, 0, 0);
2863 outSISIDXREG(SISPART2,0x00,backupP2_00);
2864 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2865 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2867 if(ivideo->vbflags & VB_301C) {
2868 inSISIDXREG(SISPART2,0x00,biosflag);
2869 if(biosflag & 0x20) {
2870 for(myflag = 2; myflag > 0; myflag--) {
2872 outSISIDXREG(SISPART2,0x00,biosflag);
2877 outSISIDXREG(SISPART2,0x00,backupP2_00);
2880 /* Determine and detect attached TV's on Chrontel */
2881 static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
2883 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2885 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2887 #ifdef CONFIG_FB_SIS_300
2888 unsigned char test[3];
2892 if(ivideo->chip < SIS_315H) {
2894 #ifdef CONFIG_FB_SIS_300
2895 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2896 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2897 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2898 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2899 /* See Chrontel TB31 for explanation */
2900 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2901 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2902 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b0e);
2903 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2905 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2906 if(temp2 != temp1) temp1 = temp2;
2908 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2909 /* Read power status */
2910 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2911 if((temp1 & 0x03) != 0x03) {
2912 /* Power all outputs */
2913 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0B0E);
2914 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2916 /* Sense connected TV devices */
2917 for(i = 0; i < 3; i++) {
2918 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0110);
2919 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2920 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0010);
2921 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2922 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2923 if(!(temp1 & 0x08)) test[i] = 0x02;
2924 else if(!(temp1 & 0x02)) test[i] = 0x01;
2926 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2929 if(test[0] == test[1]) temp1 = test[0];
2930 else if(test[0] == test[2]) temp1 = test[0];
2931 else if(test[1] == test[2]) temp1 = test[1];
2934 "sisfb: TV detection unreliable - test results varied\n");
2938 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2939 ivideo->vbflags |= TV_SVIDEO;
2940 orSISIDXREG(SISCR, 0x32, 0x02);
2941 andSISIDXREG(SISCR, 0x32, ~0x05);
2942 } else if (temp1 == 0x01) {
2943 printk(KERN_INFO "%s CVBS output\n", stdstr);
2944 ivideo->vbflags |= TV_AVIDEO;
2945 orSISIDXREG(SISCR, 0x32, 0x01);
2946 andSISIDXREG(SISCR, 0x32, ~0x06);
2948 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2949 andSISIDXREG(SISCR, 0x32, ~0x07);
2951 } else if(temp1 == 0) {
2952 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2953 andSISIDXREG(SISCR, 0x32, ~0x07);
2955 /* Set general purpose IO for Chrontel communication */
2956 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2961 #ifdef CONFIG_FB_SIS_315
2962 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2963 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2964 SiS_SetCH701x(&ivideo->SiS_Pr, 0x2049);
2965 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2966 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2968 SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2969 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2971 SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2972 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2973 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2974 SiS_SetCH701x(&ivideo->SiS_Pr, (temp1 << 8) | 0x49);
2976 if(temp2 & 0x02) temp1 |= 0x01;
2977 if(temp2 & 0x10) temp1 |= 0x01;
2978 if(temp2 & 0x04) temp1 |= 0x02;
2979 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2982 printk(KERN_INFO "%s CVBS output\n", stdstr);
2983 ivideo->vbflags |= TV_AVIDEO;
2984 orSISIDXREG(SISCR, 0x32, 0x01);
2985 andSISIDXREG(SISCR, 0x32, ~0x06);
2988 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2989 ivideo->vbflags |= TV_SVIDEO;
2990 orSISIDXREG(SISCR, 0x32, 0x02);
2991 andSISIDXREG(SISCR, 0x32, ~0x05);
2994 printk(KERN_INFO "%s SCART output\n", stdstr);
2995 orSISIDXREG(SISCR, 0x32, 0x04);
2996 andSISIDXREG(SISCR, 0x32, ~0x03);
2999 andSISIDXREG(SISCR, 0x32, ~0x07);
3005 /* ------------------------ Heap routines -------------------------- */
3007 static u32 __devinit
3008 sisfb_getheapstart(struct sis_video_info *ivideo)
3010 u32 ret = ivideo->sisfb_parm_mem * 1024;
3011 u32 max = ivideo->video_size - ivideo->hwcursor_size;
3014 /* Calculate heap start = end of memory for console
3016 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3017 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3019 * Basically given by "mem" parameter
3021 * maximum = videosize - cmd_queue - hwcursor
3022 * (results in a heap of size 0)
3023 * default = SiS 300: depends on videosize
3024 * SiS 315/330: 32k below max
3027 if(ivideo->sisvga_engine == SIS_300_VGA) {
3028 max -= TURBO_QUEUE_AREA_SIZE;
3029 if(ivideo->video_size > 0x1000000) {
3031 } else if(ivideo->video_size > 0x800000) {
3037 max -= COMMAND_QUEUE_AREA_SIZE;
3041 if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) {
3048 static int __devinit
3049 sisfb_heap_init(struct sis_video_info *ivideo)
3053 ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo);
3055 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3056 ivideo->sisfb_heap_end = ivideo->video_vbase + ivideo->video_size;
3058 /* Initialize command queue (We use MMIO only) */
3060 #ifdef CONFIG_FB_SIS_315
3061 if(ivideo->sisvga_engine == SIS_315_VGA) {
3065 ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
3067 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
3068 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3070 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3071 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3073 temp = SIS_CMD_QUEUE_SIZE_512k;
3074 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3075 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3077 tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE);
3078 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3080 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3084 #ifdef CONFIG_FB_SIS_300
3085 if(ivideo->sisvga_engine == SIS_300_VGA) {
3086 unsigned long tqueue_pos;
3089 ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
3091 tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
3093 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3096 tq_state |= (u8)(tqueue_pos >> 8);
3097 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3099 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
3101 ivideo->caps |= TURBO_QUEUE_CAP;
3105 /* Reserve memory for the HWCursor */
3106 ivideo->sisfb_heap_end -= ivideo->hwcursor_size;
3107 ivideo->hwcursor_vbase = ivideo->sisfb_heap_end;
3108 ivideo->caps |= HW_CURSOR_CAP;
3110 ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start;
3112 if(ivideo->cardnumber == 0) {
3114 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3115 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3117 sisfb_heap.vinfo = ivideo;
3119 sisfb_heap.poha_chain = NULL;
3120 sisfb_heap.poh_freelist = NULL;
3122 poh = sisfb_poh_new_node();
3123 if(poh == NULL) return 1;
3125 poh->poh_next = &sisfb_heap.oh_free;
3126 poh->poh_prev = &sisfb_heap.oh_free;
3127 poh->size = ivideo->sisfb_heap_size;
3128 poh->offset = ivideo->heapstart;
3130 sisfb_heap.oh_free.poh_next = poh;
3131 sisfb_heap.oh_free.poh_prev = poh;
3132 sisfb_heap.oh_free.size = 0;
3133 sisfb_heap.max_freesize = poh->size;
3135 sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
3136 sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
3137 sisfb_heap.oh_used.size = SENTINEL;
3141 printk(KERN_INFO "Skipped heap initialization for secondary cards\n");
3149 sisfb_poh_new_node(void)
3156 if(sisfb_heap.poh_freelist == NULL) {
3157 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3158 if(!poha) return NULL;
3160 poha->poha_next = sisfb_heap.poha_chain;
3161 sisfb_heap.poha_chain = poha;
3163 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
3165 poh = &poha->aoh[0];
3166 for(i = cOhs - 1; i != 0; i--) {
3167 poh->poh_next = poh + 1;
3171 poh->poh_next = NULL;
3172 sisfb_heap.poh_freelist = &poha->aoh[0];
3175 poh = sisfb_heap.poh_freelist;
3176 sisfb_heap.poh_freelist = poh->poh_next;
3182 sisfb_poh_allocate(u32 size)
3188 if(size > sisfb_heap.max_freesize) {
3189 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3190 (unsigned int) size / 1024);
3194 pohThis = sisfb_heap.oh_free.poh_next;
3196 while(pohThis != &sisfb_heap.oh_free) {
3197 if (size <= pohThis->size) {
3201 pohThis = pohThis->poh_next;
3205 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3206 (unsigned int) size / 1024);
3210 if(size == pohThis->size) {
3212 sisfb_delete_node(pohThis);
3214 pohRoot = sisfb_poh_new_node();
3216 if(pohRoot == NULL) {
3220 pohRoot->offset = pohThis->offset;
3221 pohRoot->size = size;
3223 pohThis->offset += size;
3224 pohThis->size -= size;
3227 sisfb_heap.max_freesize -= size;
3229 pohThis = &sisfb_heap.oh_used;
3230 sisfb_insert_node(pohThis, pohRoot);
3236 sisfb_delete_node(SIS_OH *poh)
3241 poh_prev = poh->poh_prev;
3242 poh_next = poh->poh_next;
3244 poh_prev->poh_next = poh_next;
3245 poh_next->poh_prev = poh_prev;
3249 sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
3253 pohTemp = pohList->poh_next;
3255 pohList->poh_next = poh;
3256 pohTemp->poh_prev = poh;
3258 poh->poh_prev = pohList;
3259 poh->poh_next = pohTemp;
3263 sisfb_poh_free(u32 base)
3273 poh_freed = sisfb_heap.oh_used.poh_next;
3275 while(poh_freed != &sisfb_heap.oh_used) {
3276 if(poh_freed->offset == base) {
3281 poh_freed = poh_freed->poh_next;
3284 if(!foundNode) return(NULL);
3286 sisfb_heap.max_freesize += poh_freed->size;
3288 poh_prev = poh_next = NULL;
3289 ulUpper = poh_freed->offset + poh_freed->size;
3290 ulLower = poh_freed->offset;
3292 pohThis = sisfb_heap.oh_free.poh_next;
3294 while(pohThis != &sisfb_heap.oh_free) {
3295 if(pohThis->offset == ulUpper) {
3297 } else if((pohThis->offset + pohThis->size) == ulLower) {
3300 pohThis = pohThis->poh_next;
3303 sisfb_delete_node(poh_freed);
3305 if(poh_prev && poh_next) {
3306 poh_prev->size += (poh_freed->size + poh_next->size);
3307 sisfb_delete_node(poh_next);
3308 sisfb_free_node(poh_freed);
3309 sisfb_free_node(poh_next);
3314 poh_prev->size += poh_freed->size;
3315 sisfb_free_node(poh_freed);
3320 poh_next->size += poh_freed->size;
3321 poh_next->offset = poh_freed->offset;
3322 sisfb_free_node(poh_freed);
3326 sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
3332 sisfb_free_node(SIS_OH *poh)
3334 if(poh == NULL) return;
3336 poh->poh_next = sisfb_heap.poh_freelist;
3337 sisfb_heap.poh_freelist = poh;
3341 sis_malloc(struct sis_memreq *req)
3343 struct sis_video_info *ivideo = sisfb_heap.vinfo;
3346 if((ivideo) && (!ivideo->havenoheap)) {
3347 poh = sisfb_poh_allocate((u32)req->size);
3351 req->offset = req->size = 0;
3352 DPRINTK("sisfb: Video RAM allocation failed\n");
3354 req->offset = poh->offset;
3355 req->size = poh->size;
3356 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3357 (poh->offset + ivideo->video_vbase));
3361 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3366 struct sis_video_info *ivideo = sisfb_heap.vinfo;
3369 if((!ivideo) || (ivideo->havenoheap)) return;
3371 poh = sisfb_poh_free((u32)base);
3374 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3375 (unsigned int) base);
3379 /* --------------------- SetMode routines ------------------------- */
3382 sisfb_pre_setmode(struct sis_video_info *ivideo)
3384 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3387 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3389 inSISIDXREG(SISCR, 0x31, cr31);
3393 cr33 = ivideo->rate_idx & 0x0F;
3395 #ifdef CONFIG_FB_SIS_315
3396 if(ivideo->sisvga_engine == SIS_315_VGA) {
3397 if(ivideo->chip >= SIS_661) {
3398 inSISIDXREG(SISCR, 0x38, cr38);
3399 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3402 inSISIDXREG(SISCR, tvregnum, cr38);
3403 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3407 #ifdef CONFIG_FB_SIS_300
3408 if(ivideo->sisvga_engine == SIS_300_VGA) {
3410 inSISIDXREG(SISCR, tvregnum, cr38);
3414 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3415 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3417 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3420 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3421 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) {
3422 #ifdef CONFIG_FB_SIS_315
3423 if(ivideo->chip >= SIS_661) {
3425 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3426 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3427 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3428 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3430 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3431 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3432 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3434 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3435 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3436 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3438 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3441 } else if((ivideo->vbflags & TV_HIVISION) && (ivideo->vbflags & (VB_301|VB_301B|VB_302B))) {
3442 if(ivideo->chip >= SIS_661) {
3448 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3451 ivideo->currentvbflags |= TV_HIVISION;
3452 } else if(ivideo->vbflags & TV_SCART) {
3453 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3456 ivideo->currentvbflags |= TV_SCART;
3458 if(ivideo->vbflags & TV_SVIDEO) {
3459 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3460 ivideo->currentvbflags |= TV_SVIDEO;
3462 if(ivideo->vbflags & TV_AVIDEO) {
3463 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3464 ivideo->currentvbflags |= TV_AVIDEO;
3467 cr31 |= SIS_DRIVER_MODE;
3469 if(ivideo->vbflags & (TV_AVIDEO|TV_SVIDEO)) {
3470 if(ivideo->vbflags & TV_PAL) {
3471 cr31 |= 0x01; cr35 |= 0x01;
3472 ivideo->currentvbflags |= TV_PAL;
3473 if(ivideo->vbflags & TV_PALM) {
3474 cr38 |= 0x40; cr35 |= 0x04;
3475 ivideo->currentvbflags |= TV_PALM;
3476 } else if(ivideo->vbflags & TV_PALN) {
3477 cr38 |= 0x80; cr35 |= 0x08;
3478 ivideo->currentvbflags |= TV_PALN;
3481 cr31 &= ~0x01; cr35 &= ~0x01;
3482 ivideo->currentvbflags |= TV_NTSC;
3483 if(ivideo->vbflags & TV_NTSCJ) {
3484 cr38 |= 0x40; cr35 |= 0x02;
3485 ivideo->currentvbflags |= TV_NTSCJ;
3492 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3493 cr31 |= SIS_DRIVER_MODE;
3494 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3495 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3499 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3500 cr31 |= SIS_DRIVER_MODE;
3501 if(ivideo->sisfb_nocrt2rate) {
3502 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3504 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3508 default: /* disable CRT2 */
3510 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3513 outSISIDXREG(SISCR, 0x30, cr30);
3514 outSISIDXREG(SISCR, 0x33, cr33);
3516 if(ivideo->chip >= SIS_661) {
3517 #ifdef CONFIG_FB_SIS_315
3518 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3519 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3520 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3521 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3523 } else if(ivideo->chip != SIS_300) {
3524 outSISIDXREG(SISCR, tvregnum, cr38);
3526 outSISIDXREG(SISCR, 0x31, cr31);
3528 if(ivideo->accel) sisfb_syncaccel(ivideo);
3530 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3533 /* Fix SR11 for 661 and later */
3534 #ifdef CONFIG_FB_SIS_315
3536 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3540 if(ivideo->chip >= SIS_661) {
3541 inSISIDXREG(SISSR,0x11,tmpreg);
3543 inSISIDXREG(SISSR,0x3e,tmpreg);
3544 tmpreg = (tmpreg + 1) & 0xff;
3545 outSISIDXREG(SISSR,0x3e,tmpreg);
3546 inSISIDXREG(SISSR,0x11,tmpreg);
3549 andSISIDXREG(SISSR,0x11,0x0f);
3555 static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3557 if(val > 32) val = 32;
3558 if(val < -32) val = -32;
3559 ivideo->tvxpos = val;
3561 if(ivideo->sisfblocked) return;
3562 if(!ivideo->modechanged) return;
3564 if(ivideo->currentvbflags & CRT2_TV) {
3566 if(ivideo->vbflags & VB_CHRONTEL) {
3568 int x = ivideo->tvx;
3570 switch(ivideo->chronteltype) {
3574 outSISIDXREG(SISSR,0x05,0x86);
3575 SiS_SetCH700x(&ivideo->SiS_Pr, (((x & 0xff) << 8) | 0x0a));
3576 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD);
3579 /* Not supported by hardware */
3583 } else if(ivideo->vbflags & VB_SISBRIDGE) {
3585 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3586 unsigned short temp;
3588 p2_1f = ivideo->p2_1f;
3589 p2_20 = ivideo->p2_20;
3590 p2_2b = ivideo->p2_2b;
3591 p2_42 = ivideo->p2_42;
3592 p2_43 = ivideo->p2_43;
3594 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3596 p2_1f = temp & 0xff;
3597 p2_20 = (temp & 0xf00) >> 4;
3598 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3599 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3601 p2_43 = temp & 0xff;
3602 p2_42 = (temp & 0xf00) >> 4;
3603 outSISIDXREG(SISPART2,0x1f,p2_1f);
3604 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3605 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3606 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3607 outSISIDXREG(SISPART2,0x43,p2_43);
3612 static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3614 if(val > 32) val = 32;
3615 if(val < -32) val = -32;
3616 ivideo->tvypos = val;
3618 if(ivideo->sisfblocked) return;
3619 if(!ivideo->modechanged) return;
3621 if(ivideo->currentvbflags & CRT2_TV) {
3623 if(ivideo->vbflags & VB_CHRONTEL) {
3625 int y = ivideo->tvy;
3627 switch(ivideo->chronteltype) {
3631 outSISIDXREG(SISSR,0x05,0x86);
3632 SiS_SetCH700x(&ivideo->SiS_Pr, (((y & 0xff) << 8) | 0x0b));
3633 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, ((y & 0x0100) | 0x08),0xFE);
3636 /* Not supported by hardware */
3640 } else if(ivideo->vbflags & VB_SISBRIDGE) {
3644 p2_01 = ivideo->p2_01;
3645 p2_02 = ivideo->p2_02;
3649 while((p2_01 <= 0) || (p2_02 <= 0)) {
3653 outSISIDXREG(SISPART2,0x01,p2_01);
3654 outSISIDXREG(SISPART2,0x02,p2_02);
3660 sisfb_post_setmode(struct sis_video_info *ivideo)
3662 BOOLEAN crt1isoff = FALSE;
3663 BOOLEAN doit = TRUE;
3664 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3667 #ifdef CONFIG_FB_SIS_315
3671 outSISIDXREG(SISSR,0x05,0x86);
3673 #ifdef CONFIG_FB_SIS_315
3674 sisfb_fixup_SR11(ivideo);
3677 /* Now we actually HAVE changed the display mode */
3678 ivideo->modechanged = 1;
3680 /* We can't switch off CRT1 if bridge is in slave mode */
3681 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
3682 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3683 } else ivideo->sisfb_crt1off = 0;
3685 #ifdef CONFIG_FB_SIS_300
3686 if(ivideo->sisvga_engine == SIS_300_VGA) {
3687 if((ivideo->sisfb_crt1off) && (doit)) {
3694 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3697 #ifdef CONFIG_FB_SIS_315
3698 if(ivideo->sisvga_engine == SIS_315_VGA) {
3699 if((ivideo->sisfb_crt1off) && (doit)) {
3709 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3710 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3715 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3716 ivideo->currentvbflags |= VB_SINGLE_MODE;
3718 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3719 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3720 ivideo->currentvbflags |= VB_MIRROR_MODE;
3722 ivideo->currentvbflags |= VB_SINGLE_MODE;
3726 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3728 if(ivideo->currentvbflags & CRT2_TV) {
3729 if(ivideo->vbflags & VB_SISBRIDGE) {
3730 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3731 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3732 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3733 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3734 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3735 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3736 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3737 } else if(ivideo->vbflags & VB_CHRONTEL) {
3738 if(ivideo->chronteltype == 1) {
3739 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3740 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3741 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3742 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3747 if(ivideo->tvxpos) {
3748 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3750 if(ivideo->tvypos) {
3751 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3754 if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) { /* Set filter for SiS301 */
3756 unsigned char filter_tb = 0;
3758 switch (ivideo->video_width) {
3760 filter_tb = (ivideo->vbflags & TV_NTSC) ? 4 : 12;
3763 filter_tb = (ivideo->vbflags & TV_NTSC) ? 5 : 13;
3766 filter_tb = (ivideo->vbflags & TV_NTSC) ? 6 : 14;
3770 filter_tb = (ivideo->vbflags & TV_NTSC) ? 7 : 15;
3773 ivideo->sisfb_filter = -1;
3777 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
3779 if(ivideo->vbflags & TV_NTSC) {
3781 andSISIDXREG(SISPART2, 0x3a, 0x1f);
3783 if (ivideo->vbflags & TV_SVIDEO) {
3785 andSISIDXREG(SISPART2, 0x30, 0xdf);
3787 } else if (ivideo->vbflags & TV_AVIDEO) {
3789 orSISIDXREG(SISPART2, 0x30, 0x20);
3791 switch (ivideo->video_width) {
3793 outSISIDXREG(SISPART2, 0x35, 0xEB);
3794 outSISIDXREG(SISPART2, 0x36, 0x04);
3795 outSISIDXREG(SISPART2, 0x37, 0x25);
3796 outSISIDXREG(SISPART2, 0x38, 0x18);
3799 outSISIDXREG(SISPART2, 0x35, 0xEE);
3800 outSISIDXREG(SISPART2, 0x36, 0x0C);
3801 outSISIDXREG(SISPART2, 0x37, 0x22);
3802 outSISIDXREG(SISPART2, 0x38, 0x08);
3806 outSISIDXREG(SISPART2, 0x35, 0xEB);
3807 outSISIDXREG(SISPART2, 0x36, 0x15);
3808 outSISIDXREG(SISPART2, 0x37, 0x25);
3809 outSISIDXREG(SISPART2, 0x38, 0xF6);
3814 } else if(ivideo->vbflags & TV_PAL) {
3816 andSISIDXREG(SISPART2, 0x3A, 0x1F);
3818 if (ivideo->vbflags & TV_SVIDEO) {
3820 andSISIDXREG(SISPART2, 0x30, 0xDF);
3822 } else if (ivideo->vbflags & TV_AVIDEO) {
3824 orSISIDXREG(SISPART2, 0x30, 0x20);
3826 switch (ivideo->video_width) {
3828 outSISIDXREG(SISPART2, 0x35, 0xF1);
3829 outSISIDXREG(SISPART2, 0x36, 0xF7);
3830 outSISIDXREG(SISPART2, 0x37, 0x1F);
3831 outSISIDXREG(SISPART2, 0x38, 0x32);
3834 outSISIDXREG(SISPART2, 0x35, 0xF3);
3835 outSISIDXREG(SISPART2, 0x36, 0x00);
3836 outSISIDXREG(SISPART2, 0x37, 0x1D);
3837 outSISIDXREG(SISPART2, 0x38, 0x20);
3841 outSISIDXREG(SISPART2, 0x35, 0xFC);
3842 outSISIDXREG(SISPART2, 0x36, 0xFB);
3843 outSISIDXREG(SISPART2, 0x37, 0x14);
3844 outSISIDXREG(SISPART2, 0x38, 0x2A);
3850 if((ivideo->sisfb_filter >= 0) && (ivideo->sisfb_filter <= 7)) {
3851 outSISIDXREG(SISPART2,0x35,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][0]));
3852 outSISIDXREG(SISPART2,0x36,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][1]));
3853 outSISIDXREG(SISPART2,0x37,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][2]));
3854 outSISIDXREG(SISPART2,0x38,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][3]));
3861 SISINITSTATIC int __init sisfb_setup(char *options)
3865 sisfb_setdefaultparms();
3867 printk(KERN_DEBUG "sisfb: Options %s\n", options);
3869 if(!options || !(*options)) {
3873 while((this_opt = strsep(&options, ",")) != NULL) {
3875 if(!(*this_opt)) continue;
3877 if(!strnicmp(this_opt, "off", 3)) {
3879 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3880 /* Need to check crt2 type first for fstn/dstn */
3881 sisfb_search_crt2type(this_opt + 14);
3882 } else if(!strnicmp(this_opt, "tvmode:",7)) {
3883 sisfb_search_tvstd(this_opt + 7);
3884 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3885 sisfb_search_tvstd(this_opt + 7);
3886 } else if(!strnicmp(this_opt, "mode:", 5)) {
3887 sisfb_search_mode(this_opt + 5, FALSE);
3888 } else if(!strnicmp(this_opt, "vesa:", 5)) {
3889 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
3890 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
3891 } else if(!strnicmp(this_opt, "inverse", 7)) {
3893 /* fb_invert_cmaps(); */
3894 } else if(!strnicmp(this_opt, "font:", 5)) {
3895 if(strlen(this_opt + 5) < 40) {
3896 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
3897 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
3900 } else if(!strnicmp(this_opt, "rate:", 5)) {
3901 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
3902 } else if(!strnicmp(this_opt, "filter:", 7)) {
3903 sisfb_filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
3904 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3905 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
3906 } else if(!strnicmp(this_opt, "mem:",4)) {
3907 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
3908 } else if(!strnicmp(this_opt, "pdc:", 4)) {
3909 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
3910 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
3911 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
3912 } else if(!strnicmp(this_opt, "noaccel", 7)) {
3914 } else if(!strnicmp(this_opt, "accel", 5)) {
3916 } else if(!strnicmp(this_opt, "noypan", 6)) {
3918 } else if(!strnicmp(this_opt, "ypan", 4)) {
3920 } else if(!strnicmp(this_opt, "nomax", 5)) {
3922 } else if(!strnicmp(this_opt, "max", 3)) {
3924 } else if(!strnicmp(this_opt, "userom:", 7)) {
3925 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
3926 } else if(!strnicmp(this_opt, "useoem:", 7)) {
3927 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
3928 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
3929 sisfb_nocrt2rate = 1;
3930 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
3931 unsigned long temp = 2;
3932 temp = simple_strtoul(this_opt + 9, NULL, 0);
3933 if((temp == 0) || (temp == 1)) {
3934 sisfb_scalelcd = temp ^ 1;
3936 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
3938 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3939 if((temp >= -32) && (temp <= 32)) {
3940 sisfb_tvxposoffset = temp;
3942 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
3944 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3945 if((temp >= -32) && (temp <= 32)) {
3946 sisfb_tvyposoffset = temp;
3948 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
3949 sisfb_search_specialtiming(this_opt + 14);
3950 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
3952 temp = simple_strtoul(this_opt + 7, NULL, 0);
3953 if((temp >= 0) && (temp <= 3)) {
3954 sisfb_lvdshl = temp;
3956 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
3957 sisfb_search_mode(this_opt, TRUE);
3958 #if !defined(__i386__) && !defined(__x86_64__)
3959 } else if(!strnicmp(this_opt, "resetcard", 9)) {
3960 sisfb_resetcard = 1;
3961 } else if(!strnicmp(this_opt, "videoram:", 9)) {
3962 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
3965 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
3976 static UCHAR * __devinit sis_find_rom(struct pci_dev *pdev)
3978 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3983 SIS_IOTYPE1 *rom_base, *rom;
3985 if(!(myrombase = vmalloc(65536))) return NULL;
3987 #if defined(__i386__) || defined(__x86_64__)
3989 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
3991 rom_base = ioremap(temp, 0x10000);
3992 if(!rom_base) continue;
3994 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) {
3999 romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4000 if(romptr > (0x10000 - 8)) {
4005 rom = rom_base + romptr;
4007 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4008 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) {
4013 pciid = readb(rom + 4) | (readb(rom + 5) << 8);
4014 if(pciid != 0x1039) {
4019 pciid = readb(rom + 6) | (readb(rom + 7) << 8);
4020 if(pciid == ivideo->chip_id) {
4021 memcpy_fromio(myrombase, rom_base, 65536);
4031 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4032 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4033 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4035 rom_base = ioremap(ivideo->video_base, 65536);
4037 if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) {
4038 romptr = (u16)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4039 if(romptr <= (0x10000 - 8)) {
4040 rom = rom_base + romptr;
4041 if((readb(rom) == 'P') && (readb(rom + 1) == 'C') &&
4042 (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) {
4043 pciid = readb(rom + 4) | (readb(rom + 5) << 8);
4044 if(pciid == 0x1039) {
4045 pciid = readb(rom + 6) | (readb(rom + 7) << 8);
4046 if(pciid == ivideo->chip_id) {
4047 memcpy_fromio(myrombase, rom_base, 65536);
4049 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4058 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4066 #ifdef CONFIG_FB_SIS_300
4067 static int __devinit
4068 sisfb_chkbuswidth300(struct pci_dev *pdev, SIS_IOTYPE1 *FBAddress)
4070 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4075 andSISIDXREG(SISSR,0x15,0xFB);
4076 orSISIDXREG(SISSR,0x15,0x04);
4077 outSISIDXREG(SISSR,0x13,0x00);
4078 outSISIDXREG(SISSR,0x14,0xBF);
4080 for(i=0; i<2; i++) {
4082 for(j=0; j<4; j++) {
4083 writew(temp, FBAddress);
4084 if(readw(FBAddress) == temp) break;
4085 orSISIDXREG(SISSR,0x3c,0x01);
4086 inSISIDXREG(SISSR,0x05,reg);
4087 inSISIDXREG(SISSR,0x05,reg);
4088 andSISIDXREG(SISSR,0x3c,0xfe);
4089 inSISIDXREG(SISSR,0x05,reg);
4090 inSISIDXREG(SISSR,0x05,reg);
4095 writel(0x01234567L, FBAddress);
4096 writel(0x456789ABL, (FBAddress+4));
4097 writel(0x89ABCDEFL, (FBAddress+8));
4098 writel(0xCDEF0123L, (FBAddress+12));
4099 inSISIDXREG(SISSR,0x3b,reg);
4101 if(readl((FBAddress+12)) == 0xCDEF0123L) return(4); /* Channel A 128bit */
4103 if(readl((FBAddress+4)) == 0x456789ABL) return(2); /* Channel B 64bit */
4104 return(1); /* 32bit */
4107 static void __devinit
4108 sisfb_setramsize300(struct pci_dev *pdev)
4110 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4111 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4113 USHORT sr13, sr14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0;
4114 int PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
4115 int RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
4116 int PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k;
4117 const USHORT SiS_DRAMType[17][5] = {
4118 {0x0C,0x0A,0x02,0x40,0x39},
4119 {0x0D,0x0A,0x01,0x40,0x48},
4120 {0x0C,0x09,0x02,0x20,0x35},
4121 {0x0D,0x09,0x01,0x20,0x44},
4122 {0x0C,0x08,0x02,0x10,0x31},
4123 {0x0D,0x08,0x01,0x10,0x40},
4124 {0x0C,0x0A,0x01,0x20,0x34},
4125 {0x0C,0x09,0x01,0x08,0x32},
4126 {0x0B,0x08,0x02,0x08,0x21},
4127 {0x0C,0x08,0x01,0x08,0x30},
4128 {0x0A,0x08,0x02,0x04,0x11},
4129 {0x0B,0x0A,0x01,0x10,0x28},
4130 {0x09,0x08,0x02,0x02,0x01},
4131 {0x0B,0x09,0x01,0x08,0x24},
4132 {0x0B,0x08,0x01,0x04,0x20},
4133 {0x0A,0x08,0x01,0x02,0x10},
4134 {0x09,0x08,0x01,0x01,0x00}
4137 buswidth = sisfb_chkbuswidth300(pdev, FBAddr);
4141 for(i = 6; i >= 0; i--) {
4143 PseudoRankCapacity = 1 << i;
4144 for(j = 4; j >= 1; j--) {
4146 PseudoTotalCapacity = PseudoRankCapacity * j;
4147 PseudoAdrPinCount = 15 - j;
4148 if(PseudoTotalCapacity <= 64) {
4149 for(k = 0; k <= 16; k++) {
4151 RankCapacity = buswidth * SiS_DRAMType[k][3];
4152 AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
4153 if(RankCapacity == PseudoRankCapacity)
4154 if(AdrPinCount <= PseudoAdrPinCount) {
4155 if(j == 3) { /* Rank No */
4156 BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
4157 BankNumMid = RankCapacity * MB2Bank * 1 - 1;
4159 BankNumHigh = RankCapacity * MB2Bank * j - 1;
4160 BankNumMid = RankCapacity * MB2Bank * j / 2 - 1;
4162 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4163 PhysicalAdrHigh = BankNumHigh;
4164 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4165 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4167 andSISIDXREG(SISSR,0x15,0xFB); /* Test */
4168 orSISIDXREG(SISSR,0x15,0x04); /* Test */
4169 TotalCapacity = SiS_DRAMType[k][3] * buswidth;
4170 sr13 = SiS_DRAMType[k][4];
4171 if(buswidth == 4) sr14 = (TotalCapacity - 1) | 0x80;
4172 if(buswidth == 2) sr14 = (TotalCapacity - 1) | 0x40;
4173 if(buswidth == 1) sr14 = (TotalCapacity - 1) | 0x00;
4174 outSISIDXREG(SISSR,0x13,sr13);
4175 outSISIDXREG(SISSR,0x14,sr14);
4176 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4177 /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */
4178 writew(((USHORT)PhysicalAdrHigh), Addr);
4179 Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh;
4180 /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */
4181 writew(((USHORT)BankNumMid), Addr);
4182 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage;
4183 /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */
4184 writew(((USHORT)PhysicalAdrHalfPage), Addr);
4185 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage;
4186 /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */
4187 writew(((USHORT)PhysicalAdrOtherPage), Addr);
4189 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4190 data = readw(Addr); /* *((USHORT *)(Addr)); */
4191 if(data == PhysicalAdrHigh) Done = 1;
4199 static void __devinit sisfb_post_sis300(struct pci_dev *pdev)
4201 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4202 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4203 u16 index, rindex, memtype = 0;
4205 outSISIDXREG(SISSR,0x05,0x86);
4207 if(ivideo->sishw_ext.UseROM) {
4208 if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80) {
4209 memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4211 inSISIDXREG(SISSR,0x3a,memtype);
4216 if(ivideo->revision_id <= 0x13) {
4217 v1 = 0x44; v2 = 0x42; v3 = 0x80;
4218 v4 = 0x44; v5 = 0x42; v6 = 0x80;
4220 v1 = 0x68; v2 = 0x43; v3 = 0x80; /* Assume 125Mhz MCLK */
4221 v4 = 0x68; v5 = 0x43; v6 = 0x80; /* Assume 125Mhz ECLK */
4222 if(ivideo->sishw_ext.UseROM) {
4223 index = memtype * 5;
4224 rindex = index + 0x54;
4225 v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4226 v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4227 v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4228 rindex = index + 0x7c;
4229 v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4230 v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4231 v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4234 outSISIDXREG(SISSR,0x28,v1);
4235 outSISIDXREG(SISSR,0x29,v2);
4236 outSISIDXREG(SISSR,0x2a,v3);
4237 outSISIDXREG(SISSR,0x2e,v4);
4238 outSISIDXREG(SISSR,0x2f,v5);
4239 outSISIDXREG(SISSR,0x30,v6);
4241 if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0xa4];
4242 outSISIDXREG(SISSR,0x07,v1); /* DAC speed */
4243 outSISIDXREG(SISSR,0x11,0x0f); /* DDC, power save */
4244 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4245 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4246 if(ivideo->sishw_ext.UseROM) {
4248 v1 = ivideo->sishw_ext.pjVirtualRomBase[memtype];
4249 v2 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 8];
4250 v3 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 16];
4251 v4 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 24];
4252 v5 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 32];
4253 v6 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 40];
4254 v7 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 48];
4255 v8 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 56];
4257 if(ivideo->revision_id >= 0x80) v3 &= 0xfd;
4258 outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4259 outSISIDXREG(SISSR,0x16,v2);
4260 outSISIDXREG(SISSR,0x17,v3);
4261 outSISIDXREG(SISSR,0x18,v4);
4262 outSISIDXREG(SISSR,0x19,v5);
4263 outSISIDXREG(SISSR,0x1a,v6);
4264 outSISIDXREG(SISSR,0x1b,v7);
4265 outSISIDXREG(SISSR,0x1c,v8); /* ---- */
4266 andSISIDXREG(SISSR,0x15,0xfb);
4267 orSISIDXREG(SISSR,0x15,0x04);
4268 if(ivideo->sishw_ext.UseROM) {
4269 if(ivideo->sishw_ext.pjVirtualRomBase[0x53] & 0x02) {
4270 orSISIDXREG(SISSR,0x19,0x20);
4273 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4274 if(ivideo->revision_id >= 0x80) v1 |= 0x01;
4275 outSISIDXREG(SISSR,0x1f,v1);
4276 outSISIDXREG(SISSR,0x20,0xa0); /* linear & relocated io */
4277 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4278 if(ivideo->sishw_ext.UseROM) {
4279 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe8];
4280 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe9];
4281 v3 = ivideo->sishw_ext.pjVirtualRomBase[0xea];
4283 outSISIDXREG(SISSR,0x23,v1);
4284 outSISIDXREG(SISSR,0x24,v2);
4285 outSISIDXREG(SISSR,0x25,v3);
4286 outSISIDXREG(SISSR,0x21,0x84);
4287 outSISIDXREG(SISSR,0x22,0x00);
4288 outSISIDXREG(SISCR,0x37,0x00);
4289 orSISIDXREG(SISPART1,0x24,0x01); /* unlock crt2 */
4290 outSISIDXREG(SISPART1,0x00,0x00);
4291 v1 = 0x40; v2 = 0x11;
4292 if(ivideo->sishw_ext.UseROM) {
4293 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xec];
4294 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xeb];
4296 outSISIDXREG(SISPART1,0x02,v1);
4297 if(ivideo->revision_id >= 0x80) v2 &= ~0x01;
4298 inSISIDXREG(SISPART4,0x00,reg);
4299 if((reg == 1) || (reg == 2)) {
4300 outSISIDXREG(SISCR,0x37,0x02);
4301 outSISIDXREG(SISPART2,0x00,0x1c);
4302 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4303 if(ivideo->sishw_ext.UseROM) {
4304 v4 = ivideo->sishw_ext.pjVirtualRomBase[0xf5];
4305 v5 = ivideo->sishw_ext.pjVirtualRomBase[0xf6];
4306 v6 = ivideo->sishw_ext.pjVirtualRomBase[0xf7];
4308 outSISIDXREG(SISPART4,0x0d,v4);
4309 outSISIDXREG(SISPART4,0x0e,v5);
4310 outSISIDXREG(SISPART4,0x10,v6);
4311 outSISIDXREG(SISPART4,0x0f,0x3f);
4312 inSISIDXREG(SISPART4,0x01,reg);
4314 inSISIDXREG(SISPART4,0x23,reg);
4317 outSISIDXREG(SISPART4,0x23,reg);
4322 outSISIDXREG(SISSR,0x32,v2);
4323 andSISIDXREG(SISPART1,0x24,0xfe); /* Lock CRT2 */
4324 inSISIDXREG(SISSR,0x16,reg);
4326 outSISIDXREG(SISCR,0x35,reg);
4327 outSISIDXREG(SISCR,0x83,0x00);
4328 #if !defined(__i386__) && !defined(__x86_64__)
4329 if(sisfb_videoram) {
4330 outSISIDXREG(SISSR,0x13,0x28); /* ? */
4331 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4332 outSISIDXREG(SISSR,0x14,reg);
4335 /* Need to map max FB size for finding out about RAM size */
4336 ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000);
4337 if(ivideo->video_vbase) {
4338 sisfb_setramsize300(pdev);
4339 iounmap(ivideo->video_vbase);
4341 printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4342 outSISIDXREG(SISSR,0x13,0x28); /* ? */
4343 outSISIDXREG(SISSR,0x14,0x47); /* 8MB, 64bit default */
4345 #if !defined(__i386__) && !defined(__x86_64__)
4348 if(ivideo->sishw_ext.UseROM) {
4349 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe6];
4350 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe7];
4352 inSISIDXREG(SISSR,0x3a,reg);
4353 if((reg & 0x30) == 0x30) {
4354 v1 = 0x04; /* PCI */
4357 v1 = 0x14; /* AGP */
4361 outSISIDXREG(SISSR,0x21,v1);
4362 outSISIDXREG(SISSR,0x22,v2);
4366 #ifdef CONFIG_FB_SIS_315
4367 static void __devinit sisfb_post_sis315330(struct pci_dev *pdev)
4369 #ifdef YET_TO_BE_DONE
4370 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4371 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4372 u16 index, rindex, memtype = 0;
4373 u32 reg1_32, reg2_32, reg3_32;
4377 /* outSISIDXREG(0x3c4,0x05,0x86); */
4378 outSISIDXREG(SISSR,0x05,0x86);
4380 /* Enable relocated i/o ports */
4381 /* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */
4382 setSISIDXREG(SISSR,0x20,~0x10,0x20);
4385 for(i = 0; i < 0x22; i++) {
4386 outSISIDXREG(SISSR,(0x06 + i),0x00);
4389 if( is 330) v1 = 0x0b;
4390 for(i = 0; i < v1; i++) {
4391 outSISIDXREG(SISSR,(0x31 + i),0x00);
4393 for(i = 0; i < 0x10; i++) {
4394 outSISIDXREG(SISCR,(0x30 + i),0x00);
4398 reg = inSISREG(SISMISCR);
4399 outSISIDXREG(SISSR,0x28,0x81);
4400 outSISIDXREG(SISSR,0x2A,0x00);
4401 outSISIDXREG(SISSR,0x29,0xE1);
4402 outSISREG(SISMISCW,(reg | 0x0c));
4403 outSISIDXREG(SISSR,0x2B,0x81);
4404 outSISIDXREG(SISSR,0x2D,0x00);
4405 outSISIDXREG(SISSR,0x2C,0xE1);
4406 outSISIDXREG(SISSR,0x2E,0x81);
4407 outSISIDXREG(SISSR,0x30,0x00);
4408 outSISIDXREG(SISSR,0x2F,0xE1);
4409 SiS_DDC2Delay(....);
4410 outSISREG(SISMISCW,reg);
4412 /* Get memory type */
4413 if(ivideo->sishw_ext.UseROM) {
4414 if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80)) {
4415 memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4417 inSISIDXREG(SISSR,0x3a,memtype);
4421 if(memtype <= 1) memtype = 0;
4423 inSISIDXREG(SISCR,0x5F,reg);
4426 case 0x00: memtype = 1; break;
4427 case 0x10: memtype = 3; break;
4428 case 0x20: memtype = 3; break;
4429 default: memtype = 2;
4436 v1 = 0x3b; v2 = 0x22; v3 = 0x01; /* Assume 143Mhz MCLK */
4437 v4 = 0x5c; v5 = 0x23; v6 = 0x01; /* Assume 166Mhz ECLK */
4438 if(ivideo->sishw_ext.UseROM) {
4439 index = memtype * 5;
4440 rindex = index + 0x54;
4441 v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4442 v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4443 v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4444 rindex = index + 0x68;
4445 v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4446 v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4447 v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4449 outSISIDXREG(SISSR,0x28,v1);
4450 outSISIDXREG(SISSR,0x29,v2);
4451 outSISIDXREG(SISSR,0x2a,v3);
4453 inSISIDXREG(SISSR,0x3a,reg);
4459 outSISIDXREG(SISSR,0x2e,v4);
4460 outSISIDXREG(SISSR,0x2f,v5);
4461 outSISIDXREG(SISSR,0x30,v6);
4463 /* End of comp with 330 */
4466 if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0x7c];
4467 outSISIDXREG(SISSR,0x07,v1);
4468 outSISIDXREG(SISSR,0x11,0x0f);
4470 v1 = 0x00; v2 = 0x0f; v3 = 0xba; v4 = 0xa9;
4471 v5 = 0xa0; v6 = 0x00; v7 = 0x30;
4472 if(ivideo->sishw_ext.UseROM) {
4473 index = memtype + 0x7d;
4474 v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4475 v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4476 v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4477 v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4478 v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4479 v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
4480 v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
4482 outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0x7d step 4) */
4483 outSISIDXREG(SISSR,0x16,v2);
4484 outSISIDXREG(SISSR,0x17,v3);
4485 outSISIDXREG(SISSR,0x18,v4);
4486 outSISIDXREG(SISSR,0x19,v5);
4487 outSISIDXREG(SISSR,0x1a,v6);
4488 outSISIDXREG(SISSR,0x1b,v7);
4489 outSISIDXREG(SISSR,0x1c,v8); /* ---- */
4491 v1 = 0x77; v2 = 0x77; v3 = 0x00; v4 = 0x5b; v5 = 0x00;
4492 if(ivideo->sishw_ext.UseROM) {
4493 index = memtype + 0xa2;
4494 v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4495 v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4496 v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4497 v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4498 v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4500 outSISIDXREG(SISCR,0x40,v1);
4501 outSISIDXREG(SISCR,0x41,v2);
4502 outSISIDXREG(SISCR,0x42,v3);
4503 outSISIDXREG(SISCR,0x43,v4);
4504 outSISIDXREG(SISCR,0x44,v5);
4509 if(ivideo->sishw_ext.UseROM) {
4510 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4512 outSISIDXREG(SISCR,0x59,v1);
4514 v1 = 0x; v2 = 0x; v3 = 0x; v4 = 0x;
4515 v5 = 0x; v6 = 0x; v7 = 0x; v8 = 0x;
4516 if(ivideo->sishw_ext.UseROM) {
4517 index = memtype + 0xbe;
4518 v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4519 v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4520 v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4521 v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4522 v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4523 v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
4524 v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
4525 v8 = ivideo->sishw_ext.pjVirtualRomBase[index + 28];
4527 outSISIDXREG(SISCR,0x68,v1);
4528 outSISIDXREG(SISCR,0x69,v2);
4529 outSISIDXREG(SISCR,0x6a,v3);
4530 outSISIDXREG(SISCR,0x6b,v4);
4531 outSISIDXREG(SISCR,0x6c,v5);
4532 outSISIDXREG(SISCR,0x6d,v6);
4533 outSISIDXREG(SISCR,0x6e,v7);
4534 outSISIDXREG(SISCR,0x6f,v8);
4537 inSISIDXREG(SISSR,0x3b,reg);
4540 inSISIDXREG(SISCR,0x5F,reg);
4544 outSISIDXREG(SISCR,0x48,v1);
4545 outSISIDXREG(SISCR,0x4c,0x20);
4550 if(ivideo->sishw_ext.UseROM) {
4551 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4553 outSISIDXREG(SISCR,0x59,v1);
4560 outSISIDXREG(SISCR,0x48,0x23);
4562 andSISIDXREG(SISSR,0x16,0x0f);
4564 orSISIDXREG(SISSR,0x16,0x80);
4567 if(ivideo->sishw_ext.UseROM) {
4568 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x81 + memtype];
4570 if(!(v1 & 0x10)) v2 = 0xc0;
4572 orSISIDXREG(SISSR,0x16,v2);
4573 andSISIDXREG(SISSR,0x16,0x0f);
4574 if(!(v1 & 0x10)) v2 = 0x80;
4576 orSISIDXREG(SISSR,0x16,v2);
4580 const u8 sr3cseq1[] = { 0xc0,0xe0,0xf0,0xe0,0xf0,0xa0,0xb0,0xa0,0xb0,0x90,0xd0 };
4581 const u8 sr3cseq2[] = { 0xc0,0xa0,0xb0,0xa0,0xb0,0xe0,0xf0,0xa0,0xb0,0x90,0xd0 };
4582 for(i = 0; i < 11; i++) {
4583 outSISIDXREG(SISSR,0x3c,sr3cseq1[i]);
4585 outSISIDXREG(SISSR,0x3d,0x00);
4586 outSISIDXREG(SISSR,0x3d,0x04);
4587 SiS_DDC2Delay(0x200);
4588 v1 = inSISIDXREG(SISCR,0xEC);
4589 v2 = inSISIDXREG(SISCR,0xED);
4590 reg1_32 = (v2 << 8) | v1;
4591 outSISIDXREG(SISSR,0x3D,0x00);
4592 for(i = 0; i < 11; i++) {
4593 outSISIDXREG(SISSR,0x3c,sr3cseq2[i]);
4595 outSISIDXREG(SISSR,0x3d,0x00);
4596 outSISIDXREG(SISSR,0x3d,0x04);
4597 SiS_DDC2Delay(0x200);
4598 v1 = inSISIDXREG(SISCR,0xEC);
4599 v2 = inSISIDXREG(SISCR,0xED);
4600 reg2_32 = (v2 << 8) | v1;
4601 outSISIDXREG(SISSR,0x3D,0x00);
4602 reg3_32 = reg2_32 << 1;
4606 if(reg3_32 > reg1_32) v1 = 0x10;
4607 outSISIDXREG(SISCR,0x59,v1);
4613 if(ivideo->sishw_ext.UseROM) {
4614 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x99];
4616 outSISIDXREG(SISSR,0x1f,v1);
4618 outSISIDXREG(SISSR,0x20,0x20);
4620 v1 = 0xf6; v2 = 0x0d; v3 = 0x33;
4621 if(ivideo->sishw_ext.UseROM) {
4622 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9c];
4623 v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9d];
4624 v3 = ivideo->sishw_ext.pjVirtualRomBase[0x9e];
4626 outSISIDXREG(SISSR,0x23,v1);
4627 outSISIDXREG(SISSR,0x24,v2);
4628 outSISIDXREG(SISSR,0x25,v3);
4630 outSISIDXREG(SISSR,0x21,0x84);
4631 outSISIDXREG(SISSR,0x22,0x00);
4632 outSISIDXREG(SISSR,0x27,0x1f);
4634 v1 = 0x00; v2 = 0x00;
4635 if(ivideo->sishw_ext.UseROM) {
4636 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9F];
4637 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xA1];
4639 outSISIDXREG(SISSR,0x31,v1);
4640 outSISIDXREG(SISSR,0x33,v2);
4643 if(ivideo->sishw_ext.UseROM) {
4644 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xA0];
4646 v2 = inSISIDXREG(SISPART4,0x00);
4647 if((v2 != 1) && (v2 != 2)) v1 &= 0xef;
4648 outSISIDXREG(SISSR,0x32,v1);
4651 pci_read_config_long(pdev, 0x50, ®1_32);
4655 v1 = 0xAA; v2 = 0x33;
4656 if(ivideo->sishw_ext.UseROM) {
4657 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF7];
4658 v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9E];
4661 v1 = 0x88; v2 = 0x03;
4662 if(ivideo->sishw_ext.UseROM) {
4663 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF8];
4664 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xF6];
4667 outSISIDXREG(SISCR,0x49,v1);
4668 outSISIDXREG(SISSR,0x25,v2);
4670 v1 = inSISIDXREG(SISPART4,0x00);
4671 if((v1 == 1) || (v1 == 2)) {
4672 orSISIDXREG(SISPART1,0x2F,0x01); /* Unlock CRT2 */
4673 outSISIDXREG(SISPART1,0x00,0x00);
4675 if(ivideo->sishw_ext.UseROM) {
4676 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb6];
4678 outSISIDXREG(SISPART1,0x02,v1);
4679 outSISIDXREG(SISPART1,0x2E,0x08);
4680 outSISIDXREG(SISPART2,0x00,0x1c);
4681 v1 = 0x40; v2 = 0x00; v3 = 0x80;
4682 if(ivideo->sishw_ext.UseROM) {
4683 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb7];
4684 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xb8];
4685 v3 = ivideo->sishw_ext.pjVirtualRomBase[0xbb];
4687 outSISIDXREG(SISPART4,0x0d,v1);
4688 outSISIDXREG(SISPART4,0x0e,v2);
4689 outSISIDXREG(SISPART4,0x10,v3);
4690 outSISIDXREG(SISPART4,0x0F,0x3F);
4692 inSISIDXREG(SISPART4,0x01,reg);
4694 inSISIDXREG(SISPART4,0x23,reg);
4697 outSISIDXREG(SISPART4,0x23,reg);
4700 outSISIDXREG(SISCR,0x37,0x02); /* Why? */
4702 outSISIDXREG(SISCR,0x83,0x00);
4703 outSISIDXREG(SISCR,0x90,0x00);
4704 andSISIDXREG(SISSR,0x5B,0xDF);
4705 outSISIDXREG(SISVID,0x00,0x86);
4706 outSISIDXREG(SISVID,0x32,0x00);
4707 outSISIDXREG(SISVID,0x30,0x00);
4708 outSISIDXREG(SISVID,0x32,0x01);
4709 outSISIDXREG(SISVID,0x30,0x00);
4710 orSISIDXREG(SISCR,0x63,0x80);
4716 orSISIDXREG(SISSR,0x16,0x0f);
4717 orSISIDXREG(SISSR,0x18,0xA9);
4718 orSISIDXREG(SISSR,0x19,0xA0);
4719 orSISIDXREG(SISSR,0x1B,0x30);
4720 andSISIDXREG(SISSR,0x17,0xF8);
4721 orSISIDXREG(SISSR,0x19,0x03);
4722 andSIDIDXREG(SISSR,0x13,0x00);
4724 /* Need to map max FB size for finding out about RAM size */
4725 ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000);
4726 if(ivideo->video_vbase) {
4727 /* Find out about bus width */
4729 outSISIDXREG(SISSR,0x14,0x02);
4730 andSISIDXREG(SISSR,0x16,0x0F);
4731 orSISIDXREG(SISSR,0x16,0x80);
4741 /* Find out about size */
4744 iounmap(ivideo->video_vbase);
4746 printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4747 outSISIDXREG(SISSR,0x14,0x??); /* 8MB, 64bit default */
4750 /* AGP (Missing: Checks for VIA and AMD hosts) */
4751 v1 = 0xA5; v2 = 0xFB;
4752 if(ivideo->sishw_ext.UseROM) {
4753 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9A];
4754 v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9B];
4756 outSISIDXREG(SISSR,0x21,v1);
4757 outSISIDXREG(SISSR,0x22,v2);
4765 int __devinit sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
4767 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
4768 struct sis_video_info *ivideo = NULL;
4769 struct fb_info *sis_fb_info = NULL;
4772 int sisvga_enabled = 0, i;
4774 if(sisfb_off) return -ENXIO;
4776 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
4777 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
4778 if(!sis_fb_info) return -ENOMEM;
4780 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
4781 if(!sis_fb_info) return -ENOMEM;
4782 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
4783 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
4786 ivideo = (struct sis_video_info *)sis_fb_info->par;
4787 ivideo->memyselfandi = sis_fb_info;
4789 if(card_list == NULL) {
4790 ivideo->cardnumber = 0;
4792 struct sis_video_info *countvideo = card_list;
4793 ivideo->cardnumber = 1;
4794 while((countvideo = countvideo->next) != NULL) ivideo->cardnumber++;
4797 strncpy(ivideo->myid, chipinfo->chip_name, 30);
4799 ivideo->warncount = 0;
4800 ivideo->chip_id = pdev->device;
4801 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
4802 ivideo->sishw_ext.jChipRevision = ivideo->revision_id;
4803 pci_read_config_word(pdev, PCI_COMMAND, ®16);
4804 sisvga_enabled = reg16 & 0x01;
4805 ivideo->pcibus = pdev->bus->number;
4806 ivideo->pcislot = PCI_SLOT(pdev->devfn);
4807 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
4808 ivideo->subsysvendor = pdev->subsystem_vendor;
4809 ivideo->subsysdevice = pdev->subsystem_device;
4812 if(sisfb_mode_idx == -1) {
4813 sisfb_get_vga_mode_from_kernel();
4817 ivideo->chip = chipinfo->chip;
4818 ivideo->sisvga_engine = chipinfo->vgaengine;
4819 ivideo->hwcursor_size = chipinfo->hwcursor_size;
4820 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
4821 ivideo->mni = chipinfo->mni;
4823 ivideo->detectedpdc = 0xff;
4824 ivideo->detectedpdca = 0xff;
4825 ivideo->detectedlcda = 0xff;
4827 ivideo->sisfb_thismonitor.datavalid = FALSE;
4829 ivideo->sisfb_parm_mem = sisfb_parm_mem;
4830 ivideo->sisfb_accel = sisfb_accel;
4831 ivideo->sisfb_ypan = sisfb_ypan;
4832 ivideo->sisfb_max = sisfb_max;
4833 ivideo->sisfb_userom = sisfb_userom;
4834 ivideo->sisfb_useoem = sisfb_useoem;
4835 ivideo->sisfb_mode_idx = sisfb_mode_idx;
4836 ivideo->sisfb_parm_rate = sisfb_parm_rate;
4837 ivideo->sisfb_crt1off = sisfb_crt1off;
4838 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
4839 ivideo->sisfb_crt2type = sisfb_crt2type;
4840 ivideo->sisfb_crt2flags = sisfb_crt2flags;
4841 /* pdc(a), scalelcd, special timing, lvdshl handled below */
4842 ivideo->sisfb_dstn = sisfb_dstn;
4843 ivideo->sisfb_fstn = sisfb_fstn;
4844 ivideo->sisfb_tvplug = sisfb_tvplug;
4845 ivideo->sisfb_tvstd = sisfb_tvstd;
4846 ivideo->tvxpos = sisfb_tvxposoffset;
4847 ivideo->tvypos = sisfb_tvyposoffset;
4848 ivideo->sisfb_filter = sisfb_filter;
4849 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
4850 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4851 ivideo->sisfb_inverse = sisfb_inverse;
4854 ivideo->refresh_rate = 0;
4855 if(ivideo->sisfb_parm_rate != -1) {
4856 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
4859 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
4860 ivideo->SiS_Pr.CenterScreen = -1;
4861 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
4862 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
4864 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
4865 ivideo->SiS_Pr.SiS_CHOverScan = -1;
4866 ivideo->SiS_Pr.SiS_ChSW = FALSE;
4867 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
4868 ivideo->SiS_Pr.HaveEMI = FALSE;
4869 ivideo->SiS_Pr.HaveEMILCD = FALSE;
4870 ivideo->SiS_Pr.OverruleEMI = FALSE;
4871 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
4872 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
4873 ivideo->SiS_Pr.PDC = -1;
4874 ivideo->SiS_Pr.PDCA = -1;
4875 #ifdef CONFIG_FB_SIS_315
4876 if(ivideo->chip >= SIS_330) {
4877 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
4878 if(ivideo->chip >= SIS_661) {
4879 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
4884 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
4886 pci_set_drvdata(pdev, ivideo);
4888 /* Patch special cases */
4889 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
4890 switch(ivideo->nbridge->device) {
4891 #ifdef CONFIG_FB_SIS_300
4892 case PCI_DEVICE_ID_SI_730:
4893 ivideo->chip = SIS_730;
4894 strcpy(ivideo->myid, "SiS 730");
4897 #ifdef CONFIG_FB_SIS_315
4898 case PCI_DEVICE_ID_SI_651:
4899 /* ivideo->chip is ok */
4900 strcpy(ivideo->myid, "SiS 651");
4902 case PCI_DEVICE_ID_SI_740:
4903 ivideo->chip = SIS_740;
4904 strcpy(ivideo->myid, "SiS 740");
4906 case PCI_DEVICE_ID_SI_661:
4907 ivideo->chip = SIS_661;
4908 strcpy(ivideo->myid, "SiS 661");
4910 case PCI_DEVICE_ID_SI_741:
4911 ivideo->chip = SIS_741;
4912 strcpy(ivideo->myid, "SiS 741");
4914 case PCI_DEVICE_ID_SI_760:
4915 ivideo->chip = SIS_760;
4916 strcpy(ivideo->myid, "SiS 760");
4922 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4923 strcpy(sis_fb_info->modename, ivideo->myid);
4926 ivideo->sishw_ext.jChipType = ivideo->chip;
4928 #ifdef CONFIG_FB_SIS_315
4929 if((ivideo->sishw_ext.jChipType == SIS_315PRO) ||
4930 (ivideo->sishw_ext.jChipType == SIS_315)) {
4931 ivideo->sishw_ext.jChipType = SIS_315H;
4935 ivideo->video_base = pci_resource_start(pdev, 0);
4936 ivideo->mmio_base = pci_resource_start(pdev, 1);
4937 ivideo->mmio_size = pci_resource_len(pdev, 1);
4938 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
4939 ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
4941 if(!sisvga_enabled) {
4942 if(pci_enable_device(pdev)) {
4943 pci_set_drvdata(pdev, NULL);
4949 SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress);
4951 #ifdef CONFIG_FB_SIS_300
4952 /* Find PCI systems for Chrontel/GPIO communication setup */
4953 if(ivideo->chip == SIS_630) {
4956 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
4957 mychswtable[i].subsysCard == ivideo->subsysdevice) {
4958 ivideo->SiS_Pr.SiS_ChSW = TRUE;
4959 printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
4960 mychswtable[i].vendorName, mychswtable[i].cardName);
4964 } while(mychswtable[i].subsysVendor != 0);
4968 outSISIDXREG(SISSR, 0x05, 0x86);
4970 if( (!sisvga_enabled)
4971 #if !defined(__i386__) && !defined(__x86_64__)
4972 || (sisfb_resetcard)
4975 for(i = 0x30; i <= 0x3f; i++) {
4976 outSISIDXREG(SISCR,i,0x00);
4980 /* Find out about current video mode */
4981 ivideo->modeprechange = 0x03;
4982 inSISIDXREG(SISCR,0x34,reg);
4984 ivideo->modeprechange = reg & 0x7f;
4985 } else if(sisvga_enabled) {
4986 #if defined(__i386__) || defined(__x86_64__)
4987 unsigned char SIS_IOTYPE2 *tt = ioremap(0, 0x1000);
4989 ivideo->modeprechange = readb(tt + 0x449);
4995 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4997 if((reg & 0x80) && (reg != 0xff)) {
4998 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) {
4999 printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
5000 pci_set_drvdata(pdev, NULL);
5008 ivideo->sishw_ext.bIntegratedMMEnabled = TRUE;
5009 #ifdef CONFIG_FB_SIS_300
5010 if(ivideo->sisvga_engine == SIS_300_VGA) {
5011 if(ivideo->chip != SIS_300) {
5012 inSISIDXREG(SISSR, 0x1a, reg);
5014 ivideo->sishw_ext.bIntegratedMMEnabled = FALSE;
5020 ivideo->bios_abase = NULL;
5021 if(ivideo->sisfb_userom) {
5022 ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
5023 ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase;
5024 if(ivideo->sishw_ext.pjVirtualRomBase) {
5025 printk(KERN_INFO "sisfb: Video ROM found and copied\n");
5026 ivideo->sishw_ext.UseROM = TRUE;
5028 ivideo->sishw_ext.UseROM = FALSE;
5029 printk(KERN_INFO "sisfb: Video ROM not found\n");
5032 ivideo->sishw_ext.pjVirtualRomBase = NULL;
5033 ivideo->sishw_ext.UseROM = FALSE;
5034 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
5037 /* Find systems for special custom timing */
5038 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
5040 unsigned char *biosver = NULL;
5041 unsigned char *biosdate = NULL;
5045 if(ivideo->sishw_ext.UseROM) {
5046 biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
5047 biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
5048 for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
5053 if( (mycustomttable[i].chipID == ivideo->chip) &&
5054 ((!strlen(mycustomttable[i].biosversion)) ||
5055 (ivideo->sishw_ext.UseROM &&
5056 (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
5057 ((!strlen(mycustomttable[i].biosdate)) ||
5058 (ivideo->sishw_ext.UseROM &&
5059 (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
5060 ((!mycustomttable[i].bioschksum) ||
5061 (ivideo->sishw_ext.UseROM &&
5062 (mycustomttable[i].bioschksum == chksum))) &&
5063 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
5064 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
5066 for(j = 0; j < 5; j++) {
5067 if(mycustomttable[i].biosFootprintAddr[j]) {
5068 if(ivideo->sishw_ext.UseROM) {
5069 if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
5070 mycustomttable[i].biosFootprintData[j]) {
5073 } else footprint = FALSE;
5077 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
5078 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
5079 mycustomttable[i].vendorName,
5080 mycustomttable[i].cardName);
5081 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
5082 mycustomttable[i].optionName);
5087 } while(mycustomttable[i].chipID);
5090 #ifdef CONFIG_FB_SIS_300
5091 if(ivideo->sisvga_engine == SIS_300_VGA) {
5092 if( (!sisvga_enabled)
5093 #if !defined(__i386__) && !defined(__x86_64__)
5094 || (sisfb_resetcard)
5097 if(ivideo->chip == SIS_300) {
5098 sisfb_post_sis300(pdev);
5104 #ifdef CONFIG_FB_SIS_315
5105 if(ivideo->sisvga_engine == SIS_315_VGA) {
5106 if( (!sisvga_enabled)
5107 #if !defined(__i386__) && !defined(__x86_64__)
5108 || (sisfb_resetcard)
5111 if((ivideo->chip == SIS_315H) ||
5112 (ivideo->chip == SIS_315) ||
5113 (ivideo->chip == SIS_315PRO) ||
5114 (ivideo->chip == SIS_330)) {
5115 sisfb_post_sis315330(pdev);
5121 if(sisfb_get_dram_size(ivideo)) {
5122 printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
5123 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5124 pci_set_drvdata(pdev, NULL);
5129 if((ivideo->sisfb_mode_idx < 0) ||
5130 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5131 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
5132 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
5133 /* Enable 2D accelerator engine */
5134 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
5137 if(sisfb_pdc != 0xff) {
5138 if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
5139 else sisfb_pdc &= 0x1f;
5140 ivideo->SiS_Pr.PDC = sisfb_pdc;
5142 #ifdef CONFIG_FB_SIS_315
5143 if(ivideo->sisvga_engine == SIS_315_VGA) {
5144 if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
5148 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
5149 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
5150 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
5151 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5152 pci_set_drvdata(pdev, NULL);
5157 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
5158 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
5159 release_mem_region(ivideo->video_base, ivideo->video_size);
5160 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5161 pci_set_drvdata(pdev, NULL);
5166 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
5167 ivideo->sishw_ext.pjVideoMemoryAddress = ivideo->video_vbase;
5168 if(!ivideo->video_vbase) {
5169 printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
5170 release_mem_region(ivideo->video_base, ivideo->video_size);
5171 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5172 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5173 pci_set_drvdata(pdev, NULL);
5178 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
5179 if(!ivideo->mmio_vbase) {
5180 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
5181 iounmap(ivideo->video_vbase);
5182 release_mem_region(ivideo->video_base, ivideo->video_size);
5183 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5184 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5185 pci_set_drvdata(pdev, NULL);
5190 printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n",
5191 ivideo->video_base, (ULONG)ivideo->video_vbase, ivideo->video_size / 1024);
5193 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
5194 ivideo->mmio_base, (ULONG)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
5196 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
5197 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
5200 /* Used for clearing the screen only, therefore respect our mem limit */
5201 ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
5205 ivideo->vbflags = 0;
5206 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
5207 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
5208 ivideo->defmodeidx = DEFAULT_MODE;
5210 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
5212 if((ivideo->sisfb_mode_idx < 0) ||
5213 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5215 sisfb_sense_crt1(ivideo);
5217 sisfb_get_VB_type(ivideo);
5219 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5220 sisfb_detect_VB_connect(ivideo);
5223 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
5225 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5226 if(ivideo->sisfb_crt2type != -1) {
5227 if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
5228 ivideo->currentvbflags |= CRT2_LCD;
5229 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
5230 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
5233 /* Chrontel 700x TV detection often unreliable, therefore use a
5234 * different default order on such machines
5236 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
5237 if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5238 else if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
5239 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5241 if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
5242 else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5243 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5248 if(ivideo->vbflags & CRT2_LCD) {
5249 inSISIDXREG(SISCR, 0x36, reg);
5251 if(ivideo->sisvga_engine == SIS_300_VGA) {
5252 ivideo->CRT2LCDType = sis300paneltype[reg];
5253 } else if(ivideo->chip >= SIS_661) {
5254 ivideo->CRT2LCDType = sis661paneltype[reg];
5256 ivideo->CRT2LCDType = sis310paneltype[reg];
5257 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
5258 if((ivideo->CRT2LCDType != LCD_640x480_2) &&
5259 (ivideo->CRT2LCDType != LCD_640x480_3)) {
5260 ivideo->CRT2LCDType = LCD_320x480;
5264 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
5265 /* For broken BIOSes: Assume 1024x768, RGB18 */
5266 ivideo->CRT2LCDType = LCD_1024x768;
5267 setSISIDXREG(SISCR,0x36,0xf0,0x02);
5268 setSISIDXREG(SISCR,0x37,0xee,0x01);
5269 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
5271 for(i = 0; i < SIS_LCD_NUMBER; i++) {
5272 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
5273 ivideo->lcdxres = sis_lcd_data[i].xres;
5274 ivideo->lcdyres = sis_lcd_data[i].yres;
5275 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
5279 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
5280 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
5281 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
5282 ivideo->lcdxres = 848; ivideo->lcdyres = 480; ivideo->lcddefmodeidx = 47;
5284 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
5285 ivideo->lcdxres, ivideo->lcdyres);
5288 #ifdef CONFIG_FB_SIS_300
5289 /* Save the current PanelDelayCompensation if the LCD is currently used */
5290 if(ivideo->sisvga_engine == SIS_300_VGA) {
5291 if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
5293 inSISIDXREG(SISCR,0x30,tmp);
5295 /* Currently on LCD? If yes, read current pdc */
5296 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
5297 ivideo->detectedpdc &= 0x3c;
5298 if(ivideo->SiS_Pr.PDC == -1) {
5299 /* Let option override detection */
5300 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5302 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
5303 ivideo->detectedpdc);
5305 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5306 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
5307 ivideo->SiS_Pr.PDC);
5313 #ifdef CONFIG_FB_SIS_315
5314 if(ivideo->sisvga_engine == SIS_315_VGA) {
5316 /* Try to find about LCDA */
5317 if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
5319 inSISIDXREG(SISPART1,0x13,tmp);
5321 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
5322 ivideo->detectedlcda = 0x03;
5327 if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
5329 inSISIDXREG(SISCR,0x30,tmp);
5330 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5331 /* Currently on LCD? If yes, read current pdc */
5333 inSISIDXREG(SISPART1,0x2D,pdc);
5334 ivideo->detectedpdc = (pdc & 0x0f) << 1;
5335 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
5336 inSISIDXREG(SISPART1,0x35,pdc);
5337 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
5338 inSISIDXREG(SISPART1,0x20,pdc);
5339 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
5340 if(ivideo->newrom) {
5341 /* New ROM invalidates other PDC resp. */
5342 if(ivideo->detectedlcda != 0xff) {
5343 ivideo->detectedpdc = 0xff;
5345 ivideo->detectedpdca = 0xff;
5348 if(ivideo->SiS_Pr.PDC == -1) {
5349 if(ivideo->detectedpdc != 0xff) {
5350 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5353 if(ivideo->SiS_Pr.PDCA == -1) {
5354 if(ivideo->detectedpdca != 0xff) {
5355 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
5358 if(ivideo->detectedpdc != 0xff) {
5360 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
5361 ivideo->detectedpdc);
5363 if(ivideo->detectedpdca != 0xff) {
5365 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
5366 ivideo->detectedpdca);
5371 if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
5372 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
5373 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
5374 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
5375 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
5376 ivideo->SiS_Pr.HaveEMI = TRUE;
5377 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5378 ivideo->SiS_Pr.HaveEMILCD = TRUE;
5383 /* Let user override detected PDCs (all bridges) */
5384 if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
5385 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5386 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
5387 ivideo->SiS_Pr.PDC);
5389 if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
5390 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
5391 ivideo->SiS_Pr.PDCA);
5398 if(!ivideo->sisfb_crt1off) {
5399 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
5401 if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
5402 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
5403 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
5407 if(ivideo->sisfb_mode_idx >= 0) {
5408 int bu = ivideo->sisfb_mode_idx;
5409 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
5410 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
5411 if(bu != ivideo->sisfb_mode_idx) {
5412 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
5413 sisbios_mode[bu].xres,
5414 sisbios_mode[bu].yres,
5415 sisbios_mode[bu].bpp);
5419 if(ivideo->sisfb_mode_idx < 0) {
5420 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
5422 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
5425 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
5428 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
5433 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
5435 if(ivideo->refresh_rate != 0) {
5436 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
5439 if(ivideo->rate_idx == 0) {
5440 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
5441 ivideo->refresh_rate = 60;
5444 if(ivideo->sisfb_thismonitor.datavalid) {
5445 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
5446 ivideo->rate_idx, ivideo->refresh_rate)) {
5447 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
5451 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
5452 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
5453 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
5455 sisfb_set_vparms(ivideo);
5457 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5459 /* ---------------- For 2.4: Now switch the mode ------------------ */
5461 printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
5462 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5463 ivideo->refresh_rate);
5465 sisfb_pre_setmode(ivideo);
5467 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
5468 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
5470 iounmap(ivideo->video_vbase);
5471 iounmap(ivideo->mmio_vbase);
5472 release_mem_region(ivideo->video_base, ivideo->video_size);
5473 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5474 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5475 pci_set_drvdata(pdev, NULL);
5480 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
5482 sisfb_post_setmode(ivideo);
5484 /* Maximize regardless of sisfb_max at startup */
5485 ivideo->default_var.yres_virtual = 32767;
5487 /* Force reset of x virtual in crtc_to_var */
5488 ivideo->default_var.xres_virtual = 0;
5490 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
5492 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5493 sisfb_set_pitch(ivideo);
5496 if(ivideo->sisfb_accel) {
5498 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5500 sisfb_initaccel(ivideo);
5502 sis_fb_info->node = -1;
5503 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5504 sis_fb_info->fbops = &sisfb_ops;
5505 sis_fb_info->disp = &ivideo->sis_disp;
5506 sis_fb_info->blank = &sisfb_blank;
5507 sis_fb_info->switch_con = &sisfb_switch;
5508 sis_fb_info->updatevar = &sisfb_update_var;
5509 sis_fb_info->changevar = NULL;
5510 strcpy(sis_fb_info->fontname, sisfb_fontname);
5512 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
5514 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
5516 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
5517 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5518 ivideo->refresh_rate);
5520 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
5521 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
5522 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
5524 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
5526 ivideo->default_var.pixclock = (u32) (1000000000 /
5527 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5528 ivideo->mode_no, ivideo->rate_idx));
5530 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5531 ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
5532 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
5533 ivideo->default_var.pixclock <<= 1;
5537 if(ivideo->sisfb_ypan) {
5538 /* Maximize regardless of sisfb_max at startup */
5539 ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var);
5540 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
5541 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
5545 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5548 if(ivideo->sisfb_accel) {
5550 #ifdef STUPID_ACCELF_TEXT_SHIT
5551 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5554 sisfb_initaccel(ivideo);
5556 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
5557 sis_fb_info->flags = FBINFO_DEFAULT |
5558 FBINFO_HWACCEL_YPAN |
5559 FBINFO_HWACCEL_XPAN |
5560 FBINFO_HWACCEL_COPYAREA |
5561 FBINFO_HWACCEL_FILLRECT |
5562 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
5564 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5566 sis_fb_info->var = ivideo->default_var;
5567 sis_fb_info->fix = ivideo->sisfb_fix;
5568 sis_fb_info->screen_base = ivideo->video_vbase;
5569 sis_fb_info->fbops = &sisfb_ops;
5571 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
5572 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
5574 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
5577 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
5580 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
5581 MTRR_TYPE_WRCOMB, 1);
5583 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
5587 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5588 vc_resize_con(1, 1, 0);
5591 if(register_framebuffer(sis_fb_info) < 0) {
5592 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
5593 iounmap(ivideo->video_vbase);
5594 iounmap(ivideo->mmio_vbase);
5595 release_mem_region(ivideo->video_base, ivideo->video_size);
5596 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5597 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5598 pci_set_drvdata(pdev, NULL);
5603 ivideo->registered = 1;
5606 ivideo->next = card_list;
5609 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
5610 ivideo->sisfb_accel ? "enabled" : "disabled",
5611 ivideo->sisfb_ypan ?
5612 (ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
5615 printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n",
5616 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5617 GET_FB_IDX(sis_fb_info->node),
5621 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
5623 printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
5625 } /* if mode = "none" */
5630 /*****************************************************/
5631 /* PCI DEVICE HANDLING */
5632 /*****************************************************/
5634 static void __devexit sisfb_remove(struct pci_dev *pdev)
5636 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5637 struct fb_info *sis_fb_info = ivideo->memyselfandi;
5638 int registered = ivideo->registered;
5641 iounmap(ivideo->video_vbase);
5642 iounmap(ivideo->mmio_vbase);
5643 vfree(ivideo->bios_abase);
5645 /* Release mem regions */
5646 release_mem_region(ivideo->video_base, ivideo->video_size);
5647 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5650 /* Release MTRR region */
5652 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
5656 /* Unregister the framebuffer */
5657 if(ivideo->registered) {
5658 unregister_framebuffer(sis_fb_info);
5659 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5660 framebuffer_release(sis_fb_info);
5666 pci_set_drvdata(pdev, NULL);
5668 /* TODO: Restore the initial mode
5669 * This sounds easy but is as good as impossible
5670 * on many machines with SiS chip and video bridge
5671 * since text modes are always set up differently
5672 * from machine to machine. Depends on the type
5673 * of integration between chipset and bridge.
5676 printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
5680 static struct pci_driver sisfb_driver = {
5682 .id_table = sisfb_pci_table,
5683 .probe = sisfb_probe,
5684 .remove = __devexit_p(sisfb_remove)
5687 SISINITSTATIC int __init sisfb_init(void)
5689 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5691 char *options = NULL;
5693 if(fb_get_options("sisfb", &options))
5695 sisfb_setup(options);
5698 return(pci_register_driver(&sisfb_driver));
5701 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5703 module_init(sisfb_init);
5707 /*****************************************************/
5709 /*****************************************************/
5713 static char *mode = NULL;
5714 static int vesa = -1;
5715 static unsigned int rate = 0;
5716 static unsigned int crt1off = 1;
5717 static unsigned int mem = 0;
5718 static char *forcecrt2type = NULL;
5719 static int forcecrt1 = -1;
5720 static int pdc = -1;
5721 static int pdc1 = -1;
5722 static int noaccel = -1;
5723 static int noypan = -1;
5724 static int nomax = -1;
5725 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5726 static int inverse = 0;
5728 static int userom = -1;
5729 static int useoem = -1;
5730 static char *tvstandard = NULL;
5731 static int nocrt2rate = 0;
5732 static int scalelcd = -1;
5733 static char *specialtiming = NULL;
5734 static int lvdshl = -1;
5735 static int tvxposoffset = 0, tvyposoffset = 0;
5736 static int filter = -1;
5737 #if !defined(__i386__) && !defined(__x86_64__)
5738 static int resetcard = 0;
5739 static int videoram = 0;
5742 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
5743 MODULE_LICENSE("GPL");
5744 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
5746 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5747 MODULE_PARM(mem, "i");
5748 MODULE_PARM(noaccel, "i");
5749 MODULE_PARM(noypan, "i");
5750 MODULE_PARM(nomax, "i");
5751 MODULE_PARM(userom, "i");
5752 MODULE_PARM(useoem, "i");
5753 MODULE_PARM(mode, "s");
5754 MODULE_PARM(vesa, "i");
5755 MODULE_PARM(rate, "i");
5756 MODULE_PARM(forcecrt1, "i");
5757 MODULE_PARM(forcecrt2type, "s");
5758 MODULE_PARM(scalelcd, "i");
5759 MODULE_PARM(pdc, "i");
5760 MODULE_PARM(pdc1, "i");
5761 MODULE_PARM(specialtiming, "s");
5762 MODULE_PARM(lvdshl, "i");
5763 MODULE_PARM(tvstandard, "s");
5764 MODULE_PARM(tvxposoffset, "i");
5765 MODULE_PARM(tvyposoffset, "i");
5766 MODULE_PARM(filter, "i");
5767 MODULE_PARM(nocrt2rate, "i");
5768 MODULE_PARM(inverse, "i");
5769 #if !defined(__i386__) && !defined(__x86_64__)
5770 MODULE_PARM(resetcard, "i");
5771 MODULE_PARM(videoram, "i");
5775 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5776 module_param(mem, int, 0);
5777 module_param(noaccel, int, 0);
5778 module_param(noypan, int, 0);
5779 module_param(nomax, int, 0);
5780 module_param(userom, int, 0);
5781 module_param(useoem, int, 0);
5782 module_param(mode, charp, 0);
5783 module_param(vesa, int, 0);
5784 module_param(rate, int, 0);
5785 module_param(forcecrt1, int, 0);
5786 module_param(forcecrt2type, charp, 0);
5787 module_param(scalelcd, int, 0);
5788 module_param(pdc, int, 0);
5789 module_param(pdc1, int, 0);
5790 module_param(specialtiming, charp, 0);
5791 module_param(lvdshl, int, 0);
5792 module_param(tvstandard, charp, 0);
5793 module_param(tvxposoffset, int, 0);
5794 module_param(tvyposoffset, int, 0);
5795 module_param(filter, int, 0);
5796 module_param(nocrt2rate, int, 0);
5797 #if !defined(__i386__) && !defined(__x86_64__)
5798 module_param(resetcard, int, 0);
5799 module_param(videoram, int, 0);
5803 MODULE_PARM_DESC(mem,
5804 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
5805 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
5806 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
5807 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
5808 "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
5809 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
5810 "for XFree86 4.x/X.org 6.7 and later.\n");
5812 MODULE_PARM_DESC(noaccel,
5813 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
5816 MODULE_PARM_DESC(noypan,
5817 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
5818 "will be performed by redrawing the screen. (default: 0)\n");
5820 MODULE_PARM_DESC(nomax,
5821 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
5822 "memory for the virtual screen in order to optimize scrolling performance. If\n"
5823 "this is set to anything other than 0, sisfb will not do this and thereby \n"
5824 "enable the user to positively specify a virtual Y size of the screen using\n"
5825 "fbset. (default: 0)\n");
5827 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5828 MODULE_PARM_DESC(mode,
5829 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
5830 "1024x768x16. Other formats supported include XxY-Depth and\n"
5831 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5832 "number, it will be interpreted as a VESA mode number. (default: none if\n"
5833 "sisfb is a module; this leaves the console untouched and the driver will\n"
5834 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
5835 "is in the kernel)\n");
5836 MODULE_PARM_DESC(vesa,
5837 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
5838 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
5839 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
5840 "0x0103 if sisfb is in the kernel)\n");
5843 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5844 MODULE_PARM_DESC(mode,
5845 "\nSelects the desired default display mode in the format XxYxDepth,\n"
5846 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
5847 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5848 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
5850 MODULE_PARM_DESC(vesa,
5851 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
5852 "0x117 (default: 0x0103)\n");
5855 MODULE_PARM_DESC(rate,
5856 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
5857 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
5858 "will be ignored (default: 60)\n");
5860 MODULE_PARM_DESC(forcecrt1,
5861 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
5862 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
5863 "0=CRT1 OFF) (default: [autodetected])\n");
5865 MODULE_PARM_DESC(forcecrt2type,
5866 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
5867 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
5868 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
5869 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
5870 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
5871 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
5872 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
5873 "depends on the very hardware in use. (default: [autodetected])\n");
5875 MODULE_PARM_DESC(scalelcd,
5876 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
5877 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
5878 "show black bars around the image, TMDS panels will probably do the scaling\n"
5879 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
5881 MODULE_PARM_DESC(pdc,
5882 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
5883 "should detect this correctly in most cases; however, sometimes this is not\n"
5884 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
5885 "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
5886 "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
5887 "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
5889 #ifdef CONFIG_FB_SIS_315
5890 MODULE_PARM_DESC(pdc1,
5891 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
5892 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
5893 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
5894 "implemented yet.\n");
5897 MODULE_PARM_DESC(specialtiming,
5898 "\nPlease refer to documentation for more information on this option.\n");
5900 MODULE_PARM_DESC(lvdshl,
5901 "\nPlease refer to documentation for more information on this option.\n");
5903 MODULE_PARM_DESC(tvstandard,
5904 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
5905 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
5907 MODULE_PARM_DESC(tvxposoffset,
5908 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
5911 MODULE_PARM_DESC(tvyposoffset,
5912 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
5915 MODULE_PARM_DESC(filter,
5916 "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
5917 "(Possible values 0-7, default: [no filter])\n");
5919 MODULE_PARM_DESC(nocrt2rate,
5920 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
5921 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
5923 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5924 MODULE_PARM_DESC(inverse,
5925 "\nSetting this to anything but 0 should invert the display colors, but this\n"
5926 "does not seem to work. (default: 0)\n");
5929 #if !defined(__i386__) && !defined(__x86_64__)
5930 #ifdef CONFIG_FB_SIS_300
5931 MODULE_PARM_DESC(resetcard,
5932 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
5933 "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
5936 MODULE_PARM_DESC(videoram,
5937 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
5938 "some non-x86 architectures where the memory auto detection fails. Only\n"
5939 "relevant if resetcard is set, too. Default: [auto-detect]\n");
5943 int __devinit sisfb_init_module(void)
5945 sisfb_setdefaultparms();
5947 if(rate) sisfb_parm_rate = rate;
5949 if((scalelcd == 0) || (scalelcd == 1)) {
5950 sisfb_scalelcd = scalelcd ^ 1;
5953 /* Need to check crt2 type first for fstn/dstn */
5956 sisfb_search_crt2type(forcecrt2type);
5959 sisfb_search_tvstd(tvstandard);
5962 sisfb_search_mode(mode, FALSE);
5964 sisfb_search_vesamode(vesa, FALSE);
5966 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
5968 sisfb_forcecrt1 = forcecrt1;
5969 if(forcecrt1 == 1) sisfb_crt1off = 0;
5970 else if(forcecrt1 == 0) sisfb_crt1off = 1;
5972 if(noaccel == 1) sisfb_accel = 0;
5973 else if(noaccel == 0) sisfb_accel = 1;
5975 if(noypan == 1) sisfb_ypan = 0;
5976 else if(noypan == 0) sisfb_ypan = 1;
5978 if(nomax == 1) sisfb_max = 0;
5979 else if(nomax == 0) sisfb_max = 1;
5981 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5982 if(inverse) sisfb_inverse = 1;
5985 if(mem) sisfb_parm_mem = mem;
5987 if(userom != -1) sisfb_userom = userom;
5988 if(useoem != -1) sisfb_useoem = useoem;
5990 if(pdc != -1) sisfb_pdc = (pdc & 0x7f);
5991 if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
5993 sisfb_nocrt2rate = nocrt2rate;
5996 sisfb_search_specialtiming(specialtiming);
5998 if((lvdshl >= 0) && (lvdshl <= 3)) sisfb_lvdshl = lvdshl;
6000 if(filter != -1) sisfb_filter = filter;
6002 sisfb_tvxposoffset = tvxposoffset;
6003 sisfb_tvyposoffset = tvyposoffset;
6005 #if !defined(__i386__) && !defined(__x86_64__)
6006 sisfb_resetcard = (resetcard) ? 1 : 0;
6007 if(videoram) sisfb_videoram = videoram;
6010 return(sisfb_init());
6013 static void __exit sisfb_remove_module(void)
6015 pci_unregister_driver(&sisfb_driver);
6016 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6019 module_init(sisfb_init_module);
6020 module_exit(sisfb_remove_module);
6022 #endif /* /MODULE */
6024 EXPORT_SYMBOL(sis_malloc);
6025 EXPORT_SYMBOL(sis_free);