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 static int __devinit sisfb_probe(struct pci_dev *pdev,
4766 const struct pci_device_id *ent)
4768 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
4769 struct sis_video_info *ivideo = NULL;
4770 struct fb_info *sis_fb_info = NULL;
4773 int sisvga_enabled = 0, i;
4775 if(sisfb_off) return -ENXIO;
4777 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
4778 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
4779 if(!sis_fb_info) return -ENOMEM;
4781 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
4782 if(!sis_fb_info) return -ENOMEM;
4783 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
4784 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
4787 ivideo = (struct sis_video_info *)sis_fb_info->par;
4788 ivideo->memyselfandi = sis_fb_info;
4790 if(card_list == NULL) {
4791 ivideo->cardnumber = 0;
4793 struct sis_video_info *countvideo = card_list;
4794 ivideo->cardnumber = 1;
4795 while((countvideo = countvideo->next) != NULL) ivideo->cardnumber++;
4798 strncpy(ivideo->myid, chipinfo->chip_name, 30);
4800 ivideo->warncount = 0;
4801 ivideo->chip_id = pdev->device;
4802 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
4803 ivideo->sishw_ext.jChipRevision = ivideo->revision_id;
4804 pci_read_config_word(pdev, PCI_COMMAND, ®16);
4805 sisvga_enabled = reg16 & 0x01;
4806 ivideo->pcibus = pdev->bus->number;
4807 ivideo->pcislot = PCI_SLOT(pdev->devfn);
4808 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
4809 ivideo->subsysvendor = pdev->subsystem_vendor;
4810 ivideo->subsysdevice = pdev->subsystem_device;
4813 if(sisfb_mode_idx == -1) {
4814 sisfb_get_vga_mode_from_kernel();
4818 ivideo->chip = chipinfo->chip;
4819 ivideo->sisvga_engine = chipinfo->vgaengine;
4820 ivideo->hwcursor_size = chipinfo->hwcursor_size;
4821 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
4822 ivideo->mni = chipinfo->mni;
4824 ivideo->detectedpdc = 0xff;
4825 ivideo->detectedpdca = 0xff;
4826 ivideo->detectedlcda = 0xff;
4828 ivideo->sisfb_thismonitor.datavalid = FALSE;
4830 ivideo->sisfb_parm_mem = sisfb_parm_mem;
4831 ivideo->sisfb_accel = sisfb_accel;
4832 ivideo->sisfb_ypan = sisfb_ypan;
4833 ivideo->sisfb_max = sisfb_max;
4834 ivideo->sisfb_userom = sisfb_userom;
4835 ivideo->sisfb_useoem = sisfb_useoem;
4836 ivideo->sisfb_mode_idx = sisfb_mode_idx;
4837 ivideo->sisfb_parm_rate = sisfb_parm_rate;
4838 ivideo->sisfb_crt1off = sisfb_crt1off;
4839 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
4840 ivideo->sisfb_crt2type = sisfb_crt2type;
4841 ivideo->sisfb_crt2flags = sisfb_crt2flags;
4842 /* pdc(a), scalelcd, special timing, lvdshl handled below */
4843 ivideo->sisfb_dstn = sisfb_dstn;
4844 ivideo->sisfb_fstn = sisfb_fstn;
4845 ivideo->sisfb_tvplug = sisfb_tvplug;
4846 ivideo->sisfb_tvstd = sisfb_tvstd;
4847 ivideo->tvxpos = sisfb_tvxposoffset;
4848 ivideo->tvypos = sisfb_tvyposoffset;
4849 ivideo->sisfb_filter = sisfb_filter;
4850 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
4851 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4852 ivideo->sisfb_inverse = sisfb_inverse;
4855 ivideo->refresh_rate = 0;
4856 if(ivideo->sisfb_parm_rate != -1) {
4857 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
4860 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
4861 ivideo->SiS_Pr.CenterScreen = -1;
4862 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
4863 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
4865 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
4866 ivideo->SiS_Pr.SiS_CHOverScan = -1;
4867 ivideo->SiS_Pr.SiS_ChSW = FALSE;
4868 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
4869 ivideo->SiS_Pr.HaveEMI = FALSE;
4870 ivideo->SiS_Pr.HaveEMILCD = FALSE;
4871 ivideo->SiS_Pr.OverruleEMI = FALSE;
4872 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
4873 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
4874 ivideo->SiS_Pr.PDC = -1;
4875 ivideo->SiS_Pr.PDCA = -1;
4876 #ifdef CONFIG_FB_SIS_315
4877 if(ivideo->chip >= SIS_330) {
4878 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
4879 if(ivideo->chip >= SIS_661) {
4880 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
4885 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
4887 pci_set_drvdata(pdev, ivideo);
4889 /* Patch special cases */
4890 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
4891 switch(ivideo->nbridge->device) {
4892 #ifdef CONFIG_FB_SIS_300
4893 case PCI_DEVICE_ID_SI_730:
4894 ivideo->chip = SIS_730;
4895 strcpy(ivideo->myid, "SiS 730");
4898 #ifdef CONFIG_FB_SIS_315
4899 case PCI_DEVICE_ID_SI_651:
4900 /* ivideo->chip is ok */
4901 strcpy(ivideo->myid, "SiS 651");
4903 case PCI_DEVICE_ID_SI_740:
4904 ivideo->chip = SIS_740;
4905 strcpy(ivideo->myid, "SiS 740");
4907 case PCI_DEVICE_ID_SI_661:
4908 ivideo->chip = SIS_661;
4909 strcpy(ivideo->myid, "SiS 661");
4911 case PCI_DEVICE_ID_SI_741:
4912 ivideo->chip = SIS_741;
4913 strcpy(ivideo->myid, "SiS 741");
4915 case PCI_DEVICE_ID_SI_760:
4916 ivideo->chip = SIS_760;
4917 strcpy(ivideo->myid, "SiS 760");
4923 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4924 strcpy(sis_fb_info->modename, ivideo->myid);
4927 ivideo->sishw_ext.jChipType = ivideo->chip;
4929 #ifdef CONFIG_FB_SIS_315
4930 if((ivideo->sishw_ext.jChipType == SIS_315PRO) ||
4931 (ivideo->sishw_ext.jChipType == SIS_315)) {
4932 ivideo->sishw_ext.jChipType = SIS_315H;
4936 ivideo->video_base = pci_resource_start(pdev, 0);
4937 ivideo->mmio_base = pci_resource_start(pdev, 1);
4938 ivideo->mmio_size = pci_resource_len(pdev, 1);
4939 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
4940 ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
4942 if(!sisvga_enabled) {
4943 if(pci_enable_device(pdev)) {
4944 pci_set_drvdata(pdev, NULL);
4950 SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress);
4952 #ifdef CONFIG_FB_SIS_300
4953 /* Find PCI systems for Chrontel/GPIO communication setup */
4954 if(ivideo->chip == SIS_630) {
4957 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
4958 mychswtable[i].subsysCard == ivideo->subsysdevice) {
4959 ivideo->SiS_Pr.SiS_ChSW = TRUE;
4960 printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
4961 mychswtable[i].vendorName, mychswtable[i].cardName);
4965 } while(mychswtable[i].subsysVendor != 0);
4969 outSISIDXREG(SISSR, 0x05, 0x86);
4971 if( (!sisvga_enabled)
4972 #if !defined(__i386__) && !defined(__x86_64__)
4973 || (sisfb_resetcard)
4976 for(i = 0x30; i <= 0x3f; i++) {
4977 outSISIDXREG(SISCR,i,0x00);
4981 /* Find out about current video mode */
4982 ivideo->modeprechange = 0x03;
4983 inSISIDXREG(SISCR,0x34,reg);
4985 ivideo->modeprechange = reg & 0x7f;
4986 } else if(sisvga_enabled) {
4987 #if defined(__i386__) || defined(__x86_64__)
4988 unsigned char SIS_IOTYPE2 *tt = ioremap(0, 0x1000);
4990 ivideo->modeprechange = readb(tt + 0x449);
4996 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4998 if((reg & 0x80) && (reg != 0xff)) {
4999 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) {
5000 printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
5001 pci_set_drvdata(pdev, NULL);
5009 ivideo->sishw_ext.bIntegratedMMEnabled = TRUE;
5010 #ifdef CONFIG_FB_SIS_300
5011 if(ivideo->sisvga_engine == SIS_300_VGA) {
5012 if(ivideo->chip != SIS_300) {
5013 inSISIDXREG(SISSR, 0x1a, reg);
5015 ivideo->sishw_ext.bIntegratedMMEnabled = FALSE;
5021 ivideo->bios_abase = NULL;
5022 if(ivideo->sisfb_userom) {
5023 ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
5024 ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase;
5025 if(ivideo->sishw_ext.pjVirtualRomBase) {
5026 printk(KERN_INFO "sisfb: Video ROM found and copied\n");
5027 ivideo->sishw_ext.UseROM = TRUE;
5029 ivideo->sishw_ext.UseROM = FALSE;
5030 printk(KERN_INFO "sisfb: Video ROM not found\n");
5033 ivideo->sishw_ext.pjVirtualRomBase = NULL;
5034 ivideo->sishw_ext.UseROM = FALSE;
5035 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
5038 /* Find systems for special custom timing */
5039 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
5041 unsigned char *biosver = NULL;
5042 unsigned char *biosdate = NULL;
5046 if(ivideo->sishw_ext.UseROM) {
5047 biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
5048 biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
5049 for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
5054 if( (mycustomttable[i].chipID == ivideo->chip) &&
5055 ((!strlen(mycustomttable[i].biosversion)) ||
5056 (ivideo->sishw_ext.UseROM &&
5057 (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
5058 ((!strlen(mycustomttable[i].biosdate)) ||
5059 (ivideo->sishw_ext.UseROM &&
5060 (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
5061 ((!mycustomttable[i].bioschksum) ||
5062 (ivideo->sishw_ext.UseROM &&
5063 (mycustomttable[i].bioschksum == chksum))) &&
5064 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
5065 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
5067 for(j = 0; j < 5; j++) {
5068 if(mycustomttable[i].biosFootprintAddr[j]) {
5069 if(ivideo->sishw_ext.UseROM) {
5070 if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
5071 mycustomttable[i].biosFootprintData[j]) {
5074 } else footprint = FALSE;
5078 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
5079 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
5080 mycustomttable[i].vendorName,
5081 mycustomttable[i].cardName);
5082 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
5083 mycustomttable[i].optionName);
5088 } while(mycustomttable[i].chipID);
5091 #ifdef CONFIG_FB_SIS_300
5092 if(ivideo->sisvga_engine == SIS_300_VGA) {
5093 if( (!sisvga_enabled)
5094 #if !defined(__i386__) && !defined(__x86_64__)
5095 || (sisfb_resetcard)
5098 if(ivideo->chip == SIS_300) {
5099 sisfb_post_sis300(pdev);
5105 #ifdef CONFIG_FB_SIS_315
5106 if(ivideo->sisvga_engine == SIS_315_VGA) {
5107 if( (!sisvga_enabled)
5108 #if !defined(__i386__) && !defined(__x86_64__)
5109 || (sisfb_resetcard)
5112 if((ivideo->chip == SIS_315H) ||
5113 (ivideo->chip == SIS_315) ||
5114 (ivideo->chip == SIS_315PRO) ||
5115 (ivideo->chip == SIS_330)) {
5116 sisfb_post_sis315330(pdev);
5122 if(sisfb_get_dram_size(ivideo)) {
5123 printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
5124 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5125 pci_set_drvdata(pdev, NULL);
5130 if((ivideo->sisfb_mode_idx < 0) ||
5131 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5132 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
5133 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
5134 /* Enable 2D accelerator engine */
5135 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
5138 if(sisfb_pdc != 0xff) {
5139 if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
5140 else sisfb_pdc &= 0x1f;
5141 ivideo->SiS_Pr.PDC = sisfb_pdc;
5143 #ifdef CONFIG_FB_SIS_315
5144 if(ivideo->sisvga_engine == SIS_315_VGA) {
5145 if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
5149 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
5150 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
5151 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
5152 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5153 pci_set_drvdata(pdev, NULL);
5158 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
5159 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
5160 release_mem_region(ivideo->video_base, ivideo->video_size);
5161 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5162 pci_set_drvdata(pdev, NULL);
5167 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
5168 ivideo->sishw_ext.pjVideoMemoryAddress = ivideo->video_vbase;
5169 if(!ivideo->video_vbase) {
5170 printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
5171 release_mem_region(ivideo->video_base, ivideo->video_size);
5172 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5173 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5174 pci_set_drvdata(pdev, NULL);
5179 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
5180 if(!ivideo->mmio_vbase) {
5181 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
5182 iounmap(ivideo->video_vbase);
5183 release_mem_region(ivideo->video_base, ivideo->video_size);
5184 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5185 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5186 pci_set_drvdata(pdev, NULL);
5191 printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n",
5192 ivideo->video_base, (ULONG)ivideo->video_vbase, ivideo->video_size / 1024);
5194 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
5195 ivideo->mmio_base, (ULONG)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
5197 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
5198 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
5201 /* Used for clearing the screen only, therefore respect our mem limit */
5202 ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
5206 ivideo->vbflags = 0;
5207 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
5208 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
5209 ivideo->defmodeidx = DEFAULT_MODE;
5211 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
5213 if((ivideo->sisfb_mode_idx < 0) ||
5214 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5216 sisfb_sense_crt1(ivideo);
5218 sisfb_get_VB_type(ivideo);
5220 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5221 sisfb_detect_VB_connect(ivideo);
5224 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
5226 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5227 if(ivideo->sisfb_crt2type != -1) {
5228 if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
5229 ivideo->currentvbflags |= CRT2_LCD;
5230 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
5231 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
5234 /* Chrontel 700x TV detection often unreliable, therefore use a
5235 * different default order on such machines
5237 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
5238 if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5239 else if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
5240 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5242 if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
5243 else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5244 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5249 if(ivideo->vbflags & CRT2_LCD) {
5250 inSISIDXREG(SISCR, 0x36, reg);
5252 if(ivideo->sisvga_engine == SIS_300_VGA) {
5253 ivideo->CRT2LCDType = sis300paneltype[reg];
5254 } else if(ivideo->chip >= SIS_661) {
5255 ivideo->CRT2LCDType = sis661paneltype[reg];
5257 ivideo->CRT2LCDType = sis310paneltype[reg];
5258 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
5259 if((ivideo->CRT2LCDType != LCD_640x480_2) &&
5260 (ivideo->CRT2LCDType != LCD_640x480_3)) {
5261 ivideo->CRT2LCDType = LCD_320x480;
5265 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
5266 /* For broken BIOSes: Assume 1024x768, RGB18 */
5267 ivideo->CRT2LCDType = LCD_1024x768;
5268 setSISIDXREG(SISCR,0x36,0xf0,0x02);
5269 setSISIDXREG(SISCR,0x37,0xee,0x01);
5270 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
5272 for(i = 0; i < SIS_LCD_NUMBER; i++) {
5273 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
5274 ivideo->lcdxres = sis_lcd_data[i].xres;
5275 ivideo->lcdyres = sis_lcd_data[i].yres;
5276 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
5280 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
5281 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
5282 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
5283 ivideo->lcdxres = 848; ivideo->lcdyres = 480; ivideo->lcddefmodeidx = 47;
5285 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
5286 ivideo->lcdxres, ivideo->lcdyres);
5289 #ifdef CONFIG_FB_SIS_300
5290 /* Save the current PanelDelayCompensation if the LCD is currently used */
5291 if(ivideo->sisvga_engine == SIS_300_VGA) {
5292 if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
5294 inSISIDXREG(SISCR,0x30,tmp);
5296 /* Currently on LCD? If yes, read current pdc */
5297 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
5298 ivideo->detectedpdc &= 0x3c;
5299 if(ivideo->SiS_Pr.PDC == -1) {
5300 /* Let option override detection */
5301 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5303 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
5304 ivideo->detectedpdc);
5306 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5307 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
5308 ivideo->SiS_Pr.PDC);
5314 #ifdef CONFIG_FB_SIS_315
5315 if(ivideo->sisvga_engine == SIS_315_VGA) {
5317 /* Try to find about LCDA */
5318 if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
5320 inSISIDXREG(SISPART1,0x13,tmp);
5322 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
5323 ivideo->detectedlcda = 0x03;
5328 if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
5330 inSISIDXREG(SISCR,0x30,tmp);
5331 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5332 /* Currently on LCD? If yes, read current pdc */
5334 inSISIDXREG(SISPART1,0x2D,pdc);
5335 ivideo->detectedpdc = (pdc & 0x0f) << 1;
5336 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
5337 inSISIDXREG(SISPART1,0x35,pdc);
5338 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
5339 inSISIDXREG(SISPART1,0x20,pdc);
5340 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
5341 if(ivideo->newrom) {
5342 /* New ROM invalidates other PDC resp. */
5343 if(ivideo->detectedlcda != 0xff) {
5344 ivideo->detectedpdc = 0xff;
5346 ivideo->detectedpdca = 0xff;
5349 if(ivideo->SiS_Pr.PDC == -1) {
5350 if(ivideo->detectedpdc != 0xff) {
5351 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5354 if(ivideo->SiS_Pr.PDCA == -1) {
5355 if(ivideo->detectedpdca != 0xff) {
5356 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
5359 if(ivideo->detectedpdc != 0xff) {
5361 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
5362 ivideo->detectedpdc);
5364 if(ivideo->detectedpdca != 0xff) {
5366 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
5367 ivideo->detectedpdca);
5372 if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
5373 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
5374 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
5375 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
5376 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
5377 ivideo->SiS_Pr.HaveEMI = TRUE;
5378 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5379 ivideo->SiS_Pr.HaveEMILCD = TRUE;
5384 /* Let user override detected PDCs (all bridges) */
5385 if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
5386 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5387 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
5388 ivideo->SiS_Pr.PDC);
5390 if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
5391 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
5392 ivideo->SiS_Pr.PDCA);
5399 if(!ivideo->sisfb_crt1off) {
5400 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
5402 if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
5403 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
5404 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
5408 if(ivideo->sisfb_mode_idx >= 0) {
5409 int bu = ivideo->sisfb_mode_idx;
5410 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
5411 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
5412 if(bu != ivideo->sisfb_mode_idx) {
5413 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
5414 sisbios_mode[bu].xres,
5415 sisbios_mode[bu].yres,
5416 sisbios_mode[bu].bpp);
5420 if(ivideo->sisfb_mode_idx < 0) {
5421 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
5423 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
5426 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
5429 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
5434 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
5436 if(ivideo->refresh_rate != 0) {
5437 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
5440 if(ivideo->rate_idx == 0) {
5441 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
5442 ivideo->refresh_rate = 60;
5445 if(ivideo->sisfb_thismonitor.datavalid) {
5446 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
5447 ivideo->rate_idx, ivideo->refresh_rate)) {
5448 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
5452 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
5453 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
5454 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
5456 sisfb_set_vparms(ivideo);
5458 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5460 /* ---------------- For 2.4: Now switch the mode ------------------ */
5462 printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
5463 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5464 ivideo->refresh_rate);
5466 sisfb_pre_setmode(ivideo);
5468 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
5469 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
5471 iounmap(ivideo->video_vbase);
5472 iounmap(ivideo->mmio_vbase);
5473 release_mem_region(ivideo->video_base, ivideo->video_size);
5474 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5475 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5476 pci_set_drvdata(pdev, NULL);
5481 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
5483 sisfb_post_setmode(ivideo);
5485 /* Maximize regardless of sisfb_max at startup */
5486 ivideo->default_var.yres_virtual = 32767;
5488 /* Force reset of x virtual in crtc_to_var */
5489 ivideo->default_var.xres_virtual = 0;
5491 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
5493 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5494 sisfb_set_pitch(ivideo);
5497 if(ivideo->sisfb_accel) {
5499 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5501 sisfb_initaccel(ivideo);
5503 sis_fb_info->node = -1;
5504 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5505 sis_fb_info->fbops = &sisfb_ops;
5506 sis_fb_info->disp = &ivideo->sis_disp;
5507 sis_fb_info->blank = &sisfb_blank;
5508 sis_fb_info->switch_con = &sisfb_switch;
5509 sis_fb_info->updatevar = &sisfb_update_var;
5510 sis_fb_info->changevar = NULL;
5511 strcpy(sis_fb_info->fontname, sisfb_fontname);
5513 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
5515 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
5517 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
5518 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5519 ivideo->refresh_rate);
5521 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
5522 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
5523 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
5525 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
5527 ivideo->default_var.pixclock = (u32) (1000000000 /
5528 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5529 ivideo->mode_no, ivideo->rate_idx));
5531 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5532 ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
5533 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
5534 ivideo->default_var.pixclock <<= 1;
5538 if(ivideo->sisfb_ypan) {
5539 /* Maximize regardless of sisfb_max at startup */
5540 ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var);
5541 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
5542 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
5546 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5549 if(ivideo->sisfb_accel) {
5551 #ifdef STUPID_ACCELF_TEXT_SHIT
5552 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5555 sisfb_initaccel(ivideo);
5557 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
5558 sis_fb_info->flags = FBINFO_DEFAULT |
5559 FBINFO_HWACCEL_YPAN |
5560 FBINFO_HWACCEL_XPAN |
5561 FBINFO_HWACCEL_COPYAREA |
5562 FBINFO_HWACCEL_FILLRECT |
5563 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
5565 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5567 sis_fb_info->var = ivideo->default_var;
5568 sis_fb_info->fix = ivideo->sisfb_fix;
5569 sis_fb_info->screen_base = ivideo->video_vbase;
5570 sis_fb_info->fbops = &sisfb_ops;
5572 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
5573 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
5575 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
5578 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
5581 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
5582 MTRR_TYPE_WRCOMB, 1);
5584 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
5588 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5589 vc_resize_con(1, 1, 0);
5592 if(register_framebuffer(sis_fb_info) < 0) {
5593 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
5594 iounmap(ivideo->video_vbase);
5595 iounmap(ivideo->mmio_vbase);
5596 release_mem_region(ivideo->video_base, ivideo->video_size);
5597 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5598 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5599 pci_set_drvdata(pdev, NULL);
5604 ivideo->registered = 1;
5607 ivideo->next = card_list;
5610 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
5611 ivideo->sisfb_accel ? "enabled" : "disabled",
5612 ivideo->sisfb_ypan ?
5613 (ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
5616 printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n",
5617 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5618 GET_FB_IDX(sis_fb_info->node),
5622 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
5624 printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
5626 } /* if mode = "none" */
5631 /*****************************************************/
5632 /* PCI DEVICE HANDLING */
5633 /*****************************************************/
5635 static void __devexit sisfb_remove(struct pci_dev *pdev)
5637 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5638 struct fb_info *sis_fb_info = ivideo->memyselfandi;
5639 int registered = ivideo->registered;
5642 iounmap(ivideo->video_vbase);
5643 iounmap(ivideo->mmio_vbase);
5644 vfree(ivideo->bios_abase);
5646 /* Release mem regions */
5647 release_mem_region(ivideo->video_base, ivideo->video_size);
5648 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5651 /* Release MTRR region */
5653 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
5657 /* Unregister the framebuffer */
5658 if(ivideo->registered) {
5659 unregister_framebuffer(sis_fb_info);
5660 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5661 framebuffer_release(sis_fb_info);
5667 pci_set_drvdata(pdev, NULL);
5669 /* TODO: Restore the initial mode
5670 * This sounds easy but is as good as impossible
5671 * on many machines with SiS chip and video bridge
5672 * since text modes are always set up differently
5673 * from machine to machine. Depends on the type
5674 * of integration between chipset and bridge.
5677 printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
5681 static struct pci_driver sisfb_driver = {
5683 .id_table = sisfb_pci_table,
5684 .probe = sisfb_probe,
5685 .remove = __devexit_p(sisfb_remove)
5688 SISINITSTATIC int __init sisfb_init(void)
5690 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5692 char *options = NULL;
5694 if(fb_get_options("sisfb", &options))
5696 sisfb_setup(options);
5699 return(pci_register_driver(&sisfb_driver));
5702 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5704 module_init(sisfb_init);
5708 /*****************************************************/
5710 /*****************************************************/
5714 static char *mode = NULL;
5715 static int vesa = -1;
5716 static unsigned int rate = 0;
5717 static unsigned int crt1off = 1;
5718 static unsigned int mem = 0;
5719 static char *forcecrt2type = NULL;
5720 static int forcecrt1 = -1;
5721 static int pdc = -1;
5722 static int pdc1 = -1;
5723 static int noaccel = -1;
5724 static int noypan = -1;
5725 static int nomax = -1;
5726 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5727 static int inverse = 0;
5729 static int userom = -1;
5730 static int useoem = -1;
5731 static char *tvstandard = NULL;
5732 static int nocrt2rate = 0;
5733 static int scalelcd = -1;
5734 static char *specialtiming = NULL;
5735 static int lvdshl = -1;
5736 static int tvxposoffset = 0, tvyposoffset = 0;
5737 static int filter = -1;
5738 #if !defined(__i386__) && !defined(__x86_64__)
5739 static int resetcard = 0;
5740 static int videoram = 0;
5743 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
5744 MODULE_LICENSE("GPL");
5745 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
5747 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5748 MODULE_PARM(mem, "i");
5749 MODULE_PARM(noaccel, "i");
5750 MODULE_PARM(noypan, "i");
5751 MODULE_PARM(nomax, "i");
5752 MODULE_PARM(userom, "i");
5753 MODULE_PARM(useoem, "i");
5754 MODULE_PARM(mode, "s");
5755 MODULE_PARM(vesa, "i");
5756 MODULE_PARM(rate, "i");
5757 MODULE_PARM(forcecrt1, "i");
5758 MODULE_PARM(forcecrt2type, "s");
5759 MODULE_PARM(scalelcd, "i");
5760 MODULE_PARM(pdc, "i");
5761 MODULE_PARM(pdc1, "i");
5762 MODULE_PARM(specialtiming, "s");
5763 MODULE_PARM(lvdshl, "i");
5764 MODULE_PARM(tvstandard, "s");
5765 MODULE_PARM(tvxposoffset, "i");
5766 MODULE_PARM(tvyposoffset, "i");
5767 MODULE_PARM(filter, "i");
5768 MODULE_PARM(nocrt2rate, "i");
5769 MODULE_PARM(inverse, "i");
5770 #if !defined(__i386__) && !defined(__x86_64__)
5771 MODULE_PARM(resetcard, "i");
5772 MODULE_PARM(videoram, "i");
5776 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5777 module_param(mem, int, 0);
5778 module_param(noaccel, int, 0);
5779 module_param(noypan, int, 0);
5780 module_param(nomax, int, 0);
5781 module_param(userom, int, 0);
5782 module_param(useoem, int, 0);
5783 module_param(mode, charp, 0);
5784 module_param(vesa, int, 0);
5785 module_param(rate, int, 0);
5786 module_param(forcecrt1, int, 0);
5787 module_param(forcecrt2type, charp, 0);
5788 module_param(scalelcd, int, 0);
5789 module_param(pdc, int, 0);
5790 module_param(pdc1, int, 0);
5791 module_param(specialtiming, charp, 0);
5792 module_param(lvdshl, int, 0);
5793 module_param(tvstandard, charp, 0);
5794 module_param(tvxposoffset, int, 0);
5795 module_param(tvyposoffset, int, 0);
5796 module_param(filter, int, 0);
5797 module_param(nocrt2rate, int, 0);
5798 #if !defined(__i386__) && !defined(__x86_64__)
5799 module_param(resetcard, int, 0);
5800 module_param(videoram, int, 0);
5804 MODULE_PARM_DESC(mem,
5805 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
5806 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
5807 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
5808 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
5809 "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
5810 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
5811 "for XFree86 4.x/X.org 6.7 and later.\n");
5813 MODULE_PARM_DESC(noaccel,
5814 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
5817 MODULE_PARM_DESC(noypan,
5818 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
5819 "will be performed by redrawing the screen. (default: 0)\n");
5821 MODULE_PARM_DESC(nomax,
5822 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
5823 "memory for the virtual screen in order to optimize scrolling performance. If\n"
5824 "this is set to anything other than 0, sisfb will not do this and thereby \n"
5825 "enable the user to positively specify a virtual Y size of the screen using\n"
5826 "fbset. (default: 0)\n");
5828 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5829 MODULE_PARM_DESC(mode,
5830 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
5831 "1024x768x16. Other formats supported include XxY-Depth and\n"
5832 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5833 "number, it will be interpreted as a VESA mode number. (default: none if\n"
5834 "sisfb is a module; this leaves the console untouched and the driver will\n"
5835 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
5836 "is in the kernel)\n");
5837 MODULE_PARM_DESC(vesa,
5838 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
5839 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
5840 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
5841 "0x0103 if sisfb is in the kernel)\n");
5844 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5845 MODULE_PARM_DESC(mode,
5846 "\nSelects the desired default display mode in the format XxYxDepth,\n"
5847 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
5848 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5849 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
5851 MODULE_PARM_DESC(vesa,
5852 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
5853 "0x117 (default: 0x0103)\n");
5856 MODULE_PARM_DESC(rate,
5857 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
5858 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
5859 "will be ignored (default: 60)\n");
5861 MODULE_PARM_DESC(forcecrt1,
5862 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
5863 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
5864 "0=CRT1 OFF) (default: [autodetected])\n");
5866 MODULE_PARM_DESC(forcecrt2type,
5867 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
5868 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
5869 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
5870 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
5871 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
5872 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
5873 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
5874 "depends on the very hardware in use. (default: [autodetected])\n");
5876 MODULE_PARM_DESC(scalelcd,
5877 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
5878 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
5879 "show black bars around the image, TMDS panels will probably do the scaling\n"
5880 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
5882 MODULE_PARM_DESC(pdc,
5883 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
5884 "should detect this correctly in most cases; however, sometimes this is not\n"
5885 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
5886 "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
5887 "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
5888 "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
5890 #ifdef CONFIG_FB_SIS_315
5891 MODULE_PARM_DESC(pdc1,
5892 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
5893 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
5894 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
5895 "implemented yet.\n");
5898 MODULE_PARM_DESC(specialtiming,
5899 "\nPlease refer to documentation for more information on this option.\n");
5901 MODULE_PARM_DESC(lvdshl,
5902 "\nPlease refer to documentation for more information on this option.\n");
5904 MODULE_PARM_DESC(tvstandard,
5905 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
5906 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
5908 MODULE_PARM_DESC(tvxposoffset,
5909 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
5912 MODULE_PARM_DESC(tvyposoffset,
5913 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
5916 MODULE_PARM_DESC(filter,
5917 "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
5918 "(Possible values 0-7, default: [no filter])\n");
5920 MODULE_PARM_DESC(nocrt2rate,
5921 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
5922 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
5924 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5925 MODULE_PARM_DESC(inverse,
5926 "\nSetting this to anything but 0 should invert the display colors, but this\n"
5927 "does not seem to work. (default: 0)\n");
5930 #if !defined(__i386__) && !defined(__x86_64__)
5931 #ifdef CONFIG_FB_SIS_300
5932 MODULE_PARM_DESC(resetcard,
5933 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
5934 "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
5937 MODULE_PARM_DESC(videoram,
5938 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
5939 "some non-x86 architectures where the memory auto detection fails. Only\n"
5940 "relevant if resetcard is set, too. Default: [auto-detect]\n");
5944 static int __devinit sisfb_init_module(void)
5946 sisfb_setdefaultparms();
5948 if(rate) sisfb_parm_rate = rate;
5950 if((scalelcd == 0) || (scalelcd == 1)) {
5951 sisfb_scalelcd = scalelcd ^ 1;
5954 /* Need to check crt2 type first for fstn/dstn */
5957 sisfb_search_crt2type(forcecrt2type);
5960 sisfb_search_tvstd(tvstandard);
5963 sisfb_search_mode(mode, FALSE);
5965 sisfb_search_vesamode(vesa, FALSE);
5967 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
5969 sisfb_forcecrt1 = forcecrt1;
5970 if(forcecrt1 == 1) sisfb_crt1off = 0;
5971 else if(forcecrt1 == 0) sisfb_crt1off = 1;
5973 if(noaccel == 1) sisfb_accel = 0;
5974 else if(noaccel == 0) sisfb_accel = 1;
5976 if(noypan == 1) sisfb_ypan = 0;
5977 else if(noypan == 0) sisfb_ypan = 1;
5979 if(nomax == 1) sisfb_max = 0;
5980 else if(nomax == 0) sisfb_max = 1;
5982 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5983 if(inverse) sisfb_inverse = 1;
5986 if(mem) sisfb_parm_mem = mem;
5988 if(userom != -1) sisfb_userom = userom;
5989 if(useoem != -1) sisfb_useoem = useoem;
5991 if(pdc != -1) sisfb_pdc = (pdc & 0x7f);
5992 if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
5994 sisfb_nocrt2rate = nocrt2rate;
5997 sisfb_search_specialtiming(specialtiming);
5999 if((lvdshl >= 0) && (lvdshl <= 3)) sisfb_lvdshl = lvdshl;
6001 if(filter != -1) sisfb_filter = filter;
6003 sisfb_tvxposoffset = tvxposoffset;
6004 sisfb_tvyposoffset = tvyposoffset;
6006 #if !defined(__i386__) && !defined(__x86_64__)
6007 sisfb_resetcard = (resetcard) ? 1 : 0;
6008 if(videoram) sisfb_videoram = videoram;
6011 return(sisfb_init());
6014 static void __exit sisfb_remove_module(void)
6016 pci_unregister_driver(&sisfb_driver);
6017 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6020 module_init(sisfb_init_module);
6021 module_exit(sisfb_remove_module);
6023 #endif /* /MODULE */
6025 EXPORT_SYMBOL(sis_malloc);
6026 EXPORT_SYMBOL(sis_free);