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/spinlock.h>
43 #include <linux/errno.h>
44 #include <linux/string.h>
46 #include <linux/tty.h>
47 #include <linux/slab.h>
48 #include <linux/delay.h>
50 #include <linux/console.h>
51 #include <linux/selection.h>
52 #include <linux/ioport.h>
53 #include <linux/init.h>
54 #include <linux/pci.h>
55 #include <linux/vmalloc.h>
56 #include <linux/vt_kern.h>
57 #include <linux/capability.h>
59 #include <linux/types.h>
60 #include <asm/uaccess.h>
66 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
67 #include <video/fbcon.h>
68 #include <video/fbcon-cfb8.h>
69 #include <video/fbcon-cfb16.h>
70 #include <video/fbcon-cfb24.h>
71 #include <video/fbcon-cfb32.h>
77 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
78 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
79 #error "This version of sisfb requires at least 2.6.3"
83 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
85 extern struct display_switch fbcon_sis8;
87 #ifdef FBCON_HAS_CFB16
88 extern struct display_switch fbcon_sis16;
90 #ifdef FBCON_HAS_CFB32
91 extern struct display_switch fbcon_sis32;
95 /* ------------------ Internal helper routines ----------------- */
98 sisfb_setdefaultparms(void)
108 /* Module: "None" for 2.4, default mode for 2.5+ */
109 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
112 sisfb_mode_idx = MODE_INDEX_NONE;
115 /* Static: Default mode */
118 sisfb_parm_rate = -1;
120 sisfb_forcecrt1 = -1;
126 sisfb_specialtiming = CUT_NONE;
132 sisfb_tvxposoffset = 0;
133 sisfb_tvyposoffset = 0;
135 sisfb_nocrt2rate = 0;
136 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
138 sisfb_fontname[0] = 0;
140 #if !defined(__i386__) && !defined(__x86_64__)
147 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
151 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
154 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
155 sisfb_mode_idx = MODE_INDEX_NONE;
158 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
160 sisfb_mode_idx = DEFAULT_MODE;
165 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
167 while(sisbios_mode[i++].mode_no[0] != 0) {
168 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
169 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
171 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
172 sisbios_mode[i-1].mode_no[1] == 0x56 ||
173 sisbios_mode[i-1].mode_no[1] == 0x53) continue;
175 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
176 sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
178 sisfb_mode_idx = i - 1;
183 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
187 sisfb_search_mode(char *name, BOOLEAN quiet)
190 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
191 char strbuf[16], strbuf1[20];
192 char *nameptr = name;
194 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
198 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
200 sisfb_mode_idx = DEFAULT_MODE;
204 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
205 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
207 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
209 sisfb_mode_idx = DEFAULT_MODE;
213 if(strlen(name) <= 19) {
214 strcpy(strbuf1, name);
215 for(i=0; i<strlen(strbuf1); i++) {
216 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
219 /* This does some fuzzy mode naming detection */
220 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
221 if((rate <= 32) || (depth > 32)) {
222 j = rate; rate = depth; depth = j;
224 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
226 sisfb_parm_rate = rate;
227 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
228 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
232 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
233 sprintf(strbuf, "%ux%ux8", xres, yres);
236 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
243 while(sisbios_mode[i].mode_no[0] != 0) {
244 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
246 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
247 sisbios_mode[i-1].mode_no[1] == 0x56 ||
248 sisbios_mode[i-1].mode_no[1] == 0x53) continue;
250 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
251 sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
253 sisfb_mode_idx = i - 1;
258 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
262 static void __devinit
263 sisfb_get_vga_mode_from_kernel(void)
265 #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
267 int mydepth = screen_info.lfb_depth;
269 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
271 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
272 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
273 (mydepth >= 8) && (mydepth <= 32) ) {
275 if(mydepth == 24) mydepth = 32;
277 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
278 screen_info.lfb_height,
281 printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode);
283 sisfb_search_mode(mymode, TRUE);
291 sisfb_search_crt2type(const char *name)
295 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
297 if(name == NULL) return;
299 while(sis_crt2type[i].type_no != -1) {
300 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
301 sisfb_crt2type = sis_crt2type[i].type_no;
302 sisfb_tvplug = sis_crt2type[i].tvplug_no;
303 sisfb_crt2flags = sis_crt2type[i].flags;
309 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
310 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
312 if(sisfb_crt2type < 0) {
313 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
318 sisfb_search_tvstd(const char *name)
322 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
324 if(name == NULL) return;
326 while(sis_tvtype[i].type_no != -1) {
327 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
328 sisfb_tvstd = sis_tvtype[i].type_no;
336 sisfb_search_specialtiming(const char *name)
339 BOOLEAN found = FALSE;
341 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
343 if(name == NULL) return;
345 if(!strnicmp(name, "none", 4)) {
346 sisfb_specialtiming = CUT_FORCENONE;
347 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
349 while(mycustomttable[i].chipID != 0) {
350 if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {
351 sisfb_specialtiming = mycustomttable[i].SpecialID;
353 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
354 mycustomttable[i].vendorName, mycustomttable[i].cardName,
355 mycustomttable[i].optionName);
361 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
362 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
364 while(mycustomttable[i].chipID != 0) {
365 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
366 mycustomttable[i].optionName,
367 mycustomttable[i].vendorName,
368 mycustomttable[i].cardName);
375 static BOOLEAN __devinit
376 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
378 int i, j, xres, yres, refresh, index;
381 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
382 buffer[2] != 0xff || buffer[3] != 0xff ||
383 buffer[4] != 0xff || buffer[5] != 0xff ||
384 buffer[6] != 0xff || buffer[7] != 0x00) {
385 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
389 if(buffer[0x12] != 0x01) {
390 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
395 monitor->feature = buffer[0x18];
397 if(!buffer[0x14] & 0x80) {
398 if(!(buffer[0x14] & 0x08)) {
399 printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n");
403 if(buffer[0x13] >= 0x01) {
404 /* EDID V1 rev 1 and 2: Search for monitor descriptor
409 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
410 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
411 buffer[j + 4] == 0x00) {
412 monitor->hmin = buffer[j + 7];
413 monitor->hmax = buffer[j + 8];
414 monitor->vmin = buffer[j + 5];
415 monitor->vmax = buffer[j + 6];
416 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
417 monitor->datavalid = TRUE;
424 if(!monitor->datavalid) {
425 /* Otherwise: Get a range from the list of supported
426 * Estabished Timings. This is not entirely accurate,
427 * because fixed frequency monitors are not supported
430 monitor->hmin = 65535; monitor->hmax = 0;
431 monitor->vmin = 65535; monitor->vmax = 0;
432 monitor->dclockmax = 0;
433 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
434 for(i = 0; i < 13; i++) {
435 if(emodes & sisfb_ddcsmodes[i].mask) {
436 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
437 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
438 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
439 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
440 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
444 for(i = 0; i < 8; i++) {
445 xres = (buffer[index] + 31) * 8;
446 switch(buffer[index + 1] & 0xc0) {
447 case 0xc0: yres = (xres * 9) / 16; break;
448 case 0x80: yres = (xres * 4) / 5; break;
449 case 0x40: yres = (xres * 3) / 4; break;
450 default: yres = xres; break;
452 refresh = (buffer[index + 1] & 0x3f) + 60;
453 if((xres >= 640) && (yres >= 480)) {
454 for(j = 0; j < 8; j++) {
455 if((xres == sisfb_ddcfmodes[j].x) &&
456 (yres == sisfb_ddcfmodes[j].y) &&
457 (refresh == sisfb_ddcfmodes[j].v)) {
458 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
459 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
460 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
461 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
462 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
468 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
469 monitor->datavalid = TRUE;
473 return(monitor->datavalid);
476 static void __devinit
477 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
479 USHORT temp, i, realcrtno = crtno;
482 monitor->datavalid = FALSE;
485 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
486 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
490 if((ivideo->sisfb_crt1off) && (!crtno)) return;
492 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
493 realcrtno, 0, &buffer[0]);
494 if((!temp) || (temp == 0xffff)) {
495 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
498 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
499 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
501 (temp & 0x1a) ? "" : "[none of the supported]",
502 (temp & 0x02) ? "2 " : "",
503 (temp & 0x08) ? "D&P" : "",
504 (temp & 0x10) ? "FPDI-2" : "");
506 i = 3; /* Number of retrys */
508 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
509 realcrtno, 1, &buffer[0]);
510 } while((temp) && i--);
512 if(sisfb_interpret_edid(monitor, &buffer[0])) {
513 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
514 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
515 monitor->dclockmax / 1000);
517 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
520 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
523 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
529 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
530 int mode_idx, int rate_idx, int rate)
533 unsigned int dclock, hsync;
535 if(!monitor->datavalid) return TRUE;
537 if(mode_idx < 0) return FALSE;
539 /* Skip for 320x200, 320x240, 640x400 */
540 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
551 #ifdef CONFIG_FB_SIS_315
554 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
558 if(rate < (monitor->vmin - 1)) return FALSE;
559 if(rate > (monitor->vmax + 1)) return FALSE;
561 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, &ivideo->sishw_ext,
562 sisbios_mode[mode_idx].mode_no[ivideo->mni],
563 &htotal, &vtotal, rate_idx)) {
564 dclock = (htotal * vtotal * rate) / 1000;
565 if(dclock > (monitor->dclockmax + 1000)) return FALSE;
566 hsync = dclock / htotal;
567 if(hsync < (monitor->hmin - 1)) return FALSE;
568 if(hsync > (monitor->hmax + 1)) return FALSE;
576 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
578 u16 xres=0, yres, myres;
580 #ifdef CONFIG_FB_SIS_300
581 if(ivideo->sisvga_engine == SIS_300_VGA) {
582 if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1);
585 #ifdef CONFIG_FB_SIS_315
586 if(ivideo->sisvga_engine == SIS_315_VGA) {
587 if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1);
591 myres = sisbios_mode[myindex].yres;
593 switch(vbflags & VB_DISPTYPE_DISP2) {
597 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
599 if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) {
600 if(sisbios_mode[myindex].xres > xres) return(-1);
601 if(myres > yres) return(-1);
604 if(vbflags & (VB_LVDS | VB_30xBDH)) {
605 if(sisbios_mode[myindex].xres == 320) {
606 if((myres == 240) || (myres == 480)) {
607 if(!ivideo->sisfb_fstn) {
608 if(sisbios_mode[myindex].mode_no[1] == 0x5a ||
609 sisbios_mode[myindex].mode_no[1] == 0x5b)
612 if(sisbios_mode[myindex].mode_no[1] == 0x50 ||
613 sisbios_mode[myindex].mode_no[1] == 0x56 ||
614 sisbios_mode[myindex].mode_no[1] == 0x53)
621 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
622 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
623 ivideo->SiS_Pr.SiS_CustomT, xres, yres) < 0x14) {
629 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
630 sisbios_mode[myindex].yres, 0) < 0x14) {
636 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
637 sisbios_mode[myindex].yres, 0) < 0x14) {
647 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
652 xres = sisbios_mode[mode_idx].xres;
653 yres = sisbios_mode[mode_idx].yres;
655 ivideo->rate_idx = 0;
656 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
657 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
658 if(sisfb_vrate[i].refresh == rate) {
659 ivideo->rate_idx = sisfb_vrate[i].idx;
661 } else if(sisfb_vrate[i].refresh > rate) {
662 if((sisfb_vrate[i].refresh - rate) <= 3) {
663 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
664 rate, sisfb_vrate[i].refresh);
665 ivideo->rate_idx = sisfb_vrate[i].idx;
666 ivideo->refresh_rate = sisfb_vrate[i].refresh;
667 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
668 && (sisfb_vrate[i].idx != 1)) {
669 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
670 rate, sisfb_vrate[i-1].refresh);
671 ivideo->rate_idx = sisfb_vrate[i-1].idx;
672 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
675 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
676 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
677 rate, sisfb_vrate[i].refresh);
678 ivideo->rate_idx = sisfb_vrate[i].idx;
684 if(ivideo->rate_idx > 0) {
685 return ivideo->rate_idx;
687 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
694 sisfb_bridgeisslave(struct sis_video_info *ivideo)
698 if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE;
700 inSISIDXREG(SISPART1,0x00,P1_00);
701 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
702 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
710 sisfballowretracecrt1(struct sis_video_info *ivideo)
714 inSISIDXREG(SISCR,0x17,temp);
715 if(!(temp & 0x80)) return FALSE;
717 inSISIDXREG(SISSR,0x1f,temp);
718 if(temp & 0xc0) return FALSE;
724 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
726 if(!sisfballowretracecrt1(ivideo)) return FALSE;
728 if(inSISREG(SISINPSTAT) & 0x08) return TRUE;
733 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
737 if(!sisfballowretracecrt1(ivideo)) return;
740 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
742 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
746 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
748 unsigned char temp, reg;
750 switch(ivideo->sisvga_engine) {
751 case SIS_300_VGA: reg = 0x25; break;
752 case SIS_315_VGA: reg = 0x30; break;
753 default: return FALSE;
756 inSISIDXREG(SISPART1, reg, temp);
757 if(temp & 0x02) return FALSE;
762 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
764 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
765 if(sisfb_bridgeisslave(ivideo)) {
766 return(sisfbcheckvretracecrt1(ivideo));
768 return(sisfbcheckvretracecrt2(ivideo));
771 return(sisfbcheckvretracecrt1(ivideo));
775 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
777 u8 idx, reg1, reg2, reg3, reg4;
780 (*vcount) = (*hcount) = 0;
782 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
783 ret |= (FB_VBLANK_HAVE_VSYNC |
784 FB_VBLANK_HAVE_HBLANK |
785 FB_VBLANK_HAVE_VBLANK |
786 FB_VBLANK_HAVE_VCOUNT |
787 FB_VBLANK_HAVE_HCOUNT);
788 switch(ivideo->sisvga_engine) {
789 case SIS_300_VGA: idx = 0x25; break;
791 case SIS_315_VGA: idx = 0x30; break;
793 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
794 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
795 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
796 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
797 if(!(reg1 & 0x01)) ret |= FB_VBLANK_VBLANKING;
798 if(!(reg1 & 0x02)) ret |= FB_VBLANK_VSYNCING;
799 if(!(reg4 & 0x80)) ret |= FB_VBLANK_HBLANKING;
800 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
801 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
802 } else if(sisfballowretracecrt1(ivideo)) {
803 ret |= (FB_VBLANK_HAVE_VSYNC |
804 FB_VBLANK_HAVE_VBLANK |
805 FB_VBLANK_HAVE_VCOUNT |
806 FB_VBLANK_HAVE_HCOUNT);
807 reg1 = inSISREG(SISINPSTAT);
808 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
809 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
810 inSISIDXREG(SISCR,0x20,reg1);
811 inSISIDXREG(SISCR,0x1b,reg1);
812 inSISIDXREG(SISCR,0x1c,reg2);
813 inSISIDXREG(SISCR,0x1d,reg3);
814 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
815 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
821 sisfb_myblank(struct sis_video_info *ivideo, int blank)
823 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
824 BOOLEAN backlight = TRUE;
845 case 2: /* no vsync */
854 case 3: /* no hsync */
876 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
878 if( (!ivideo->sisfb_thismonitor.datavalid) ||
879 ((ivideo->sisfb_thismonitor.datavalid) &&
880 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
882 if(ivideo->sisvga_engine == SIS_315_VGA) {
883 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
886 if(!(sisfb_bridgeisslave(ivideo))) {
887 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
888 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
894 if(ivideo->currentvbflags & CRT2_LCD) {
896 if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
898 SiS_SiS30xBLOn(&ivideo->SiS_Pr, &ivideo->sishw_ext);
900 SiS_SiS30xBLOff(&ivideo->SiS_Pr, &ivideo->sishw_ext);
902 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
903 if(ivideo->vbflags & VB_CHRONTEL) {
905 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr,&ivideo->sishw_ext);
907 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
912 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
913 (ivideo->vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
914 ((ivideo->sisvga_engine == SIS_315_VGA) &&
915 ((ivideo->vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
916 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
919 if(ivideo->sisvga_engine == SIS_300_VGA) {
920 if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
921 (!(ivideo->vbflags & VB_30xBDH))) {
922 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
924 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
925 if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
926 (!(ivideo->vbflags & VB_30xBDH))) {
927 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
931 } else if(ivideo->currentvbflags & CRT2_VGA) {
933 if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) {
934 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
942 /* ----------- FBDev related routines for all series ----------- */
945 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
947 return (var->bits_per_pixel == 8) ? 256 : 16;
951 sisfb_set_vparms(struct sis_video_info *ivideo)
953 switch(ivideo->video_bpp) {
955 ivideo->DstColor = 0x0000;
956 ivideo->SiS310_AccelDepth = 0x00000000;
957 ivideo->video_cmap_len = 256;
960 ivideo->DstColor = 0x8000;
961 ivideo->SiS310_AccelDepth = 0x00010000;
962 ivideo->video_cmap_len = 16;
965 ivideo->DstColor = 0xC000;
966 ivideo->SiS310_AccelDepth = 0x00020000;
967 ivideo->video_cmap_len = 16;
970 ivideo->video_cmap_len = 16;
971 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
978 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
980 int maxyres = ivideo->heapstart / (var->xres_virtual * (var->bits_per_pixel >> 3));
982 if(maxyres > 32767) maxyres = 32767;
988 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
990 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
991 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
992 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
993 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
994 ivideo->scrnpitchCRT1 <<= 1;
1001 sisfb_set_pitch(struct sis_video_info *ivideo)
1003 BOOLEAN isslavemode = FALSE;
1004 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1005 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1007 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
1009 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1010 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1011 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1012 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1015 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1016 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1017 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1018 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1019 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1024 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1026 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1028 switch(var->bits_per_pixel) {
1030 var->red.offset = var->green.offset = var->blue.offset = 0;
1031 var->red.length = var->green.length = var->blue.length = 6;
1034 var->red.offset = 11;
1035 var->red.length = 5;
1036 var->green.offset = 5;
1037 var->green.length = 6;
1038 var->blue.offset = 0;
1039 var->blue.length = 5;
1040 var->transp.offset = 0;
1041 var->transp.length = 0;
1044 var->red.offset = 16;
1045 var->red.length = 8;
1046 var->green.offset = 8;
1047 var->green.length = 8;
1048 var->blue.offset = 0;
1049 var->blue.length = 8;
1050 var->transp.offset = 24;
1051 var->transp.length = 8;
1057 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1059 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1060 unsigned int htotal = 0, vtotal = 0;
1061 unsigned int drate = 0, hrate = 0;
1066 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1068 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1070 pixclock = var->pixclock;
1072 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1073 vtotal += var->yres;
1075 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1076 vtotal += var->yres;
1078 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1079 vtotal += var->yres;
1081 } else vtotal += var->yres;
1083 if(!(htotal) || !(vtotal)) {
1084 DPRINTK("sisfb: Invalid 'var' information\n");
1088 if(pixclock && htotal && vtotal) {
1089 drate = 1000000000 / pixclock;
1090 hrate = (drate * 1000) / htotal;
1091 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1093 ivideo->refresh_rate = 60;
1096 old_mode = ivideo->sisfb_mode_idx;
1097 ivideo->sisfb_mode_idx = 0;
1099 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1100 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1101 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1102 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1103 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1104 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1108 ivideo->sisfb_mode_idx++;
1112 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1113 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1115 ivideo->sisfb_mode_idx = -1;
1118 if(ivideo->sisfb_mode_idx < 0) {
1119 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1120 var->yres, var->bits_per_pixel);
1121 ivideo->sisfb_mode_idx = old_mode;
1125 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1126 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1127 ivideo->refresh_rate = 60;
1130 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1131 if(ivideo->sisfb_thismonitor.datavalid) {
1132 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
1133 ivideo->rate_idx, ivideo->refresh_rate)) {
1134 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1139 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1140 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1144 sisfb_pre_setmode(ivideo);
1146 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
1147 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1151 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1153 sisfb_post_setmode(ivideo);
1155 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1156 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1157 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1159 sisfb_calc_pitch(ivideo, var);
1160 sisfb_set_pitch(ivideo);
1163 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1164 #ifdef STUPID_ACCELF_TEXT_SHIT
1165 if(var->accel_flags & FB_ACCELF_TEXT) {
1166 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1168 info->flags |= FBINFO_HWACCEL_DISABLED;
1171 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1173 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1176 sisfb_set_vparms(ivideo);
1178 ivideo->current_width = ivideo->video_width;
1179 ivideo->current_height = ivideo->video_height;
1180 ivideo->current_bpp = ivideo->video_bpp;
1181 ivideo->current_htotal = htotal;
1182 ivideo->current_vtotal = vtotal;
1183 ivideo->current_linelength = ivideo->video_linelength;
1184 ivideo->current_pixclock = var->pixclock;
1185 ivideo->current_refresh_rate = ivideo->refresh_rate;
1186 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1187 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1195 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1199 if(var->xoffset > (var->xres_virtual - var->xres)) {
1202 if(var->yoffset > (var->yres_virtual - var->yres)) {
1206 base = (var->yoffset * var->xres_virtual) + var->xoffset;
1208 /* calculate base bpp dep. */
1209 switch(var->bits_per_pixel) {
1221 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1223 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1224 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1225 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1226 if(ivideo->sisvga_engine == SIS_315_VGA) {
1227 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1229 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1230 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1231 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1232 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1233 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1234 if(ivideo->sisvga_engine == SIS_315_VGA) {
1235 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1241 /* ------------ FBDev related routines for 2.4 series ----------- */
1243 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1246 sisfb_crtc_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1248 u16 VRE, VBE, VRS, VBS, VDE, VT;
1249 u16 HRE, HBE, HRS, HBS, HDE, HT;
1250 u8 sr_data, cr_data, cr_data2, cr_data3, mr_data;
1251 int A, B, C, D, E, F, temp;
1252 unsigned int hrate, drate, maxyres;
1254 inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
1256 if(sr_data & SIS_INTERLACED_MODE)
1257 var->vmode = FB_VMODE_INTERLACED;
1259 var->vmode = FB_VMODE_NONINTERLACED;
1261 switch((sr_data & 0x1C) >> 2) {
1262 case SIS_8BPP_COLOR_MODE:
1263 var->bits_per_pixel = 8;
1265 case SIS_16BPP_COLOR_MODE:
1266 var->bits_per_pixel = 16;
1268 case SIS_32BPP_COLOR_MODE:
1269 var->bits_per_pixel = 32;
1273 sisfb_bpp_to_var(ivideo, var);
1275 inSISIDXREG(SISSR, 0x0A, sr_data);
1276 inSISIDXREG(SISCR, 0x06, cr_data);
1277 inSISIDXREG(SISCR, 0x07, cr_data2);
1279 VT = (cr_data & 0xFF) |
1280 ((u16) (cr_data2 & 0x01) << 8) |
1281 ((u16) (cr_data2 & 0x20) << 4) |
1282 ((u16) (sr_data & 0x01) << 10);
1285 inSISIDXREG(SISCR, 0x12, cr_data);
1287 VDE = (cr_data & 0xff) |
1288 ((u16) (cr_data2 & 0x02) << 7) |
1289 ((u16) (cr_data2 & 0x40) << 3) |
1290 ((u16) (sr_data & 0x02) << 9);
1293 inSISIDXREG(SISCR, 0x10, cr_data);
1295 VRS = (cr_data & 0xff) |
1296 ((u16) (cr_data2 & 0x04) << 6) |
1297 ((u16) (cr_data2 & 0x80) << 2) |
1298 ((u16) (sr_data & 0x08) << 7);
1301 inSISIDXREG(SISCR, 0x15, cr_data);
1302 inSISIDXREG(SISCR, 0x09, cr_data3);
1304 if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE;
1306 VBS = (cr_data & 0xff) |
1307 ((u16) (cr_data2 & 0x08) << 5) |
1308 ((u16) (cr_data3 & 0x20) << 4) |
1309 ((u16) (sr_data & 0x04) << 8);
1311 inSISIDXREG(SISCR, 0x16, cr_data);
1313 VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
1314 temp = VBE - ((E - 1) & 511);
1315 B = (temp > 0) ? temp : (temp + 512);
1317 inSISIDXREG(SISCR, 0x11, cr_data);
1319 VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
1320 temp = VRE - ((E + F - 1) & 31);
1321 C = (temp > 0) ? temp : (temp + 32);
1326 var->upper_margin = D;
1327 var->lower_margin = F;
1330 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1332 var->upper_margin <<= 1;
1333 var->lower_margin <<= 1;
1334 var->vsync_len <<= 1;
1335 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1337 var->upper_margin >>= 1;
1338 var->lower_margin >>= 1;
1339 var->vsync_len >>= 1;
1342 inSISIDXREG(SISSR, 0x0b, sr_data);
1343 inSISIDXREG(SISCR, 0x00, cr_data);
1345 HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
1348 inSISIDXREG(SISCR, 0x01, cr_data);
1350 HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
1353 inSISIDXREG(SISCR, 0x04, cr_data);
1355 HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
1358 inSISIDXREG(SISCR, 0x02, cr_data);
1360 HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
1362 inSISIDXREG(SISSR, 0x0c, sr_data);
1363 inSISIDXREG(SISCR, 0x03, cr_data);
1364 inSISIDXREG(SISCR, 0x05, cr_data2);
1366 HBE = (cr_data & 0x1f) |
1367 ((u16) (cr_data2 & 0x80) >> 2) |
1368 ((u16) (sr_data & 0x03) << 6);
1369 HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
1371 temp = HBE - ((E - 1) & 255);
1372 B = (temp > 0) ? temp : (temp + 256);
1374 temp = HRE - ((E + F + 3) & 63);
1375 C = (temp > 0) ? temp : (temp + 64);
1380 if(var->xres_virtual < var->xres) {
1381 var->xres_virtual = var->xres;
1384 if((var->xres == 320) &&
1385 (var->yres == 200 || var->yres == 240)) {
1386 /* Terrible hack, but the correct CRTC data for
1387 * these modes only produces a black screen...
1389 var->left_margin = (400 - 376);
1390 var->right_margin = (328 - 320);
1391 var->hsync_len = (376 - 328);
1393 var->left_margin = D * 8;
1394 var->right_margin = F * 8;
1395 var->hsync_len = C * 8;
1397 var->activate = FB_ACTIVATE_NOW;
1401 mr_data = inSISREG(SISMISCR);
1403 var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
1405 var->sync |= FB_SYNC_VERT_HIGH_ACT;
1408 var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
1410 var->sync |= FB_SYNC_HOR_HIGH_ACT;
1416 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1419 hrate = ivideo->refresh_rate * VT / 2;
1420 drate = (hrate * HT) / 1000;
1421 var->pixclock = (u32) (1000000000 / drate);
1423 if(ivideo->sisfb_ypan) {
1424 maxyres = sisfb_calc_maxyres(ivideo, var);
1425 if(ivideo->sisfb_max) {
1426 var->yres_virtual = maxyres;
1428 if(var->yres_virtual > maxyres) {
1429 var->yres_virtual = maxyres;
1432 if(var->yres_virtual <= var->yres) {
1433 var->yres_virtual = var->yres;
1436 var->yres_virtual = var->yres;
1442 sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
1443 unsigned *transp, struct fb_info *info)
1445 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1447 if(regno >= ivideo->video_cmap_len) return 1;
1449 *red = ivideo->sis_palette[regno].red;
1450 *green = ivideo->sis_palette[regno].green;
1451 *blue = ivideo->sis_palette[regno].blue;
1458 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1459 unsigned transp, struct fb_info *info)
1461 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1463 if(regno >= ivideo->video_cmap_len) return 1;
1465 ivideo->sis_palette[regno].red = red;
1466 ivideo->sis_palette[regno].green = green;
1467 ivideo->sis_palette[regno].blue = blue;
1469 switch(ivideo->video_bpp) {
1470 #ifdef FBCON_HAS_CFB8
1472 outSISREG(SISDACA, regno);
1473 outSISREG(SISDACD, (red >> 10));
1474 outSISREG(SISDACD, (green >> 10));
1475 outSISREG(SISDACD, (blue >> 10));
1476 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1477 outSISREG(SISDAC2A, regno);
1478 outSISREG(SISDAC2D, (red >> 8));
1479 outSISREG(SISDAC2D, (green >> 8));
1480 outSISREG(SISDAC2D, (blue >> 8));
1484 #ifdef FBCON_HAS_CFB16
1486 ivideo->sis_fbcon_cmap.cfb16[regno] =
1487 ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1490 #ifdef FBCON_HAS_CFB32
1495 ivideo->sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
1504 sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info)
1506 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1507 struct display *display;
1508 struct display_switch *sw;
1509 struct fb_fix_screeninfo fix;
1512 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1514 sisfb_get_fix(&fix, con, info);
1516 display->var = *var;
1517 display->screen_base = (char *)ivideo->video_vbase;
1518 display->visual = fix.visual;
1519 display->type = fix.type;
1520 display->type_aux = fix.type_aux;
1521 display->ypanstep = fix.ypanstep;
1522 display->ywrapstep = fix.ywrapstep;
1523 display->line_length = fix.line_length;
1524 display->can_soft_blank = 1;
1525 display->inverse = ivideo->sisfb_inverse;
1526 display->next_line = fix.line_length;
1530 switch(ivideo->video_bpp) {
1531 #ifdef FBCON_HAS_CFB8
1532 case 8: sw = ivideo->accel ? &fbcon_sis8 : &fbcon_cfb8;
1535 #ifdef FBCON_HAS_CFB16
1536 case 16:sw = ivideo->accel ? &fbcon_sis16 : &fbcon_cfb16;
1537 display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb16;
1540 #ifdef FBCON_HAS_CFB32
1541 case 32:sw = ivideo->accel ? &fbcon_sis32 : &fbcon_cfb32;
1542 display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb32;
1545 default:sw = &fbcon_dummy;
1548 memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw));
1549 display->dispsw = &ivideo->sisfb_sw;
1551 restore_flags(flags);
1553 if(ivideo->sisfb_ypan) {
1554 /* display->scrollmode = 0; */
1556 display->scrollmode = SCROLL_YREDRAW;
1557 ivideo->sisfb_sw.bmove = fbcon_redraw_bmove;
1562 sisfb_do_install_cmap(int con, struct fb_info *info)
1564 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1566 if(con != ivideo->currcon) return;
1568 if(fb_display[con].cmap.len) {
1569 fb_set_cmap(&fb_display[con].cmap, sisfb_setcolreg, info);
1571 int size = sisfb_get_cmap_len(&fb_display[con].var);
1572 fb_set_cmap(fb_default_cmap(size), sisfb_setcolreg, info);
1577 sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1579 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1582 memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo));
1584 *var = fb_display[con].var;
1587 if(ivideo->sisfb_fstn) {
1588 if(var->xres == 320 && var->yres == 480) var->yres = 240;
1595 sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1597 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1600 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1602 if(sisfb_do_set_var(var, con == ivideo->currcon, info)) {
1603 sisfb_crtc_to_var(ivideo, var);
1607 sisfb_crtc_to_var(ivideo, var);
1609 sisfb_set_disp(con, var, info);
1611 if(info->changevar) {
1612 (*info->changevar)(con);
1615 if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) {
1619 sisfb_do_install_cmap(con, info);
1621 #if 0 /* Why was this called here? */
1622 unsigned int cols, rows;
1623 cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
1624 rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
1625 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1631 sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1633 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1634 struct display *display;
1636 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1638 if(con == ivideo->currcon) {
1640 return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
1642 } else if(display->cmap.len) {
1644 fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2);
1648 int size = sisfb_get_cmap_len(&display->var);
1649 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
1657 sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1659 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1660 struct display *display;
1663 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1665 size = sisfb_get_cmap_len(&display->var);
1666 if(display->cmap.len != size) {
1667 err = fb_alloc_cmap(&display->cmap, size, 0);
1671 if(con == ivideo->currcon) {
1672 return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
1674 fb_copy_cmap(cmap, &display->cmap, kspc ? 0 : 1);
1681 sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info)
1683 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1686 if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
1688 if((var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual) ||
1689 (var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)) {
1693 if(con == ivideo->currcon) {
1694 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
1697 fb_display[con].var.xoffset = var->xoffset;
1698 fb_display[con].var.yoffset = var->yoffset;
1704 sisfb_update_var(int con, struct fb_info *info)
1706 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1708 return(sisfb_pan_var(ivideo, &fb_display[con].var));
1712 sisfb_switch(int con, struct fb_info *info)
1714 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1717 if(fb_display[ivideo->currcon].cmap.len) {
1718 fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info);
1721 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1723 if(!memcmp(&fb_display[con].var, &fb_display[ivideo->currcon].var,
1724 sizeof(struct fb_var_screeninfo))) {
1725 ivideo->currcon = con;
1729 ivideo->currcon = con;
1731 sisfb_do_set_var(&fb_display[con].var, 1, info);
1733 sisfb_set_disp(con, &fb_display[con].var, info);
1735 sisfb_do_install_cmap(con, info);
1737 cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
1738 rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
1739 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1741 sisfb_update_var(con, info);
1747 sisfb_blank(int blank, struct fb_info *info)
1749 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1751 sisfb_myblank(ivideo, blank);
1755 /* ------------ FBDev related routines for 2.6 series ----------- */
1757 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1760 sisfb_open(struct fb_info *info, int user)
1766 sisfb_release(struct fb_info *info, int user)
1772 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1773 unsigned transp, struct fb_info *info)
1775 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1777 if(regno >= sisfb_get_cmap_len(&info->var)) return 1;
1779 switch(info->var.bits_per_pixel) {
1781 outSISREG(SISDACA, regno);
1782 outSISREG(SISDACD, (red >> 10));
1783 outSISREG(SISDACD, (green >> 10));
1784 outSISREG(SISDACD, (blue >> 10));
1785 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1786 outSISREG(SISDAC2A, regno);
1787 outSISREG(SISDAC2D, (red >> 8));
1788 outSISREG(SISDAC2D, (green >> 8));
1789 outSISREG(SISDAC2D, (blue >> 8));
1793 ((u32 *)(info->pseudo_palette))[regno] =
1794 ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1800 ((u32 *)(info->pseudo_palette))[regno] =
1801 (red << 16) | (green << 8) | (blue);
1808 sisfb_set_par(struct fb_info *info)
1812 if((err = sisfb_do_set_var(&info->var, 1, info))) {
1816 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1817 sisfb_get_fix(&info->fix, info->currcon, info);
1819 sisfb_get_fix(&info->fix, -1, info);
1825 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1827 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1828 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1829 unsigned int drate = 0, hrate = 0, maxyres;
1831 int refresh_rate, search_idx;
1832 BOOLEAN recalc_clock = FALSE;
1835 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1837 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1839 pixclock = var->pixclock;
1841 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1842 vtotal += var->yres;
1844 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1845 vtotal += var->yres;
1847 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1848 vtotal += var->yres;
1850 } else vtotal += var->yres;
1852 if(!(htotal) || !(vtotal)) {
1853 SISFAIL("sisfb: no valid timing data");
1857 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1858 (sisbios_mode[search_idx].xres <= var->xres) ) {
1859 if( (sisbios_mode[search_idx].xres == var->xres) &&
1860 (sisbios_mode[search_idx].yres == var->yres) &&
1861 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1862 if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) {
1872 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1873 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1874 (var->yres <= sisbios_mode[search_idx].yres) &&
1875 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1876 if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) {
1884 printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1885 var->xres, var->yres, var->bits_per_pixel,
1886 sisbios_mode[search_idx].xres,
1887 sisbios_mode[search_idx].yres,
1888 var->bits_per_pixel);
1889 var->xres = sisbios_mode[search_idx].xres;
1890 var->yres = sisbios_mode[search_idx].yres;
1894 printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n",
1895 var->xres, var->yres, var->bits_per_pixel);
1900 if( ((ivideo->vbflags & VB_LVDS) || /* Slave modes on LVDS and 301B-DH */
1901 ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1902 (var->bits_per_pixel == 8) ) {
1904 recalc_clock = TRUE;
1905 } else if( (ivideo->current_htotal == htotal) && /* x=x & y=y & c=c -> assume depth change */
1906 (ivideo->current_vtotal == vtotal) &&
1907 (ivideo->current_pixclock == pixclock) ) {
1908 drate = 1000000000 / pixclock;
1909 hrate = (drate * 1000) / htotal;
1910 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1911 } else if( ( (ivideo->current_htotal != htotal) || /* x!=x | y!=y & c=c -> invalid pixclock */
1912 (ivideo->current_vtotal != vtotal) ) &&
1913 (ivideo->current_pixclock == var->pixclock) ) {
1914 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1915 refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1916 } else if(ivideo->sisfb_parm_rate != -1) {
1917 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1918 refresh_rate = ivideo->sisfb_parm_rate;
1922 recalc_clock = TRUE;
1923 } else if((pixclock) && (htotal) && (vtotal)) {
1924 drate = 1000000000 / pixclock;
1925 hrate = (drate * 1000) / htotal;
1926 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1927 } else if(ivideo->current_refresh_rate) {
1928 refresh_rate = ivideo->current_refresh_rate;
1929 recalc_clock = TRUE;
1932 recalc_clock = TRUE;
1935 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1937 /* Eventually recalculate timing and clock */
1939 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1940 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1942 sisbios_mode[search_idx].mode_no[ivideo->mni],
1944 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
1945 sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex, var);
1946 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1947 var->pixclock <<= 1;
1951 if(ivideo->sisfb_thismonitor.datavalid) {
1952 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1953 myrateindex, refresh_rate)) {
1954 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1958 /* Adapt RGB settings */
1959 sisfb_bpp_to_var(ivideo, var);
1961 /* Sanity check for offsets */
1962 if(var->xoffset < 0) var->xoffset = 0;
1963 if(var->yoffset < 0) var->yoffset = 0;
1965 if(var->xres > var->xres_virtual) {
1966 var->xres_virtual = var->xres;
1969 if(ivideo->sisfb_ypan) {
1970 maxyres = sisfb_calc_maxyres(ivideo, var);
1971 if(ivideo->sisfb_max) {
1972 var->yres_virtual = maxyres;
1974 if(var->yres_virtual > maxyres) {
1975 var->yres_virtual = maxyres;
1978 if(var->yres_virtual <= var->yres) {
1979 var->yres_virtual = var->yres;
1982 if(var->yres != var->yres_virtual) {
1983 var->yres_virtual = var->yres;
1989 /* Truncate offsets to maximum if too high */
1990 if(var->xoffset > var->xres_virtual - var->xres) {
1991 var->xoffset = var->xres_virtual - var->xres - 1;
1994 if(var->yoffset > var->yres_virtual - var->yres) {
1995 var->yoffset = var->yres_virtual - var->yres - 1;
1998 /* Set everything else to 0 */
1999 var->red.msb_right =
2000 var->green.msb_right =
2001 var->blue.msb_right =
2002 var->transp.offset =
2003 var->transp.length =
2004 var->transp.msb_right = 0;
2010 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
2012 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2015 if(var->xoffset > (var->xres_virtual - var->xres)) {
2018 if(var->yoffset > (var->yres_virtual - var->yres)) {
2022 if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
2024 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
2025 var->yoffset + info->var.yres > info->var.yres_virtual) {
2029 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
2031 info->var.xoffset = var->xoffset;
2032 info->var.yoffset = var->yoffset;
2038 sisfb_blank(int blank, struct fb_info *info)
2040 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2042 return(sisfb_myblank(ivideo, blank));
2047 /* ----------- FBDev related routines for all series ---------- */
2050 sisfb_ioctl(struct inode *inode, struct file *file,
2051 unsigned int cmd, unsigned long arg,
2052 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2055 struct fb_info *info)
2057 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2058 struct sis_memreq sismemreq;
2059 struct fb_vblank sisvbblank;
2062 static int count = 0;
2063 u32 __user *argp = (u32 __user *) arg;
2067 if(!capable(CAP_SYS_RAWIO)) {
2070 if(copy_from_user(&sismemreq, argp, sizeof(sismemreq))) {
2073 sis_malloc(&sismemreq);
2074 if(copy_to_user(argp, &sismemreq, sizeof(sismemreq))) {
2075 sis_free((u32)sismemreq.offset);
2081 if(!capable(CAP_SYS_RAWIO)) {
2084 if(get_user(gpu32, argp)) {
2090 case FBIOGET_VBLANK:
2091 sisvbblank.count = 0;
2092 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
2093 if(copy_to_user(argp, &sisvbblank, sizeof(sisvbblank))) {
2098 case SISFB_GET_INFO_SIZE:
2099 return put_user(sizeof(sisfb_info), argp);
2101 case SISFB_GET_INFO_OLD:
2103 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2105 case SISFB_GET_INFO: /* For communication with X driver */
2106 x.sisfb_id = SISFB_ID;
2107 x.sisfb_version = VER_MAJOR;
2108 x.sisfb_revision = VER_MINOR;
2109 x.sisfb_patchlevel = VER_LEVEL;
2110 x.chip_id = ivideo->chip_id;
2111 x.memory = ivideo->video_size / 1024;
2112 x.heapstart = ivideo->heapstart / 1024;
2113 if(ivideo->modechanged) {
2114 x.fbvidmode = ivideo->mode_no;
2116 x.fbvidmode = ivideo->modeprechange;
2118 x.sisfb_caps = ivideo->caps;
2119 x.sisfb_tqlen = 512; /* yet fixed */
2120 x.sisfb_pcibus = ivideo->pcibus;
2121 x.sisfb_pcislot = ivideo->pcislot;
2122 x.sisfb_pcifunc = ivideo->pcifunc;
2123 x.sisfb_lcdpdc = ivideo->detectedpdc;
2124 x.sisfb_lcdpdca = ivideo->detectedpdca;
2125 x.sisfb_lcda = ivideo->detectedlcda;
2126 x.sisfb_vbflags = ivideo->vbflags;
2127 x.sisfb_currentvbflags = ivideo->currentvbflags;
2128 x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
2129 x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
2130 x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
2131 x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
2132 x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
2133 x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
2134 x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
2135 x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
2136 x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
2137 x.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
2139 if(copy_to_user(argp, &x, sizeof(x))) {
2144 case SISFB_GET_VBRSTATUS_OLD:
2146 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2148 case SISFB_GET_VBRSTATUS:
2149 if(sisfb_CheckVBRetrace(ivideo)) {
2150 return put_user((u32)1, argp);
2152 return put_user((u32)0, argp);
2155 case SISFB_GET_AUTOMAXIMIZE_OLD:
2157 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2159 case SISFB_GET_AUTOMAXIMIZE:
2160 if(ivideo->sisfb_max) return put_user((u32)1, argp);
2161 else return put_user((u32)0, argp);
2163 case SISFB_SET_AUTOMAXIMIZE_OLD:
2165 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2167 case SISFB_SET_AUTOMAXIMIZE:
2168 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2171 ivideo->sisfb_max = (gpu32) ? 1 : 0;
2174 case SISFB_SET_TVPOSOFFSET:
2175 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2178 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
2179 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
2182 case SISFB_GET_TVPOSOFFSET:
2183 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)), argp);
2185 case SISFB_SET_LOCK:
2186 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2189 ivideo->sisfblocked = (gpu32) ? 1 : 0;
2199 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
2201 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2203 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2205 strcpy(fix->id, ivideo->myid);
2207 fix->smem_start = ivideo->video_base;
2208 fix->smem_len = ivideo->sisfb_mem;
2209 fix->type = FB_TYPE_PACKED_PIXELS;
2211 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
2213 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
2215 fix->line_length = ivideo->video_linelength;
2216 fix->mmio_start = ivideo->mmio_base;
2217 fix->mmio_len = ivideo->mmio_size;
2218 if(ivideo->sisvga_engine == SIS_300_VGA) {
2219 fix->accel = FB_ACCEL_SIS_GLAMOUR;
2220 } else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) {
2221 fix->accel = FB_ACCEL_SIS_XABRE;
2223 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
2229 /* ---------------- fb_ops structures ----------------- */
2231 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2232 static struct fb_ops sisfb_ops = {
2233 .owner = THIS_MODULE,
2234 .fb_get_fix = sisfb_get_fix,
2235 .fb_get_var = sisfb_get_var,
2236 .fb_set_var = sisfb_set_var,
2237 .fb_get_cmap = sisfb_get_cmap,
2238 .fb_set_cmap = sisfb_set_cmap,
2239 .fb_pan_display = sisfb_pan_display,
2240 .fb_ioctl = sisfb_ioctl
2244 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
2245 static struct fb_ops sisfb_ops = {
2246 .owner = THIS_MODULE,
2247 .fb_open = sisfb_open,
2248 .fb_release = sisfb_release,
2249 .fb_check_var = sisfb_check_var,
2250 .fb_set_par = sisfb_set_par,
2251 .fb_setcolreg = sisfb_setcolreg,
2252 .fb_pan_display = sisfb_pan_display,
2253 .fb_blank = sisfb_blank,
2254 .fb_fillrect = fbcon_sis_fillrect,
2255 .fb_copyarea = fbcon_sis_copyarea,
2256 .fb_imageblit = cfb_imageblit,
2257 .fb_cursor = soft_cursor,
2258 .fb_sync = fbcon_sis_sync,
2259 .fb_ioctl = sisfb_ioctl
2263 /* ---------------- Chip generation dependent routines ---------------- */
2265 static struct pci_dev * sisfb_get_northbridge(int basechipid)
2267 struct pci_dev *pdev = NULL;
2268 int nbridgenum, nbridgeidx, i;
2269 const unsigned short nbridgeids[] = {
2270 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2271 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2272 PCI_DEVICE_ID_SI_730,
2273 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2274 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2275 PCI_DEVICE_ID_SI_651,
2276 PCI_DEVICE_ID_SI_740,
2277 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760 VGA */
2278 PCI_DEVICE_ID_SI_741,
2279 PCI_DEVICE_ID_SI_660,
2280 PCI_DEVICE_ID_SI_760
2283 switch(basechipid) {
2284 #ifdef CONFIG_FB_SIS_300
2285 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2286 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2288 #ifdef CONFIG_FB_SIS_315
2289 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2290 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
2291 case SIS_660: nbridgeidx = 7; nbridgenum = 4; break;
2293 default: return NULL;
2295 for(i = 0; i < nbridgenum; i++) {
2296 if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break;
2301 static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
2303 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2307 ivideo->video_size = 0;
2309 switch(ivideo->chip) {
2310 #ifdef CONFIG_FB_SIS_300
2312 inSISIDXREG(SISSR, 0x14, reg);
2313 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2318 if(!ivideo->nbridge) return -1;
2319 pci_read_config_byte(ivideo->nbridge, 0x63, ®);
2320 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2323 #ifdef CONFIG_FB_SIS_315
2327 inSISIDXREG(SISSR, 0x14, reg);
2328 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2329 switch((reg >> 2) & 0x03) {
2332 ivideo->video_size <<= 1;
2335 ivideo->video_size += (ivideo->video_size/2);
2339 inSISIDXREG(SISSR, 0x14, reg);
2340 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2341 if(reg & 0x0c) ivideo->video_size <<= 1;
2346 inSISIDXREG(SISSR, 0x14, reg);
2347 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2351 inSISIDXREG(SISCR, 0x79, reg);
2352 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2356 inSISIDXREG(SISCR, 0x79, reg);
2357 reg = (reg & 0xf0) >> 4;
2358 if(reg) ivideo->video_size = (1 << reg) << 20;
2359 inSISIDXREG(SISCR, 0x78, reg);
2362 if(reg == 0x10) ivideo->video_size += (32 << 20);
2363 else ivideo->video_size += (64 << 20);
2373 /* -------------- video bridge device detection --------------- */
2375 static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2379 #ifdef CONFIG_FB_SIS_300
2380 if(ivideo->sisvga_engine == SIS_300_VGA) {
2381 inSISIDXREG(SISSR, 0x17, temp);
2382 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2383 /* PAL/NTSC is stored on SR16 on such machines */
2384 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2385 inSISIDXREG(SISSR, 0x16, temp);
2387 ivideo->vbflags |= TV_PAL;
2389 ivideo->vbflags |= TV_NTSC;
2395 inSISIDXREG(SISCR, 0x32, cr32);
2397 if(cr32 & SIS_CRT1) {
2398 ivideo->sisfb_crt1off = 0;
2400 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2403 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2405 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2406 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2407 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2409 /* Check given parms for hardware compatibility.
2410 * (Cannot do this in the search_xx routines since we don't
2411 * know what hardware we are running on then)
2414 if(ivideo->chip != SIS_550) {
2415 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2418 if(ivideo->sisfb_tvplug != -1) {
2419 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2420 (!(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) ) {
2421 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2422 ivideo->sisfb_tvplug = -1;
2423 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2427 if(ivideo->sisfb_tvplug != -1) {
2428 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2429 (!(ivideo->vbflags & (VB_301|VB_301B|VB_302B))) ) {
2430 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2431 ivideo->sisfb_tvplug = -1;
2432 printk(KERN_ERR "sisfb: HiVision not supported\n");
2436 if(ivideo->sisfb_tvstd != -1) {
2437 if( (!(ivideo->vbflags & VB_SISBRIDGE)) &&
2438 (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags & VB_CHRONTEL))) ) {
2439 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2440 ivideo->sisfb_tvstd = -1;
2441 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2446 /* Detect/set TV plug & type */
2447 if(ivideo->sisfb_tvplug != -1) {
2448 ivideo->vbflags |= ivideo->sisfb_tvplug;
2450 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2451 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2452 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2454 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2455 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2459 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2460 if(ivideo->sisfb_tvstd != -1) {
2461 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2462 ivideo->vbflags |= ivideo->sisfb_tvstd;
2464 if(ivideo->vbflags & TV_SCART) {
2465 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2466 ivideo->vbflags |= TV_PAL;
2468 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2469 if(ivideo->sisvga_engine == SIS_300_VGA) {
2470 inSISIDXREG(SISSR, 0x38, temp);
2471 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2472 else ivideo->vbflags |= TV_NTSC;
2473 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2474 inSISIDXREG(SISSR, 0x38, temp);
2475 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2476 else ivideo->vbflags |= TV_NTSC;
2478 inSISIDXREG(SISCR, 0x79, temp);
2479 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2480 else ivideo->vbflags |= TV_NTSC;
2485 /* Copy forceCRT1 option to CRT1off if option is given */
2486 if(ivideo->sisfb_forcecrt1 != -1) {
2487 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2491 static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo)
2493 char stdstr[] = "sisfb: Detected";
2494 char bridgestr[] = "video bridge";
2498 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2501 inSISIDXREG(SISPART4, 0x01, reg);
2503 ivideo->vbflags |= VB_301;
2504 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2505 } else if(reg < 0xc0) {
2506 ivideo->vbflags |= VB_301B;
2507 inSISIDXREG(SISPART4,0x23,reg);
2509 ivideo->vbflags |= VB_30xBDH;
2510 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2512 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2514 } else if(reg < 0xd0) {
2515 ivideo->vbflags |= VB_301C;
2516 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2517 } else if(reg < 0xe0) {
2518 ivideo->vbflags |= VB_301LV;
2519 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2520 } else if(reg <= 0xe1) {
2521 inSISIDXREG(SISPART4,0x39,reg);
2523 ivideo->vbflags |= VB_302LV;
2524 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2526 ivideo->vbflags |= VB_301C;
2527 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2529 ivideo->vbflags |= VB_302ELV;
2530 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2536 ivideo->vbflags |= VB_302B;
2537 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2541 if((!(ivideo->vbflags & VB_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2542 inSISIDXREG(SISCR, 0x37, reg);
2543 reg &= SIS_EXTERNAL_CHIP_MASK;
2545 if(ivideo->sisvga_engine == SIS_300_VGA) {
2546 #ifdef CONFIG_FB_SIS_300
2548 case SIS_EXTERNAL_CHIP_LVDS:
2549 ivideo->vbflags |= VB_LVDS;
2551 case SIS_EXTERNAL_CHIP_TRUMPION:
2552 ivideo->vbflags |= VB_TRUMPION;
2554 case SIS_EXTERNAL_CHIP_CHRONTEL:
2555 ivideo->vbflags |= VB_CHRONTEL;
2557 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2558 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2561 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 1;
2563 } else if(ivideo->chip < SIS_661) {
2564 #ifdef CONFIG_FB_SIS_315
2566 case SIS310_EXTERNAL_CHIP_LVDS:
2567 ivideo->vbflags |= VB_LVDS;
2569 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2570 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2573 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2575 } else if(ivideo->chip >= SIS_661) {
2576 #ifdef CONFIG_FB_SIS_315
2577 inSISIDXREG(SISCR, 0x38, reg);
2581 ivideo->vbflags |= VB_LVDS;
2584 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2587 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);
2590 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2593 if(ivideo->vbflags & VB_LVDS) {
2594 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2596 if(ivideo->vbflags & VB_TRUMPION) {
2597 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2599 if(ivideo->vbflags & VB_CHRONTEL) {
2600 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2602 if(ivideo->vbflags & VB_CONEXANT) {
2603 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2607 if(ivideo->vbflags & VB_SISBRIDGE) {
2608 SiS_Sense30x(ivideo);
2609 } else if(ivideo->vbflags & VB_CHRONTEL) {
2610 SiS_SenseCh(ivideo);
2614 /* ------------------ Sensing routines ------------------ */
2616 static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo)
2621 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2623 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2625 return (count == -1) ? FALSE : TRUE;
2628 static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
2630 BOOLEAN mustwait = FALSE;
2632 #ifdef CONFIG_FB_SIS_315
2638 inSISIDXREG(SISSR,0x1F,SR1F);
2639 orSISIDXREG(SISSR,0x1F,0x04);
2640 andSISIDXREG(SISSR,0x1F,0x3F);
2641 if(SR1F & 0xc0) mustwait = TRUE;
2643 #ifdef CONFIG_FB_SIS_315
2644 if(ivideo->sisvga_engine == SIS_315_VGA) {
2645 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,CR63);
2647 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2651 inSISIDXREG(SISCR,0x17,CR17);
2654 orSISIDXREG(SISCR,0x17,0x80);
2656 outSISIDXREG(SISSR, 0x00, 0x01);
2657 outSISIDXREG(SISSR, 0x00, 0x03);
2661 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2664 #ifdef CONFIG_FB_SIS_315
2665 if(ivideo->chip >= SIS_330) {
2666 andSISIDXREG(SISCR,0x32,~0x20);
2667 if(ivideo->chip >= SIS_340) {
2668 outSISIDXREG(SISCR, 0x57, 0x4a);
2670 outSISIDXREG(SISCR, 0x57, 0x5f);
2672 orSISIDXREG(SISCR, 0x53, 0x02);
2673 while((inSISREG(SISINPSTAT)) & 0x01) break;
2674 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2675 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2676 andSISIDXREG(SISCR, 0x53, 0xfd);
2677 andSISIDXREG(SISCR, 0x57, 0x00);
2681 if(temp == 0xffff) {
2684 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, 0, 0, NULL);
2685 } while(((temp == 0) || (temp == 0xffff)) && i--);
2687 if((temp == 0) || (temp == 0xffff)) {
2688 if(sisfb_test_DDC1(ivideo)) temp = 1;
2692 if((temp) && (temp != 0xffff)) {
2693 orSISIDXREG(SISCR,0x32,0x20);
2696 #ifdef CONFIG_FB_SIS_315
2697 if(ivideo->sisvga_engine == SIS_315_VGA) {
2698 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,CR63);
2702 setSISIDXREG(SISCR,0x17,0x7F,CR17);
2704 outSISIDXREG(SISSR,0x1F,SR1F);
2707 /* Determine and detect attached devices on SiS30x */
2708 static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2710 int temp, mytest, result, i, j;
2712 for(j = 0; j < 10; j++) {
2714 for(i = 0; i < 3; i++) {
2716 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2717 temp = (type >> 8) | (mytest & 0x00ff);
2718 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2719 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2722 inSISIDXREG(SISPART4,0x03,temp);
2725 if(temp == mytest) result++;
2727 outSISIDXREG(SISPART4,0x11,0x00);
2728 andSISIDXREG(SISPART4,0x10,0xe0);
2729 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2732 if((result == 0) || (result >= 2)) break;
2737 static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
2739 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2740 u16 svhs=0, svhs_c=0;
2741 u16 cvbs=0, cvbs_c=0;
2742 u16 vga2=0, vga2_c=0;
2744 char stdstr[] = "sisfb: Detected";
2745 char tvstr[] = "TV connected to";
2747 if(ivideo->vbflags & VB_301) {
2748 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2749 inSISIDXREG(SISPART4,0x01,myflag);
2751 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2753 } else if(ivideo->vbflags & (VB_301B | VB_302B)) {
2754 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2755 } else if(ivideo->vbflags & (VB_301LV | VB_302LV)) {
2756 svhs = 0x0200; cvbs = 0x0100;
2757 } else if(ivideo->vbflags & (VB_301C | VB_302ELV)) {
2758 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2761 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2762 if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
2763 svhs_c = 0x0408; cvbs_c = 0x0808;
2767 if(ivideo->chip == SIS_300) {
2768 inSISIDXREG(SISSR,0x3b,myflag);
2769 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2772 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2773 orSISIDXREG(SISSR,0x1e,0x20);
2775 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2776 if(ivideo->vbflags & VB_301C) {
2777 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2779 orSISIDXREG(SISPART4,0x0d,0x04);
2781 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2783 inSISIDXREG(SISPART2,0x00,backupP2_00);
2784 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2786 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2787 if(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV)) {
2788 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2791 if(!(ivideo->vbflags & VB_301C)) {
2792 SISDoSense(ivideo, 0, 0);
2795 andSISIDXREG(SISCR, 0x32, ~0x14);
2797 if(vga2_c || vga2) {
2798 if(SISDoSense(ivideo, vga2, vga2_c)) {
2799 if(biosflag & 0x01) {
2800 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2801 orSISIDXREG(SISCR, 0x32, 0x04);
2803 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2804 orSISIDXREG(SISCR, 0x32, 0x10);
2809 andSISIDXREG(SISCR, 0x32, 0x3f);
2811 if(ivideo->vbflags & VB_301C) {
2812 orSISIDXREG(SISPART4,0x0d,0x04);
2815 if((ivideo->sisvga_engine == SIS_315_VGA) &&
2816 (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV))) {
2817 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2818 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2819 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2820 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2821 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2822 orSISIDXREG(SISCR,0x32,0x80);
2825 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2828 andSISIDXREG(SISCR, 0x32, ~0x03);
2830 if(!(ivideo->vbflags & TV_YPBPR)) {
2831 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2832 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2833 orSISIDXREG(SISCR, 0x32, 0x02);
2835 if((biosflag & 0x02) || (!result)) {
2836 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2837 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2838 orSISIDXREG(SISCR, 0x32, 0x01);
2843 SISDoSense(ivideo, 0, 0);
2845 outSISIDXREG(SISPART2,0x00,backupP2_00);
2846 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2847 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2849 if(ivideo->vbflags & VB_301C) {
2850 inSISIDXREG(SISPART2,0x00,biosflag);
2851 if(biosflag & 0x20) {
2852 for(myflag = 2; myflag > 0; myflag--) {
2854 outSISIDXREG(SISPART2,0x00,biosflag);
2859 outSISIDXREG(SISPART2,0x00,backupP2_00);
2862 /* Determine and detect attached TV's on Chrontel */
2863 static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
2865 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2867 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2869 #ifdef CONFIG_FB_SIS_300
2870 unsigned char test[3];
2874 if(ivideo->chip < SIS_315H) {
2876 #ifdef CONFIG_FB_SIS_300
2877 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2878 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2879 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2880 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2881 /* See Chrontel TB31 for explanation */
2882 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2883 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2884 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b0e);
2885 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2887 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2888 if(temp2 != temp1) temp1 = temp2;
2890 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2891 /* Read power status */
2892 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2893 if((temp1 & 0x03) != 0x03) {
2894 /* Power all outputs */
2895 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0B0E);
2896 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2898 /* Sense connected TV devices */
2899 for(i = 0; i < 3; i++) {
2900 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0110);
2901 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2902 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0010);
2903 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2904 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2905 if(!(temp1 & 0x08)) test[i] = 0x02;
2906 else if(!(temp1 & 0x02)) test[i] = 0x01;
2908 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2911 if(test[0] == test[1]) temp1 = test[0];
2912 else if(test[0] == test[2]) temp1 = test[0];
2913 else if(test[1] == test[2]) temp1 = test[1];
2916 "sisfb: TV detection unreliable - test results varied\n");
2920 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2921 ivideo->vbflags |= TV_SVIDEO;
2922 orSISIDXREG(SISCR, 0x32, 0x02);
2923 andSISIDXREG(SISCR, 0x32, ~0x05);
2924 } else if (temp1 == 0x01) {
2925 printk(KERN_INFO "%s CVBS output\n", stdstr);
2926 ivideo->vbflags |= TV_AVIDEO;
2927 orSISIDXREG(SISCR, 0x32, 0x01);
2928 andSISIDXREG(SISCR, 0x32, ~0x06);
2930 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2931 andSISIDXREG(SISCR, 0x32, ~0x07);
2933 } else if(temp1 == 0) {
2934 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2935 andSISIDXREG(SISCR, 0x32, ~0x07);
2937 /* Set general purpose IO for Chrontel communication */
2938 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2943 #ifdef CONFIG_FB_SIS_315
2944 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2945 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2946 SiS_SetCH701x(&ivideo->SiS_Pr, 0x2049);
2947 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2948 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2950 SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2951 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2953 SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2954 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2955 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2956 SiS_SetCH701x(&ivideo->SiS_Pr, (temp1 << 8) | 0x49);
2958 if(temp2 & 0x02) temp1 |= 0x01;
2959 if(temp2 & 0x10) temp1 |= 0x01;
2960 if(temp2 & 0x04) temp1 |= 0x02;
2961 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2964 printk(KERN_INFO "%s CVBS output\n", stdstr);
2965 ivideo->vbflags |= TV_AVIDEO;
2966 orSISIDXREG(SISCR, 0x32, 0x01);
2967 andSISIDXREG(SISCR, 0x32, ~0x06);
2970 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2971 ivideo->vbflags |= TV_SVIDEO;
2972 orSISIDXREG(SISCR, 0x32, 0x02);
2973 andSISIDXREG(SISCR, 0x32, ~0x05);
2976 printk(KERN_INFO "%s SCART output\n", stdstr);
2977 orSISIDXREG(SISCR, 0x32, 0x04);
2978 andSISIDXREG(SISCR, 0x32, ~0x03);
2981 andSISIDXREG(SISCR, 0x32, ~0x07);
2987 /* ------------------------ Heap routines -------------------------- */
2989 static u32 __devinit
2990 sisfb_getheapstart(struct sis_video_info *ivideo)
2992 u32 ret = ivideo->sisfb_parm_mem * 1024;
2993 u32 max = ivideo->video_size - ivideo->hwcursor_size;
2996 /* Calculate heap start = end of memory for console
2998 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
2999 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3001 * Basically given by "mem" parameter
3003 * maximum = videosize - cmd_queue - hwcursor
3004 * (results in a heap of size 0)
3005 * default = SiS 300: depends on videosize
3006 * SiS 315/330: 32k below max
3009 if(ivideo->sisvga_engine == SIS_300_VGA) {
3010 max -= TURBO_QUEUE_AREA_SIZE;
3011 if(ivideo->video_size > 0x1000000) {
3013 } else if(ivideo->video_size > 0x800000) {
3019 max -= COMMAND_QUEUE_AREA_SIZE;
3023 if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) {
3030 static int __devinit
3031 sisfb_heap_init(struct sis_video_info *ivideo)
3035 ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo);
3037 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3038 ivideo->sisfb_heap_end = ivideo->video_vbase + ivideo->video_size;
3040 /* Initialize command queue (We use MMIO only) */
3042 #ifdef CONFIG_FB_SIS_315
3043 if(ivideo->sisvga_engine == SIS_315_VGA) {
3047 ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
3049 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
3050 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3052 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3053 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3055 temp = SIS_CMD_QUEUE_SIZE_512k;
3056 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3057 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3059 tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE);
3060 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3062 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3066 #ifdef CONFIG_FB_SIS_300
3067 if(ivideo->sisvga_engine == SIS_300_VGA) {
3068 unsigned long tqueue_pos;
3071 ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
3073 tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
3075 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3078 tq_state |= (u8)(tqueue_pos >> 8);
3079 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3081 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
3083 ivideo->caps |= TURBO_QUEUE_CAP;
3087 /* Reserve memory for the HWCursor */
3088 ivideo->sisfb_heap_end -= ivideo->hwcursor_size;
3089 ivideo->hwcursor_vbase = ivideo->sisfb_heap_end;
3090 ivideo->caps |= HW_CURSOR_CAP;
3092 ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start;
3094 if(ivideo->cardnumber == 0) {
3096 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3097 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3099 sisfb_heap.vinfo = ivideo;
3101 sisfb_heap.poha_chain = NULL;
3102 sisfb_heap.poh_freelist = NULL;
3104 poh = sisfb_poh_new_node();
3105 if(poh == NULL) return 1;
3107 poh->poh_next = &sisfb_heap.oh_free;
3108 poh->poh_prev = &sisfb_heap.oh_free;
3109 poh->size = ivideo->sisfb_heap_size;
3110 poh->offset = ivideo->heapstart;
3112 sisfb_heap.oh_free.poh_next = poh;
3113 sisfb_heap.oh_free.poh_prev = poh;
3114 sisfb_heap.oh_free.size = 0;
3115 sisfb_heap.max_freesize = poh->size;
3117 sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
3118 sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
3119 sisfb_heap.oh_used.size = SENTINEL;
3123 printk(KERN_INFO "Skipped heap initialization for secondary cards\n");
3131 sisfb_poh_new_node(void)
3138 if(sisfb_heap.poh_freelist == NULL) {
3139 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3140 if(!poha) return NULL;
3142 poha->poha_next = sisfb_heap.poha_chain;
3143 sisfb_heap.poha_chain = poha;
3145 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
3147 poh = &poha->aoh[0];
3148 for(i = cOhs - 1; i != 0; i--) {
3149 poh->poh_next = poh + 1;
3153 poh->poh_next = NULL;
3154 sisfb_heap.poh_freelist = &poha->aoh[0];
3157 poh = sisfb_heap.poh_freelist;
3158 sisfb_heap.poh_freelist = poh->poh_next;
3164 sisfb_poh_allocate(u32 size)
3170 if(size > sisfb_heap.max_freesize) {
3171 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3172 (unsigned int) size / 1024);
3176 pohThis = sisfb_heap.oh_free.poh_next;
3178 while(pohThis != &sisfb_heap.oh_free) {
3179 if (size <= pohThis->size) {
3183 pohThis = pohThis->poh_next;
3187 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3188 (unsigned int) size / 1024);
3192 if(size == pohThis->size) {
3194 sisfb_delete_node(pohThis);
3196 pohRoot = sisfb_poh_new_node();
3198 if(pohRoot == NULL) {
3202 pohRoot->offset = pohThis->offset;
3203 pohRoot->size = size;
3205 pohThis->offset += size;
3206 pohThis->size -= size;
3209 sisfb_heap.max_freesize -= size;
3211 pohThis = &sisfb_heap.oh_used;
3212 sisfb_insert_node(pohThis, pohRoot);
3218 sisfb_delete_node(SIS_OH *poh)
3223 poh_prev = poh->poh_prev;
3224 poh_next = poh->poh_next;
3226 poh_prev->poh_next = poh_next;
3227 poh_next->poh_prev = poh_prev;
3231 sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
3235 pohTemp = pohList->poh_next;
3237 pohList->poh_next = poh;
3238 pohTemp->poh_prev = poh;
3240 poh->poh_prev = pohList;
3241 poh->poh_next = pohTemp;
3245 sisfb_poh_free(u32 base)
3255 poh_freed = sisfb_heap.oh_used.poh_next;
3257 while(poh_freed != &sisfb_heap.oh_used) {
3258 if(poh_freed->offset == base) {
3263 poh_freed = poh_freed->poh_next;
3266 if(!foundNode) return(NULL);
3268 sisfb_heap.max_freesize += poh_freed->size;
3270 poh_prev = poh_next = NULL;
3271 ulUpper = poh_freed->offset + poh_freed->size;
3272 ulLower = poh_freed->offset;
3274 pohThis = sisfb_heap.oh_free.poh_next;
3276 while(pohThis != &sisfb_heap.oh_free) {
3277 if(pohThis->offset == ulUpper) {
3279 } else if((pohThis->offset + pohThis->size) == ulLower) {
3282 pohThis = pohThis->poh_next;
3285 sisfb_delete_node(poh_freed);
3287 if(poh_prev && poh_next) {
3288 poh_prev->size += (poh_freed->size + poh_next->size);
3289 sisfb_delete_node(poh_next);
3290 sisfb_free_node(poh_freed);
3291 sisfb_free_node(poh_next);
3296 poh_prev->size += poh_freed->size;
3297 sisfb_free_node(poh_freed);
3302 poh_next->size += poh_freed->size;
3303 poh_next->offset = poh_freed->offset;
3304 sisfb_free_node(poh_freed);
3308 sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
3314 sisfb_free_node(SIS_OH *poh)
3316 if(poh == NULL) return;
3318 poh->poh_next = sisfb_heap.poh_freelist;
3319 sisfb_heap.poh_freelist = poh;
3323 sis_malloc(struct sis_memreq *req)
3325 struct sis_video_info *ivideo = sisfb_heap.vinfo;
3328 if((ivideo) && (!ivideo->havenoheap)) {
3329 poh = sisfb_poh_allocate((u32)req->size);
3333 req->offset = req->size = 0;
3334 DPRINTK("sisfb: Video RAM allocation failed\n");
3336 req->offset = poh->offset;
3337 req->size = poh->size;
3338 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3339 (poh->offset + ivideo->video_vbase));
3343 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3348 struct sis_video_info *ivideo = sisfb_heap.vinfo;
3351 if((!ivideo) || (ivideo->havenoheap)) return;
3353 poh = sisfb_poh_free((u32)base);
3356 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3357 (unsigned int) base);
3361 /* --------------------- SetMode routines ------------------------- */
3364 sisfb_pre_setmode(struct sis_video_info *ivideo)
3366 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3369 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3371 inSISIDXREG(SISCR, 0x31, cr31);
3375 cr33 = ivideo->rate_idx & 0x0F;
3377 #ifdef CONFIG_FB_SIS_315
3378 if(ivideo->sisvga_engine == SIS_315_VGA) {
3379 if(ivideo->chip >= SIS_661) {
3380 inSISIDXREG(SISCR, 0x38, cr38);
3381 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3384 inSISIDXREG(SISCR, tvregnum, cr38);
3385 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3389 #ifdef CONFIG_FB_SIS_300
3390 if(ivideo->sisvga_engine == SIS_300_VGA) {
3392 inSISIDXREG(SISCR, tvregnum, cr38);
3396 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3397 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3399 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3402 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3403 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) {
3404 #ifdef CONFIG_FB_SIS_315
3405 if(ivideo->chip >= SIS_661) {
3407 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3408 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3409 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3410 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3412 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3413 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3414 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3416 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3417 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3418 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3420 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3423 } else if((ivideo->vbflags & TV_HIVISION) && (ivideo->vbflags & (VB_301|VB_301B|VB_302B))) {
3424 if(ivideo->chip >= SIS_661) {
3430 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3433 ivideo->currentvbflags |= TV_HIVISION;
3434 } else if(ivideo->vbflags & TV_SCART) {
3435 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3438 ivideo->currentvbflags |= TV_SCART;
3440 if(ivideo->vbflags & TV_SVIDEO) {
3441 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3442 ivideo->currentvbflags |= TV_SVIDEO;
3444 if(ivideo->vbflags & TV_AVIDEO) {
3445 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3446 ivideo->currentvbflags |= TV_AVIDEO;
3449 cr31 |= SIS_DRIVER_MODE;
3451 if(ivideo->vbflags & (TV_AVIDEO|TV_SVIDEO)) {
3452 if(ivideo->vbflags & TV_PAL) {
3453 cr31 |= 0x01; cr35 |= 0x01;
3454 ivideo->currentvbflags |= TV_PAL;
3455 if(ivideo->vbflags & TV_PALM) {
3456 cr38 |= 0x40; cr35 |= 0x04;
3457 ivideo->currentvbflags |= TV_PALM;
3458 } else if(ivideo->vbflags & TV_PALN) {
3459 cr38 |= 0x80; cr35 |= 0x08;
3460 ivideo->currentvbflags |= TV_PALN;
3463 cr31 &= ~0x01; cr35 &= ~0x01;
3464 ivideo->currentvbflags |= TV_NTSC;
3465 if(ivideo->vbflags & TV_NTSCJ) {
3466 cr38 |= 0x40; cr35 |= 0x02;
3467 ivideo->currentvbflags |= TV_NTSCJ;
3474 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3475 cr31 |= SIS_DRIVER_MODE;
3476 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3477 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3481 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3482 cr31 |= SIS_DRIVER_MODE;
3483 if(ivideo->sisfb_nocrt2rate) {
3484 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3486 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3490 default: /* disable CRT2 */
3492 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3495 outSISIDXREG(SISCR, 0x30, cr30);
3496 outSISIDXREG(SISCR, 0x33, cr33);
3498 if(ivideo->chip >= SIS_661) {
3499 #ifdef CONFIG_FB_SIS_315
3500 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3501 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3502 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3503 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3505 } else if(ivideo->chip != SIS_300) {
3506 outSISIDXREG(SISCR, tvregnum, cr38);
3508 outSISIDXREG(SISCR, 0x31, cr31);
3510 if(ivideo->accel) sisfb_syncaccel(ivideo);
3512 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3515 /* Fix SR11 for 661 and later */
3516 #ifdef CONFIG_FB_SIS_315
3518 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3522 if(ivideo->chip >= SIS_661) {
3523 inSISIDXREG(SISSR,0x11,tmpreg);
3525 inSISIDXREG(SISSR,0x3e,tmpreg);
3526 tmpreg = (tmpreg + 1) & 0xff;
3527 outSISIDXREG(SISSR,0x3e,tmpreg);
3528 inSISIDXREG(SISSR,0x11,tmpreg);
3531 andSISIDXREG(SISSR,0x11,0x0f);
3537 static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3539 if(val > 32) val = 32;
3540 if(val < -32) val = -32;
3541 ivideo->tvxpos = val;
3543 if(ivideo->sisfblocked) return;
3544 if(!ivideo->modechanged) return;
3546 if(ivideo->currentvbflags & CRT2_TV) {
3548 if(ivideo->vbflags & VB_CHRONTEL) {
3550 int x = ivideo->tvx;
3552 switch(ivideo->chronteltype) {
3556 outSISIDXREG(SISSR,0x05,0x86);
3557 SiS_SetCH700x(&ivideo->SiS_Pr, (((x & 0xff) << 8) | 0x0a));
3558 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD);
3561 /* Not supported by hardware */
3565 } else if(ivideo->vbflags & VB_SISBRIDGE) {
3567 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3568 unsigned short temp;
3570 p2_1f = ivideo->p2_1f;
3571 p2_20 = ivideo->p2_20;
3572 p2_2b = ivideo->p2_2b;
3573 p2_42 = ivideo->p2_42;
3574 p2_43 = ivideo->p2_43;
3576 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3578 p2_1f = temp & 0xff;
3579 p2_20 = (temp & 0xf00) >> 4;
3580 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3581 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3583 p2_43 = temp & 0xff;
3584 p2_42 = (temp & 0xf00) >> 4;
3585 outSISIDXREG(SISPART2,0x1f,p2_1f);
3586 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3587 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3588 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3589 outSISIDXREG(SISPART2,0x43,p2_43);
3594 static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3596 if(val > 32) val = 32;
3597 if(val < -32) val = -32;
3598 ivideo->tvypos = val;
3600 if(ivideo->sisfblocked) return;
3601 if(!ivideo->modechanged) return;
3603 if(ivideo->currentvbflags & CRT2_TV) {
3605 if(ivideo->vbflags & VB_CHRONTEL) {
3607 int y = ivideo->tvy;
3609 switch(ivideo->chronteltype) {
3613 outSISIDXREG(SISSR,0x05,0x86);
3614 SiS_SetCH700x(&ivideo->SiS_Pr, (((y & 0xff) << 8) | 0x0b));
3615 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, ((y & 0x0100) | 0x08),0xFE);
3618 /* Not supported by hardware */
3622 } else if(ivideo->vbflags & VB_SISBRIDGE) {
3626 p2_01 = ivideo->p2_01;
3627 p2_02 = ivideo->p2_02;
3631 while((p2_01 <= 0) || (p2_02 <= 0)) {
3635 outSISIDXREG(SISPART2,0x01,p2_01);
3636 outSISIDXREG(SISPART2,0x02,p2_02);
3642 sisfb_post_setmode(struct sis_video_info *ivideo)
3644 BOOLEAN crt1isoff = FALSE;
3645 BOOLEAN doit = TRUE;
3646 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3649 #ifdef CONFIG_FB_SIS_315
3653 outSISIDXREG(SISSR,0x05,0x86);
3655 #ifdef CONFIG_FB_SIS_315
3656 sisfb_fixup_SR11(ivideo);
3659 /* Now we actually HAVE changed the display mode */
3660 ivideo->modechanged = 1;
3662 /* We can't switch off CRT1 if bridge is in slave mode */
3663 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
3664 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3665 } else ivideo->sisfb_crt1off = 0;
3667 #ifdef CONFIG_FB_SIS_300
3668 if(ivideo->sisvga_engine == SIS_300_VGA) {
3669 if((ivideo->sisfb_crt1off) && (doit)) {
3676 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3679 #ifdef CONFIG_FB_SIS_315
3680 if(ivideo->sisvga_engine == SIS_315_VGA) {
3681 if((ivideo->sisfb_crt1off) && (doit)) {
3691 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3692 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3697 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3698 ivideo->currentvbflags |= VB_SINGLE_MODE;
3700 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3701 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3702 ivideo->currentvbflags |= VB_MIRROR_MODE;
3704 ivideo->currentvbflags |= VB_SINGLE_MODE;
3708 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3710 if(ivideo->currentvbflags & CRT2_TV) {
3711 if(ivideo->vbflags & VB_SISBRIDGE) {
3712 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3713 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3714 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3715 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3716 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3717 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3718 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3719 } else if(ivideo->vbflags & VB_CHRONTEL) {
3720 if(ivideo->chronteltype == 1) {
3721 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3722 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3723 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3724 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3729 if(ivideo->tvxpos) {
3730 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3732 if(ivideo->tvypos) {
3733 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3736 if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) { /* Set filter for SiS301 */
3738 unsigned char filter_tb = 0;
3740 switch (ivideo->video_width) {
3742 filter_tb = (ivideo->vbflags & TV_NTSC) ? 4 : 12;
3745 filter_tb = (ivideo->vbflags & TV_NTSC) ? 5 : 13;
3748 filter_tb = (ivideo->vbflags & TV_NTSC) ? 6 : 14;
3752 filter_tb = (ivideo->vbflags & TV_NTSC) ? 7 : 15;
3755 ivideo->sisfb_filter = -1;
3759 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
3761 if(ivideo->vbflags & TV_NTSC) {
3763 andSISIDXREG(SISPART2, 0x3a, 0x1f);
3765 if (ivideo->vbflags & TV_SVIDEO) {
3767 andSISIDXREG(SISPART2, 0x30, 0xdf);
3769 } else if (ivideo->vbflags & TV_AVIDEO) {
3771 orSISIDXREG(SISPART2, 0x30, 0x20);
3773 switch (ivideo->video_width) {
3775 outSISIDXREG(SISPART2, 0x35, 0xEB);
3776 outSISIDXREG(SISPART2, 0x36, 0x04);
3777 outSISIDXREG(SISPART2, 0x37, 0x25);
3778 outSISIDXREG(SISPART2, 0x38, 0x18);
3781 outSISIDXREG(SISPART2, 0x35, 0xEE);
3782 outSISIDXREG(SISPART2, 0x36, 0x0C);
3783 outSISIDXREG(SISPART2, 0x37, 0x22);
3784 outSISIDXREG(SISPART2, 0x38, 0x08);
3788 outSISIDXREG(SISPART2, 0x35, 0xEB);
3789 outSISIDXREG(SISPART2, 0x36, 0x15);
3790 outSISIDXREG(SISPART2, 0x37, 0x25);
3791 outSISIDXREG(SISPART2, 0x38, 0xF6);
3796 } else if(ivideo->vbflags & TV_PAL) {
3798 andSISIDXREG(SISPART2, 0x3A, 0x1F);
3800 if (ivideo->vbflags & TV_SVIDEO) {
3802 andSISIDXREG(SISPART2, 0x30, 0xDF);
3804 } else if (ivideo->vbflags & TV_AVIDEO) {
3806 orSISIDXREG(SISPART2, 0x30, 0x20);
3808 switch (ivideo->video_width) {
3810 outSISIDXREG(SISPART2, 0x35, 0xF1);
3811 outSISIDXREG(SISPART2, 0x36, 0xF7);
3812 outSISIDXREG(SISPART2, 0x37, 0x1F);
3813 outSISIDXREG(SISPART2, 0x38, 0x32);
3816 outSISIDXREG(SISPART2, 0x35, 0xF3);
3817 outSISIDXREG(SISPART2, 0x36, 0x00);
3818 outSISIDXREG(SISPART2, 0x37, 0x1D);
3819 outSISIDXREG(SISPART2, 0x38, 0x20);
3823 outSISIDXREG(SISPART2, 0x35, 0xFC);
3824 outSISIDXREG(SISPART2, 0x36, 0xFB);
3825 outSISIDXREG(SISPART2, 0x37, 0x14);
3826 outSISIDXREG(SISPART2, 0x38, 0x2A);
3832 if((ivideo->sisfb_filter >= 0) && (ivideo->sisfb_filter <= 7)) {
3833 outSISIDXREG(SISPART2,0x35,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][0]));
3834 outSISIDXREG(SISPART2,0x36,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][1]));
3835 outSISIDXREG(SISPART2,0x37,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][2]));
3836 outSISIDXREG(SISPART2,0x38,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][3]));
3843 int __init sisfb_setup(char *options)
3847 sisfb_setdefaultparms();
3849 printk(KERN_DEBUG "sisfb: Options %s\n", options);
3851 if(!options || !(*options)) {
3855 while((this_opt = strsep(&options, ",")) != NULL) {
3857 if(!(*this_opt)) continue;
3859 if(!strnicmp(this_opt, "off", 3)) {
3861 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3862 /* Need to check crt2 type first for fstn/dstn */
3863 sisfb_search_crt2type(this_opt + 14);
3864 } else if(!strnicmp(this_opt, "tvmode:",7)) {
3865 sisfb_search_tvstd(this_opt + 7);
3866 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3867 sisfb_search_tvstd(this_opt + 7);
3868 } else if(!strnicmp(this_opt, "mode:", 5)) {
3869 sisfb_search_mode(this_opt + 5, FALSE);
3870 } else if(!strnicmp(this_opt, "vesa:", 5)) {
3871 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
3872 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
3873 } else if(!strnicmp(this_opt, "inverse", 7)) {
3875 /* fb_invert_cmaps(); */
3876 } else if(!strnicmp(this_opt, "font:", 5)) {
3877 if(strlen(this_opt + 5) < 40) {
3878 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
3879 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
3882 } else if(!strnicmp(this_opt, "rate:", 5)) {
3883 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
3884 } else if(!strnicmp(this_opt, "filter:", 7)) {
3885 sisfb_filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
3886 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3887 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
3888 } else if(!strnicmp(this_opt, "mem:",4)) {
3889 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
3890 } else if(!strnicmp(this_opt, "pdc:", 4)) {
3891 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
3892 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
3893 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
3894 } else if(!strnicmp(this_opt, "noaccel", 7)) {
3896 } else if(!strnicmp(this_opt, "accel", 5)) {
3898 } else if(!strnicmp(this_opt, "noypan", 6)) {
3900 } else if(!strnicmp(this_opt, "ypan", 4)) {
3902 } else if(!strnicmp(this_opt, "nomax", 5)) {
3904 } else if(!strnicmp(this_opt, "max", 3)) {
3906 } else if(!strnicmp(this_opt, "userom:", 7)) {
3907 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
3908 } else if(!strnicmp(this_opt, "useoem:", 7)) {
3909 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
3910 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
3911 sisfb_nocrt2rate = 1;
3912 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
3913 unsigned long temp = 2;
3914 temp = simple_strtoul(this_opt + 9, NULL, 0);
3915 if((temp == 0) || (temp == 1)) {
3916 sisfb_scalelcd = temp ^ 1;
3918 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
3920 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3921 if((temp >= -32) && (temp <= 32)) {
3922 sisfb_tvxposoffset = temp;
3924 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
3926 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3927 if((temp >= -32) && (temp <= 32)) {
3928 sisfb_tvyposoffset = temp;
3930 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
3931 sisfb_search_specialtiming(this_opt + 14);
3932 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
3934 temp = simple_strtoul(this_opt + 7, NULL, 0);
3935 if((temp >= 0) && (temp <= 3)) {
3936 sisfb_lvdshl = temp;
3938 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
3939 sisfb_search_mode(this_opt, TRUE);
3940 #if !defined(__i386__) && !defined(__x86_64__)
3941 } else if(!strnicmp(this_opt, "resetcard", 9)) {
3942 sisfb_resetcard = 1;
3943 } else if(!strnicmp(this_opt, "videoram:", 9)) {
3944 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
3947 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
3958 static void __iomem * __devinit sis_find_rom(struct pci_dev *pdev)
3960 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3962 #if defined(__i386__) || defined(__x86_64__)
3964 void __iomem *rom_base, *rom;
3966 unsigned short pciid;
3968 for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
3970 rom_base = ioremap(segstart, 0x10000);
3971 if(!rom_base) continue;
3973 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) {
3978 romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
3979 if(romptr > (0x10000 - 8)) {
3984 rom = rom_base + romptr;
3986 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
3987 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) {
3992 pciid = readb(rom + 4) | (readb(rom + 5) << 8);
3993 if(pciid != 0x1039) {
3998 pciid = readb(rom + 6) | (readb(rom + 7) << 8);
3999 if(pciid == ivideo->chip_id) return rom_base;
4004 void __iomem *rom_base, *rom, *myrombase = NULL;
4006 unsigned short pciid;
4009 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &backup);
4010 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4011 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4013 rom_base = ioremap(ivideo->video_base, 65536);
4015 if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) {
4016 romptr = (u16)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4017 if(romptr <= (0x10000 - 8)) {
4018 rom = rom_base + romptr;
4019 if((readb(rom) == 'P') && (readb(rom + 1) == 'C') &&
4020 (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) {
4021 pciid = readb(rom + 4) | (readb(rom + 5) << 8);
4022 if(pciid == 0x1039) {
4023 pciid = readb(rom + 6) | (readb(rom + 7) << 8);
4024 if(pciid == ivideo->chip_id) {
4025 if((myrombase = vmalloc(65536))) {
4026 memcpy_fromio(myrombase, rom_base, 65536);
4035 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, backup);
4036 if(myrombase) return myrombase;
4041 #ifdef CONFIG_FB_SIS_300
4042 static int __devinit
4043 sisfb_chkbuswidth300(struct pci_dev *pdev, void __iomem *FBAddress)
4045 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4050 andSISIDXREG(SISSR,0x15,0xFB);
4051 orSISIDXREG(SISSR,0x15,0x04);
4052 outSISIDXREG(SISSR,0x13,0x00);
4053 outSISIDXREG(SISSR,0x14,0xBF);
4055 for(i=0; i<2; i++) {
4057 for(j=0; j<4; j++) {
4058 writew(temp, FBAddress);
4059 if(readw(FBAddress) == temp) break;
4060 orSISIDXREG(SISSR,0x3c,0x01);
4061 inSISIDXREG(SISSR,0x05,reg);
4062 inSISIDXREG(SISSR,0x05,reg);
4063 andSISIDXREG(SISSR,0x3c,0xfe);
4064 inSISIDXREG(SISSR,0x05,reg);
4065 inSISIDXREG(SISSR,0x05,reg);
4070 writel(0x01234567L, FBAddress);
4071 writel(0x456789ABL, (FBAddress+4));
4072 writel(0x89ABCDEFL, (FBAddress+8));
4073 writel(0xCDEF0123L, (FBAddress+12));
4074 inSISIDXREG(SISSR,0x3b,reg);
4076 if(readl((FBAddress+12)) == 0xCDEF0123L) return(4); /* Channel A 128bit */
4078 if(readl((FBAddress+4)) == 0x456789ABL) return(2); /* Channel B 64bit */
4079 return(1); /* 32bit */
4082 static void __devinit
4083 sisfb_setramsize300(struct pci_dev *pdev)
4085 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4086 void __iomem *FBAddr = ivideo->sishw_ext.pjVideoMemoryAddress, *Addr;
4087 USHORT SR13, SR14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0;
4088 int PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
4089 int RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
4090 int PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k;
4091 const USHORT SiS_DRAMType[17][5] = {
4092 {0x0C,0x0A,0x02,0x40,0x39},
4093 {0x0D,0x0A,0x01,0x40,0x48},
4094 {0x0C,0x09,0x02,0x20,0x35},
4095 {0x0D,0x09,0x01,0x20,0x44},
4096 {0x0C,0x08,0x02,0x10,0x31},
4097 {0x0D,0x08,0x01,0x10,0x40},
4098 {0x0C,0x0A,0x01,0x20,0x34},
4099 {0x0C,0x09,0x01,0x08,0x32},
4100 {0x0B,0x08,0x02,0x08,0x21},
4101 {0x0C,0x08,0x01,0x08,0x30},
4102 {0x0A,0x08,0x02,0x04,0x11},
4103 {0x0B,0x0A,0x01,0x10,0x28},
4104 {0x09,0x08,0x02,0x02,0x01},
4105 {0x0B,0x09,0x01,0x08,0x24},
4106 {0x0B,0x08,0x01,0x04,0x20},
4107 {0x0A,0x08,0x01,0x02,0x10},
4108 {0x09,0x08,0x01,0x01,0x00}
4111 buswidth = sisfb_chkbuswidth300(pdev, FBAddr);
4115 for(i = 6; i >= 0; i--) {
4117 PseudoRankCapacity = 1 << i;
4118 for(j = 4; j >= 1; j--) {
4120 PseudoTotalCapacity = PseudoRankCapacity * j;
4121 PseudoAdrPinCount = 15 - j;
4122 if(PseudoTotalCapacity <= 64) {
4123 for(k = 0; k <= 16; k++) {
4125 RankCapacity = buswidth * SiS_DRAMType[k][3];
4126 AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
4127 if(RankCapacity == PseudoRankCapacity)
4128 if(AdrPinCount <= PseudoAdrPinCount) {
4129 if(j == 3) { /* Rank No */
4130 BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
4131 BankNumMid = RankCapacity * MB2Bank * 1 - 1;
4133 BankNumHigh = RankCapacity * MB2Bank * j - 1;
4134 BankNumMid = RankCapacity * MB2Bank * j / 2 - 1;
4136 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4137 PhysicalAdrHigh = BankNumHigh;
4138 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4139 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4141 andSISIDXREG(SISSR,0x15,0xFB); /* Test */
4142 orSISIDXREG(SISSR,0x15,0x04); /* Test */
4143 TotalCapacity = SiS_DRAMType[k][3] * buswidth;
4144 SR13 = SiS_DRAMType[k][4];
4145 if(buswidth == 4) SR14 = (TotalCapacity - 1) | 0x80;
4146 if(buswidth == 2) SR14 = (TotalCapacity - 1) | 0x40;
4147 if(buswidth == 1) SR14 = (TotalCapacity - 1) | 0x00;
4148 outSISIDXREG(SISSR,0x13,SR13);
4149 outSISIDXREG(SISSR,0x14,SR14);
4150 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4151 /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */
4152 writew(((USHORT)PhysicalAdrHigh), Addr);
4153 Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh;
4154 /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */
4155 writew(((USHORT)BankNumMid), Addr);
4156 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage;
4157 /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */
4158 writew(((USHORT)PhysicalAdrHalfPage), Addr);
4159 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage;
4160 /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */
4161 writew(((USHORT)PhysicalAdrOtherPage), Addr);
4163 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4164 data = readw(Addr); /* *((USHORT *)(Addr)); */
4165 if(data == PhysicalAdrHigh) Done = 1;
4173 static void __devinit sisfb_post_sis300(struct pci_dev *pdev)
4175 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4176 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4177 u16 index, rindex, memtype = 0;
4179 outSISIDXREG(SISSR,0x05,0x86);
4181 if(ivideo->sishw_ext.UseROM) {
4182 if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80) {
4183 memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4185 inSISIDXREG(SISSR,0x3a,memtype);
4190 if(ivideo->revision_id <= 0x13) {
4191 v1 = 0x44; v2 = 0x42; v3 = 0x80;
4192 v4 = 0x44; v5 = 0x42; v6 = 0x80;
4194 v1 = 0x68; v2 = 0x43; v3 = 0x80; /* Assume 125Mhz MCLK */
4195 v4 = 0x68; v5 = 0x43; v6 = 0x80; /* Assume 125Mhz ECLK */
4196 if(ivideo->sishw_ext.UseROM) {
4197 index = memtype * 5;
4198 rindex = index + 0x54;
4199 v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4200 v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4201 v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4202 rindex = index + 0x7c;
4203 v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4204 v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4205 v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4208 outSISIDXREG(SISSR,0x28,v1);
4209 outSISIDXREG(SISSR,0x29,v2);
4210 outSISIDXREG(SISSR,0x2a,v3);
4211 outSISIDXREG(SISSR,0x2e,v4);
4212 outSISIDXREG(SISSR,0x2f,v5);
4213 outSISIDXREG(SISSR,0x30,v6);
4215 if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0xa4];
4216 outSISIDXREG(SISSR,0x07,v1); /* DAC speed */
4217 outSISIDXREG(SISSR,0x11,0x0f); /* DDC, power save */
4218 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4219 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4220 if(ivideo->sishw_ext.UseROM) {
4222 v1 = ivideo->sishw_ext.pjVirtualRomBase[memtype];
4223 v2 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 8];
4224 v3 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 16];
4225 v4 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 24];
4226 v5 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 32];
4227 v6 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 40];
4228 v7 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 48];
4229 v8 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 56];
4231 if(ivideo->revision_id >= 0x80) v3 &= 0xfd;
4232 outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4233 outSISIDXREG(SISSR,0x16,v2);
4234 outSISIDXREG(SISSR,0x17,v3);
4235 outSISIDXREG(SISSR,0x18,v4);
4236 outSISIDXREG(SISSR,0x19,v5);
4237 outSISIDXREG(SISSR,0x1a,v6);
4238 outSISIDXREG(SISSR,0x1b,v7);
4239 outSISIDXREG(SISSR,0x1c,v8); /* ---- */
4240 andSISIDXREG(SISSR,0x15,0xfb);
4241 orSISIDXREG(SISSR,0x15,0x04);
4242 if(ivideo->sishw_ext.UseROM) {
4243 if(ivideo->sishw_ext.pjVirtualRomBase[0x53] & 0x02) {
4244 orSISIDXREG(SISSR,0x19,0x20);
4247 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4248 if(ivideo->revision_id >= 0x80) v1 |= 0x01;
4249 outSISIDXREG(SISSR,0x1f,v1);
4250 outSISIDXREG(SISSR,0x20,0xa0); /* linear & relocated io */
4251 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4252 if(ivideo->sishw_ext.UseROM) {
4253 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe8];
4254 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe9];
4255 v3 = ivideo->sishw_ext.pjVirtualRomBase[0xea];
4257 outSISIDXREG(SISSR,0x23,v1);
4258 outSISIDXREG(SISSR,0x24,v2);
4259 outSISIDXREG(SISSR,0x25,v3);
4260 outSISIDXREG(SISSR,0x21,0x84);
4261 outSISIDXREG(SISSR,0x22,0x00);
4262 outSISIDXREG(SISCR,0x37,0x00);
4263 orSISIDXREG(SISPART1,0x24,0x01); /* unlock crt2 */
4264 outSISIDXREG(SISPART1,0x00,0x00);
4265 v1 = 0x40; v2 = 0x11;
4266 if(ivideo->sishw_ext.UseROM) {
4267 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xec];
4268 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xeb];
4270 outSISIDXREG(SISPART1,0x02,v1);
4271 if(ivideo->revision_id >= 0x80) v2 &= ~0x01;
4272 inSISIDXREG(SISPART4,0x00,reg);
4273 if((reg == 1) || (reg == 2)) {
4274 outSISIDXREG(SISCR,0x37,0x02);
4275 outSISIDXREG(SISPART2,0x00,0x1c);
4276 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4277 if(ivideo->sishw_ext.UseROM) {
4278 v4 = ivideo->sishw_ext.pjVirtualRomBase[0xf5];
4279 v5 = ivideo->sishw_ext.pjVirtualRomBase[0xf6];
4280 v6 = ivideo->sishw_ext.pjVirtualRomBase[0xf7];
4282 outSISIDXREG(SISPART4,0x0d,v4);
4283 outSISIDXREG(SISPART4,0x0e,v5);
4284 outSISIDXREG(SISPART4,0x10,v6);
4285 outSISIDXREG(SISPART4,0x0f,0x3f);
4286 inSISIDXREG(SISPART4,0x01,reg);
4288 inSISIDXREG(SISPART4,0x23,reg);
4291 outSISIDXREG(SISPART4,0x23,reg);
4296 outSISIDXREG(SISSR,0x32,v2);
4297 andSISIDXREG(SISPART1,0x24,0xfe); /* Lock CRT2 */
4298 inSISIDXREG(SISSR,0x16,reg);
4300 outSISIDXREG(SISCR,0x35,reg);
4301 outSISIDXREG(SISCR,0x83,0x00);
4302 #if !defined(__i386__) && !defined(__x86_64__)
4303 if(sisfb_videoram) {
4304 outSISIDXREG(SISSR,0x13,0x28); /* ? */
4305 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4306 outSISIDXREG(SISSR,0x14,reg);
4309 /* Need to map max FB size for finding out about RAM size */
4310 ivideo->sishw_ext.pjVideoMemoryAddress = ioremap(ivideo->video_base, 0x4000000);
4311 if(ivideo->sishw_ext.pjVideoMemoryAddress) {
4312 sisfb_setramsize300(pdev);
4313 iounmap(ivideo->sishw_ext.pjVideoMemoryAddress);
4315 printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4316 outSISIDXREG(SISSR,0x13,0x28); /* ? */
4317 outSISIDXREG(SISSR,0x14,0x47); /* 8MB, 64bit default */
4319 #if !defined(__i386__) && !defined(__x86_64__)
4322 if(ivideo->sishw_ext.UseROM) {
4323 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe6];
4324 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe7];
4326 inSISIDXREG(SISSR,0x3a,reg);
4327 if((reg & 0x30) == 0x30) {
4328 v1 = 0x04; /* PCI */
4331 v1 = 0x14; /* AGP */
4335 outSISIDXREG(SISSR,0x21,v1);
4336 outSISIDXREG(SISSR,0x22,v2);
4340 #ifdef CONFIG_FB_SIS_315
4341 static void __devinit sisfb_post_sis315330(struct pci_dev *pdev)
4343 #ifdef YET_TO_BE_DONE
4344 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4345 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4346 u16 index, rindex, memtype = 0;
4347 u32 reg1_32, reg2_32, reg3_32;
4351 /* outSISIDXREG(0x3c4,0x05,0x86); */
4352 outSISIDXREG(SISSR,0x05,0x86);
4354 /* Enable relocated i/o ports */
4355 /* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */
4356 setSISIDXREG(SISSR,0x20,~0x10,0x20);
4359 for(i = 0; i < 0x22; i++) {
4360 outSISIDXREG(SISSR,(0x06 + i),0x00);
4363 if( is 330) v1 = 0x0b;
4364 for(i = 0; i < v1; i++) {
4365 outSISIDXREG(SISSR,(0x31 + i),0x00);
4367 for(i = 0; i < 0x10; i++) {
4368 outSISIDXREG(SISCR,(0x30 + i),0x00);
4372 reg = inSISREG(SISMISCR);
4373 outSISIDXREG(SISSR,0x28,0x81);
4374 outSISIDXREG(SISSR,0x2A,0x00);
4375 outSISIDXREG(SISSR,0x29,0xE1);
4376 outSISREG(SISMISCW,(reg | 0x0c));
4377 outSISIDXREG(SISSR,0x2B,0x81);
4378 outSISIDXREG(SISSR,0x2D,0x00);
4379 outSISIDXREG(SISSR,0x2C,0xE1);
4380 outSISIDXREG(SISSR,0x2E,0x81);
4381 outSISIDXREG(SISSR,0x30,0x00);
4382 outSISIDXREG(SISSR,0x2F,0xE1);
4383 SiS_DDC2Delay(....);
4384 outSISREG(SISMISCW,reg);
4386 /* Get memory type */
4387 if(ivideo->sishw_ext.UseROM) {
4388 if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80)) {
4389 memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4391 inSISIDXREG(SISSR,0x3a,memtype);
4395 if(memtype <= 1) memtype = 0;
4397 inSISIDXREG(SISCR,0x5F,reg);
4400 case 0x00: memtype = 1; break;
4401 case 0x10: memtype = 3; break;
4402 case 0x20: memtype = 3; break;
4403 default: memtype = 2;
4410 v1 = 0x3b; v2 = 0x22; v3 = 0x01; /* Assume 143Mhz MCLK */
4411 v4 = 0x5c; v5 = 0x23; v6 = 0x01; /* Assume 166Mhz ECLK */
4412 if(ivideo->sishw_ext.UseROM) {
4413 index = memtype * 5;
4414 rindex = index + 0x54;
4415 v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4416 v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4417 v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4418 rindex = index + 0x68;
4419 v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4420 v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4421 v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4423 outSISIDXREG(SISSR,0x28,v1);
4424 outSISIDXREG(SISSR,0x29,v2);
4425 outSISIDXREG(SISSR,0x2a,v3);
4427 inSISIDXREG(SISSR,0x3a,reg);
4433 outSISIDXREG(SISSR,0x2e,v4);
4434 outSISIDXREG(SISSR,0x2f,v5);
4435 outSISIDXREG(SISSR,0x30,v6);
4437 /* End of comp with 330 */
4440 if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0x7c];
4441 outSISIDXREG(SISSR,0x07,v1);
4442 outSISIDXREG(SISSR,0x11,0x0f);
4444 v1 = 0x00; v2 = 0x0f; v3 = 0xba; v4 = 0xa9;
4445 v5 = 0xa0; v6 = 0x00; v7 = 0x30;
4446 if(ivideo->sishw_ext.UseROM) {
4447 index = memtype + 0x7d;
4448 v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4449 v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4450 v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4451 v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4452 v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4453 v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
4454 v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
4456 outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0x7d step 4) */
4457 outSISIDXREG(SISSR,0x16,v2);
4458 outSISIDXREG(SISSR,0x17,v3);
4459 outSISIDXREG(SISSR,0x18,v4);
4460 outSISIDXREG(SISSR,0x19,v5);
4461 outSISIDXREG(SISSR,0x1a,v6);
4462 outSISIDXREG(SISSR,0x1b,v7);
4463 outSISIDXREG(SISSR,0x1c,v8); /* ---- */
4465 v1 = 0x77; v2 = 0x77; v3 = 0x00; v4 = 0x5b; v5 = 0x00;
4466 if(ivideo->sishw_ext.UseROM) {
4467 index = memtype + 0xa2;
4468 v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4469 v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4470 v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4471 v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4472 v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4474 outSISIDXREG(SISCR,0x40,v1);
4475 outSISIDXREG(SISCR,0x41,v2);
4476 outSISIDXREG(SISCR,0x42,v3);
4477 outSISIDXREG(SISCR,0x43,v4);
4478 outSISIDXREG(SISCR,0x44,v5);
4483 if(ivideo->sishw_ext.UseROM) {
4484 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4486 outSISIDXREG(SISCR,0x59,v1);
4488 v1 = 0x; v2 = 0x; v3 = 0x; v4 = 0x;
4489 v5 = 0x; v6 = 0x; v7 = 0x; v8 = 0x;
4490 if(ivideo->sishw_ext.UseROM) {
4491 index = memtype + 0xbe;
4492 v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4493 v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4494 v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4495 v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4496 v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4497 v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
4498 v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
4499 v8 = ivideo->sishw_ext.pjVirtualRomBase[index + 28];
4501 outSISIDXREG(SISCR,0x68,v1);
4502 outSISIDXREG(SISCR,0x69,v2);
4503 outSISIDXREG(SISCR,0x6a,v3);
4504 outSISIDXREG(SISCR,0x6b,v4);
4505 outSISIDXREG(SISCR,0x6c,v5);
4506 outSISIDXREG(SISCR,0x6d,v6);
4507 outSISIDXREG(SISCR,0x6e,v7);
4508 outSISIDXREG(SISCR,0x6f,v8);
4511 inSISIDXREG(SISSR,0x3b,reg);
4514 inSISIDXREG(SISCR,0x5F,reg);
4518 outSISIDXREG(SISCR,0x48,v1);
4519 outSISIDXREG(SISCR,0x4c,0x20);
4524 if(ivideo->sishw_ext.UseROM) {
4525 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4527 outSISIDXREG(SISCR,0x59,v1);
4534 outSISIDXREG(SISCR,0x48,0x23);
4536 andSISIDXREG(SISSR,0x16,0x0f);
4538 orSISIDXREG(SISSR,0x16,0x80);
4541 if(ivideo->sishw_ext.UseROM) {
4542 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x81 + memtype];
4544 if(!(v1 & 0x10)) v2 = 0xc0;
4546 orSISIDXREG(SISSR,0x16,v2);
4547 andSISIDXREG(SISSR,0x16,0x0f);
4548 if(!(v1 & 0x10)) v2 = 0x80;
4550 orSISIDXREG(SISSR,0x16,v2);
4554 const u8 sr3cseq1[] = { 0xc0,0xe0,0xf0,0xe0,0xf0,0xa0,0xb0,0xa0,0xb0,0x90,0xd0 };
4555 const u8 sr3cseq2[] = { 0xc0,0xa0,0xb0,0xa0,0xb0,0xe0,0xf0,0xa0,0xb0,0x90,0xd0 };
4556 for(i = 0; i < 11; i++) {
4557 outSISIDXREG(SISSR,0x3c,sr3cseq1[i]);
4559 outSISIDXREG(SISSR,0x3d,0x00);
4560 outSISIDXREG(SISSR,0x3d,0x04);
4561 SiS_DDC2Delay(0x200);
4562 v1 = inSISIDXREG(SISCR,0xEC);
4563 v2 = inSISIDXREG(SISCR,0xED);
4564 reg1_32 = (v2 << 8) | v1;
4565 outSISIDXREG(SISSR,0x3D,0x00);
4566 for(i = 0; i < 11; i++) {
4567 outSISIDXREG(SISSR,0x3c,sr3cseq2[i]);
4569 outSISIDXREG(SISSR,0x3d,0x00);
4570 outSISIDXREG(SISSR,0x3d,0x04);
4571 SiS_DDC2Delay(0x200);
4572 v1 = inSISIDXREG(SISCR,0xEC);
4573 v2 = inSISIDXREG(SISCR,0xED);
4574 reg2_32 = (v2 << 8) | v1;
4575 outSISIDXREG(SISSR,0x3D,0x00);
4576 reg3_32 = reg2_32 << 1;
4580 if(reg3_32 > reg1_32) v1 = 0x10;
4581 outSISIDXREG(SISCR,0x59,v1);
4587 if(ivideo->sishw_ext.UseROM) {
4588 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x99];
4590 outSISIDXREG(SISSR,0x1f,v1);
4592 outSISIDXREG(SISSR,0x20,0x20);
4594 v1 = 0xf6; v2 = 0x0d; v3 = 0x33;
4595 if(ivideo->sishw_ext.UseROM) {
4596 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9c];
4597 v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9d];
4598 v3 = ivideo->sishw_ext.pjVirtualRomBase[0x9e];
4600 outSISIDXREG(SISSR,0x23,v1);
4601 outSISIDXREG(SISSR,0x24,v2);
4602 outSISIDXREG(SISSR,0x25,v3);
4604 outSISIDXREG(SISSR,0x21,0x84);
4605 outSISIDXREG(SISSR,0x22,0x00);
4606 outSISIDXREG(SISSR,0x27,0x1f);
4608 v1 = 0x00; v2 = 0x00;
4609 if(ivideo->sishw_ext.UseROM) {
4610 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9F];
4611 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xA1];
4613 outSISIDXREG(SISSR,0x31,v1);
4614 outSISIDXREG(SISSR,0x33,v2);
4617 if(ivideo->sishw_ext.UseROM) {
4618 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xA0];
4620 v2 = inSISIDXREG(SISPART4,0x00);
4621 if((v2 != 1) && (v2 != 2)) v1 &= 0xef;
4622 outSISIDXREG(SISSR,0x32,v1);
4625 pci_read_config_long(pdev, 0x50, ®1_32);
4629 v1 = 0xAA; v2 = 0x33;
4630 if(ivideo->sishw_ext.UseROM) {
4631 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF7];
4632 v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9E];
4635 v1 = 0x88; v2 = 0x03;
4636 if(ivideo->sishw_ext.UseROM) {
4637 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF8];
4638 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xF6];
4641 outSISIDXREG(SISCR,0x49,v1);
4642 outSISIDXREG(SISSR,0x25,v2);
4644 v1 = inSISIDXREG(SISPART4,0x00);
4645 if((v1 == 1) || (v1 == 2)) {
4646 orSISIDXREG(SISPART1,0x2F,0x01); /* Unlock CRT2 */
4647 outSISIDXREG(SISPART1,0x00,0x00);
4649 if(ivideo->sishw_ext.UseROM) {
4650 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb6];
4652 outSISIDXREG(SISPART1,0x02,v1);
4653 outSISIDXREG(SISPART1,0x2E,0x08);
4654 outSISIDXREG(SISPART2,0x00,0x1c);
4655 v1 = 0x40; v2 = 0x00; v3 = 0x80;
4656 if(ivideo->sishw_ext.UseROM) {
4657 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb7];
4658 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xb8];
4659 v3 = ivideo->sishw_ext.pjVirtualRomBase[0xbb];
4661 outSISIDXREG(SISPART4,0x0d,v1);
4662 outSISIDXREG(SISPART4,0x0e,v2);
4663 outSISIDXREG(SISPART4,0x10,v3);
4664 outSISIDXREG(SISPART4,0x0F,0x3F);
4666 inSISIDXREG(SISPART4,0x01,reg);
4668 inSISIDXREG(SISPART4,0x23,reg);
4671 outSISIDXREG(SISPART4,0x23,reg);
4674 outSISIDXREG(SISCR,0x37,0x02); /* Why? */
4676 outSISIDXREG(SISCR,0x83,0x00);
4677 outSISIDXREG(SISCR,0x90,0x00);
4678 andSISIDXREG(SISSR,0x5B,0xDF);
4679 outSISIDXREG(SISVID,0x00,0x86);
4680 outSISIDXREG(SISVID,0x32,0x00);
4681 outSISIDXREG(SISVID,0x30,0x00);
4682 outSISIDXREG(SISVID,0x32,0x01);
4683 outSISIDXREG(SISVID,0x30,0x00);
4684 orSISIDXREG(SISCR,0x63,0x80);
4690 orSISIDXREG(SISSR,0x16,0x0f);
4691 orSISIDXREG(SISSR,0x18,0xA9);
4692 orSISIDXREG(SISSR,0x19,0xA0);
4693 orSISIDXREG(SISSR,0x1B,0x30);
4694 andSISIDXREG(SISSR,0x17,0xF8);
4695 orSISIDXREG(SISSR,0x19,0x03);
4696 andSIDIDXREG(SISSR,0x13,0x00);
4698 /* Need to map max FB size for finding out about RAM size */
4699 ivideo->sishw_ext.pjVideoMemoryAddress = ioremap(ivideo->video_base, 0x4000000);
4700 if(ivideo->sishw_ext.pjVideoMemoryAddress) {
4701 /* Find out about bus width */
4703 outSISIDXREG(SISSR,0x14,0x02);
4704 andSISIDXREG(SISSR,0x16,0x0F);
4705 orSISIDXREG(SISSR,0x16,0x80);
4715 /* Find out about size */
4718 iounmap(ivideo->sishw_ext.pjVideoMemoryAddress);
4720 printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4721 outSISIDXREG(SISSR,0x14,0x??); /* 8MB, 64bit default */
4724 /* AGP (Missing: Checks for VIA and AMD hosts) */
4725 v1 = 0xA5; v2 = 0xFB;
4726 if(ivideo->sishw_ext.UseROM) {
4727 v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9A];
4728 v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9B];
4730 outSISIDXREG(SISSR,0x21,v1);
4731 outSISIDXREG(SISSR,0x22,v2);
4739 int __devinit sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
4741 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
4742 struct sis_video_info *ivideo = NULL;
4743 struct fb_info *sis_fb_info = NULL;
4746 int sisvga_enabled = 0, i;
4748 if(sisfb_off) return -ENXIO;
4750 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
4751 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
4752 if(!sis_fb_info) return -ENOMEM;
4754 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
4755 if(!sis_fb_info) return -ENOMEM;
4756 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
4757 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
4760 ivideo = (struct sis_video_info *)sis_fb_info->par;
4761 ivideo->memyselfandi = sis_fb_info;
4763 if(card_list == NULL) {
4764 ivideo->cardnumber = 0;
4766 struct sis_video_info *countvideo = card_list;
4767 ivideo->cardnumber = 1;
4768 while ((countvideo = countvideo->next) != NULL) ivideo->cardnumber++;
4771 strncpy(ivideo->myid, chipinfo->chip_name, 30);
4773 ivideo->chip_id = pdev->device;
4774 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
4775 ivideo->sishw_ext.jChipRevision = ivideo->revision_id;
4776 pci_read_config_word(pdev, PCI_COMMAND, ®16);
4777 sisvga_enabled = reg16 & 0x01;
4778 ivideo->pcibus = pdev->bus->number;
4779 ivideo->pcislot = PCI_SLOT(pdev->devfn);
4780 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
4781 ivideo->subsysvendor = pdev->subsystem_vendor;
4782 ivideo->subsysdevice = pdev->subsystem_device;
4783 #ifdef SIS_CONFIG_COMPAT
4784 ivideo->ioctl32registered = 0;
4785 ivideo->ioctl32vblankregistered = 0;
4789 if(sisfb_mode_idx == -1) {
4790 sisfb_get_vga_mode_from_kernel();
4794 ivideo->chip = chipinfo->chip;
4795 ivideo->sisvga_engine = chipinfo->vgaengine;
4796 ivideo->hwcursor_size = chipinfo->hwcursor_size;
4797 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
4798 ivideo->mni = chipinfo->mni;
4800 ivideo->detectedpdc = 0xff;
4801 ivideo->detectedpdca = 0xff;
4802 ivideo->detectedlcda = 0xff;
4804 ivideo->sisfb_thismonitor.datavalid = FALSE;
4806 ivideo->sisfb_parm_mem = sisfb_parm_mem;
4807 ivideo->sisfb_accel = sisfb_accel;
4808 ivideo->sisfb_ypan = sisfb_ypan;
4809 ivideo->sisfb_max = sisfb_max;
4810 ivideo->sisfb_userom = sisfb_userom;
4811 ivideo->sisfb_useoem = sisfb_useoem;
4812 ivideo->sisfb_mode_idx = sisfb_mode_idx;
4813 ivideo->sisfb_parm_rate = sisfb_parm_rate;
4814 ivideo->sisfb_crt1off = sisfb_crt1off;
4815 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
4816 ivideo->sisfb_crt2type = sisfb_crt2type;
4817 ivideo->sisfb_crt2flags = sisfb_crt2flags;
4818 /* pdc(a), scalelcd, special timing, lvdshl handled below */
4819 ivideo->sisfb_dstn = sisfb_dstn;
4820 ivideo->sisfb_fstn = sisfb_fstn;
4821 ivideo->sisfb_tvplug = sisfb_tvplug;
4822 ivideo->sisfb_tvstd = sisfb_tvstd;
4823 ivideo->tvxpos = sisfb_tvxposoffset;
4824 ivideo->tvypos = sisfb_tvyposoffset;
4825 ivideo->sisfb_filter = sisfb_filter;
4826 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
4827 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4828 ivideo->sisfb_inverse = sisfb_inverse;
4831 ivideo->refresh_rate = 0;
4832 if(ivideo->sisfb_parm_rate != -1) {
4833 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
4836 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
4837 ivideo->SiS_Pr.CenterScreen = -1;
4838 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
4839 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
4841 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
4842 ivideo->SiS_Pr.SiS_CHOverScan = -1;
4843 ivideo->SiS_Pr.SiS_ChSW = FALSE;
4844 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
4845 ivideo->SiS_Pr.HaveEMI = FALSE;
4846 ivideo->SiS_Pr.HaveEMILCD = FALSE;
4847 ivideo->SiS_Pr.OverruleEMI = FALSE;
4848 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
4849 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
4850 ivideo->SiS_Pr.PDC = -1;
4851 ivideo->SiS_Pr.PDCA = -1;
4852 #ifdef CONFIG_FB_SIS_315
4853 if(ivideo->chip >= SIS_330) {
4854 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
4855 if(ivideo->chip >= SIS_661) {
4856 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
4861 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
4863 pci_set_drvdata(pdev, ivideo);
4865 /* Patch special cases */
4866 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
4867 switch(ivideo->nbridge->device) {
4868 #ifdef CONFIG_FB_SIS_300
4869 case PCI_DEVICE_ID_SI_730:
4870 ivideo->chip = SIS_730;
4871 strcpy(ivideo->myid, "SiS 730");
4874 #ifdef CONFIG_FB_SIS_315
4875 case PCI_DEVICE_ID_SI_651:
4876 /* ivideo->chip is ok */
4877 strcpy(ivideo->myid, "SiS 651");
4879 case PCI_DEVICE_ID_SI_740:
4880 ivideo->chip = SIS_740;
4881 strcpy(ivideo->myid, "SiS 740");
4883 case PCI_DEVICE_ID_SI_661:
4884 ivideo->chip = SIS_661;
4885 strcpy(ivideo->myid, "SiS 661");
4887 case PCI_DEVICE_ID_SI_741:
4888 ivideo->chip = SIS_741;
4889 strcpy(ivideo->myid, "SiS 741");
4891 case PCI_DEVICE_ID_SI_760:
4892 ivideo->chip = SIS_760;
4893 strcpy(ivideo->myid, "SiS 760");
4899 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4900 strcpy(sis_fb_info->modename, ivideo->myid);
4903 ivideo->sishw_ext.jChipType = ivideo->chip;
4905 #ifdef CONFIG_FB_SIS_315
4906 if((ivideo->sishw_ext.jChipType == SIS_315PRO) ||
4907 (ivideo->sishw_ext.jChipType == SIS_315)) {
4908 ivideo->sishw_ext.jChipType = SIS_315H;
4912 ivideo->video_base = pci_resource_start(pdev, 0);
4913 ivideo->mmio_base = pci_resource_start(pdev, 1);
4914 ivideo->mmio_size = pci_resource_len(pdev, 1);
4915 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
4916 ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
4918 if(!sisvga_enabled) {
4919 if(pci_enable_device(pdev)) {
4920 pci_set_drvdata(pdev, NULL);
4926 SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress);
4928 #ifdef CONFIG_FB_SIS_300
4929 /* Find PCI systems for Chrontel/GPIO communication setup */
4930 if(ivideo->chip == SIS_630) {
4933 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
4934 mychswtable[i].subsysCard == ivideo->subsysdevice) {
4935 ivideo->SiS_Pr.SiS_ChSW = TRUE;
4936 printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
4937 mychswtable[i].vendorName, mychswtable[i].cardName);
4941 } while(mychswtable[i].subsysVendor != 0);
4945 outSISIDXREG(SISSR, 0x05, 0x86);
4947 if( (!sisvga_enabled)
4948 #if !defined(__i386__) && !defined(__x86_64__)
4949 || (sisfb_resetcard)
4952 for(i = 0x30; i <= 0x3f; i++) {
4953 outSISIDXREG(SISCR,i,0x00);
4957 /* Find out about current video mode */
4958 inSISIDXREG(SISCR,0x34,reg);
4960 ivideo->modeprechange = reg & 0x7f;
4962 ivideo->modeprechange = 0x03;
4963 #if defined(__i386__) || defined(__x86_64__)
4965 unsigned char __iomem *tt = ioremap(0, 0x1000);
4967 ivideo->modeprechange = tt[0x449];
4974 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4976 if((reg & 0x80) && (reg != 0xff)) {
4977 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) {
4978 printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
4979 pci_set_drvdata(pdev, NULL);
4987 ivideo->sishw_ext.bIntegratedMMEnabled = TRUE;
4988 #ifdef CONFIG_FB_SIS_300
4989 if(ivideo->sisvga_engine == SIS_300_VGA) {
4990 if(ivideo->chip != SIS_300) {
4991 inSISIDXREG(SISSR, 0x1a, reg);
4993 ivideo->sishw_ext.bIntegratedMMEnabled = FALSE;
4999 ivideo->bios_abase = NULL;
5000 ivideo->bios_vbase = NULL;
5001 if(ivideo->sisfb_userom) {
5002 ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
5003 #if defined(__i386__) || defined(__x86_64__)
5004 ivideo->bios_vbase = ivideo->sishw_ext.pjVirtualRomBase; /* mapped */
5006 ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase; /* allocated */
5008 if(ivideo->sishw_ext.pjVirtualRomBase) {
5009 printk(KERN_INFO "sisfb: Video ROM found and %s to 0x%p\n",
5010 ivideo->bios_vbase ? "mapped" : "copied",
5011 ivideo->sishw_ext.pjVirtualRomBase);
5012 ivideo->sishw_ext.UseROM = TRUE;
5014 ivideo->sishw_ext.UseROM = FALSE;
5015 printk(KERN_INFO "sisfb: Video ROM not found\n");
5018 ivideo->sishw_ext.pjVirtualRomBase = NULL;
5019 ivideo->sishw_ext.UseROM = FALSE;
5020 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
5023 /* Find systems for special custom timing */
5024 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
5026 unsigned char *biosver = NULL;
5027 unsigned char *biosdate = NULL;
5031 if(ivideo->sishw_ext.UseROM) {
5032 biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
5033 biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
5034 for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
5039 if( (mycustomttable[i].chipID == ivideo->chip) &&
5040 ((!strlen(mycustomttable[i].biosversion)) ||
5041 (ivideo->sishw_ext.UseROM &&
5042 (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
5043 ((!strlen(mycustomttable[i].biosdate)) ||
5044 (ivideo->sishw_ext.UseROM &&
5045 (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
5046 ((!mycustomttable[i].bioschksum) ||
5047 (ivideo->sishw_ext.UseROM &&
5048 (mycustomttable[i].bioschksum == chksum))) &&
5049 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
5050 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
5052 for(j = 0; j < 5; j++) {
5053 if(mycustomttable[i].biosFootprintAddr[j]) {
5054 if(ivideo->sishw_ext.UseROM) {
5055 if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
5056 mycustomttable[i].biosFootprintData[j]) {
5059 } else footprint = FALSE;
5063 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
5064 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
5065 mycustomttable[i].vendorName,
5066 mycustomttable[i].cardName);
5067 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
5068 mycustomttable[i].optionName);
5073 } while(mycustomttable[i].chipID);
5076 #ifdef CONFIG_FB_SIS_300
5077 if(ivideo->sisvga_engine == SIS_300_VGA) {
5078 if( (!sisvga_enabled)
5079 #if !defined(__i386__) && !defined(__x86_64__)
5080 || (sisfb_resetcard)
5083 if(ivideo->chip == SIS_300) {
5084 sisfb_post_sis300(pdev);
5090 #ifdef CONFIG_FB_SIS_315
5091 if(ivideo->sisvga_engine == SIS_315_VGA) {
5092 if( (!sisvga_enabled)
5093 #if !defined(__i386__) && !defined(__x86_64__)
5094 || (sisfb_resetcard)
5097 if((ivideo->chip == SIS_315H) ||
5098 (ivideo->chip == SIS_315) ||
5099 (ivideo->chip == SIS_315PRO) ||
5100 (ivideo->chip == SIS_330)) {
5101 sisfb_post_sis315330(pdev);
5107 if(sisfb_get_dram_size(ivideo)) {
5108 printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
5109 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5110 pci_set_drvdata(pdev, NULL);
5115 if((ivideo->sisfb_mode_idx < 0) ||
5116 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5117 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
5118 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
5119 /* Enable 2D accelerator engine */
5120 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
5123 if(sisfb_pdc != 0xff) {
5124 if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
5125 else sisfb_pdc &= 0x1f;
5126 ivideo->SiS_Pr.PDC = sisfb_pdc;
5128 #ifdef CONFIG_FB_SIS_315
5129 if(ivideo->sisvga_engine == SIS_315_VGA) {
5130 if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
5134 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
5135 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
5136 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
5137 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5138 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5139 pci_set_drvdata(pdev, NULL);
5144 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
5145 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
5146 release_mem_region(ivideo->video_base, ivideo->video_size);
5147 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5148 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5149 pci_set_drvdata(pdev, NULL);
5154 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
5155 ivideo->sishw_ext.pjVideoMemoryAddress = ivideo->video_vbase;
5156 if(!ivideo->video_vbase) {
5157 printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
5158 release_mem_region(ivideo->video_base, ivideo->video_size);
5159 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5160 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5161 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5162 pci_set_drvdata(pdev, NULL);
5167 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
5168 if(!ivideo->mmio_vbase) {
5169 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
5170 iounmap(ivideo->video_vbase);
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 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5175 pci_set_drvdata(pdev, NULL);
5180 printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %ldk\n",
5181 ivideo->video_base, ivideo->video_vbase, ivideo->video_size / 1024);
5183 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
5184 ivideo->mmio_base, ivideo->mmio_vbase, ivideo->mmio_size / 1024);
5186 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
5187 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
5190 /* Used for clearing the screen only, therefore respect our mem limit */
5191 ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
5195 ivideo->vbflags = 0;
5196 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
5197 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
5198 ivideo->defmodeidx = DEFAULT_MODE;
5200 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
5202 if((ivideo->sisfb_mode_idx < 0) ||
5203 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5205 sisfb_sense_crt1(ivideo);
5207 sisfb_get_VB_type(ivideo);
5209 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5210 sisfb_detect_VB_connect(ivideo);
5213 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
5215 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5216 if(ivideo->sisfb_crt2type != -1) {
5217 if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
5218 ivideo->currentvbflags |= CRT2_LCD;
5219 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
5220 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
5223 /* Chrontel 700x TV detection often unreliable, therefore use a
5224 * different default order on such machines
5226 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
5227 if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5228 else if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
5229 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5231 if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
5232 else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5233 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5238 if(ivideo->vbflags & CRT2_LCD) {
5239 inSISIDXREG(SISCR, 0x36, reg);
5241 if(ivideo->sisvga_engine == SIS_300_VGA) {
5242 ivideo->sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
5243 } else if(ivideo->chip >= SIS_661) {
5244 ivideo->sishw_ext.ulCRT2LCDType = sis661paneltype[reg];
5246 ivideo->sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
5247 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
5248 if((ivideo->sishw_ext.ulCRT2LCDType != LCD_640x480_2) &&
5249 (ivideo->sishw_ext.ulCRT2LCDType != LCD_640x480_3)) {
5250 ivideo->sishw_ext.ulCRT2LCDType = LCD_320x480;
5254 if(ivideo->sishw_ext.ulCRT2LCDType == LCD_UNKNOWN) {
5255 ivideo->sishw_ext.ulCRT2LCDType = LCD_1024x768;
5256 printk(KERN_DEBUG "sisfb: Illegal panel ID (%02x), assuming 1024x768\n", reg);
5258 for(i = 0; i < SIS_LCD_NUMBER; i++) {
5259 if(ivideo->sishw_ext.ulCRT2LCDType == sis_lcd_data[i].lcdtype) {
5260 ivideo->lcdxres = sis_lcd_data[i].xres;
5261 ivideo->lcdyres = sis_lcd_data[i].yres;
5262 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
5266 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
5267 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
5268 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
5269 ivideo->lcdxres = 848; ivideo->lcdyres = 480; ivideo->lcddefmodeidx = 47;
5271 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
5272 ivideo->lcdxres, ivideo->lcdyres);
5275 #ifdef CONFIG_FB_SIS_300
5276 /* Save the current PanelDelayCompensation if the LCD is currently used */
5277 if(ivideo->sisvga_engine == SIS_300_VGA) {
5278 if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
5280 inSISIDXREG(SISCR,0x30,tmp);
5282 /* Currently on LCD? If yes, read current pdc */
5283 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
5284 ivideo->detectedpdc &= 0x3c;
5285 if(ivideo->SiS_Pr.PDC == -1) {
5286 /* Let option override detection */
5287 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5289 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
5290 ivideo->detectedpdc);
5292 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5293 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
5294 ivideo->SiS_Pr.PDC);
5300 #ifdef CONFIG_FB_SIS_315
5301 if(ivideo->sisvga_engine == SIS_315_VGA) {
5303 /* Try to find about LCDA */
5304 if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
5306 inSISIDXREG(SISPART1,0x13,tmp);
5308 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
5309 ivideo->detectedlcda = 0x03;
5314 if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
5316 inSISIDXREG(SISCR,0x30,tmp);
5317 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5318 /* Currently on LCD? If yes, read current pdc */
5320 inSISIDXREG(SISPART1,0x2D,pdc);
5321 ivideo->detectedpdc = (pdc & 0x0f) << 1;
5322 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
5323 inSISIDXREG(SISPART1,0x35,pdc);
5324 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
5325 inSISIDXREG(SISPART1,0x20,pdc);
5326 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
5327 if(ivideo->newrom) {
5328 /* New ROM invalidates other PDC resp. */
5329 if(ivideo->detectedlcda != 0xff) {
5330 ivideo->detectedpdc = 0xff;
5332 ivideo->detectedpdca = 0xff;
5335 if(ivideo->SiS_Pr.PDC == -1) {
5336 if(ivideo->detectedpdc != 0xff) {
5337 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5340 if(ivideo->SiS_Pr.PDCA == -1) {
5341 if(ivideo->detectedpdca != 0xff) {
5342 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
5345 if(ivideo->detectedpdc != 0xff) {
5347 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
5348 ivideo->detectedpdc);
5350 if(ivideo->detectedpdca != 0xff) {
5352 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
5353 ivideo->detectedpdca);
5358 if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
5359 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
5360 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
5361 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
5362 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
5363 ivideo->SiS_Pr.HaveEMI = TRUE;
5364 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5365 ivideo->SiS_Pr.HaveEMILCD = TRUE;
5370 /* Let user override detected PDCs (all bridges) */
5371 if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
5372 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5373 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
5374 ivideo->SiS_Pr.PDC);
5376 if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
5377 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
5378 ivideo->SiS_Pr.PDCA);
5385 if(!ivideo->sisfb_crt1off) {
5386 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
5388 if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
5389 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
5390 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
5394 if(ivideo->sisfb_mode_idx >= 0) {
5395 int bu = ivideo->sisfb_mode_idx;
5396 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
5397 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
5398 if(bu != ivideo->sisfb_mode_idx) {
5399 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
5400 sisbios_mode[bu].xres,
5401 sisbios_mode[bu].yres,
5402 sisbios_mode[bu].bpp);
5406 if(ivideo->sisfb_mode_idx < 0) {
5407 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
5409 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
5412 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
5415 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
5420 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
5422 if(ivideo->refresh_rate != 0) {
5423 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
5426 if(ivideo->rate_idx == 0) {
5427 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
5428 ivideo->refresh_rate = 60;
5431 if(ivideo->sisfb_thismonitor.datavalid) {
5432 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
5433 ivideo->rate_idx, ivideo->refresh_rate)) {
5434 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
5438 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
5439 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
5440 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
5442 sisfb_set_vparms(ivideo);
5444 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5446 /* ---------------- For 2.4: Now switch the mode ------------------ */
5448 printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
5449 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5450 ivideo->refresh_rate);
5452 sisfb_pre_setmode(ivideo);
5454 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
5455 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
5457 iounmap(ivideo->video_vbase);
5458 iounmap(ivideo->mmio_vbase);
5459 release_mem_region(ivideo->video_base, ivideo->video_size);
5460 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5461 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5462 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5463 pci_set_drvdata(pdev, NULL);
5468 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
5470 sisfb_post_setmode(ivideo);
5472 /* Maximize regardless of sisfb_max at startup */
5473 ivideo->default_var.yres_virtual = 32767;
5475 /* Force reset of x virtual in crtc_to_var */
5476 ivideo->default_var.xres_virtual = 0;
5478 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
5480 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5481 sisfb_set_pitch(ivideo);
5484 if(ivideo->sisfb_accel) {
5486 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5488 sisfb_initaccel(ivideo);
5490 sis_fb_info->node = -1;
5491 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5492 sis_fb_info->fbops = &sisfb_ops;
5493 sis_fb_info->disp = &ivideo->sis_disp;
5494 sis_fb_info->blank = &sisfb_blank;
5495 sis_fb_info->switch_con = &sisfb_switch;
5496 sis_fb_info->updatevar = &sisfb_update_var;
5497 sis_fb_info->changevar = NULL;
5498 strcpy(sis_fb_info->fontname, sisfb_fontname);
5500 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
5502 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
5504 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
5505 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5506 ivideo->refresh_rate);
5508 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
5509 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
5510 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
5512 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
5514 ivideo->default_var.pixclock = (u32) (1000000000 /
5515 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5516 ivideo->mode_no, ivideo->rate_idx));
5518 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5519 ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
5520 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
5521 ivideo->default_var.pixclock <<= 1;
5525 if(ivideo->sisfb_ypan) {
5526 /* Maximize regardless of sisfb_max at startup */
5527 ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var);
5528 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
5529 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
5533 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5536 if(ivideo->sisfb_accel) {
5538 #ifdef STUPID_ACCELF_TEXT_SHIT
5539 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5542 sisfb_initaccel(ivideo);
5544 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
5545 sis_fb_info->flags = FBINFO_DEFAULT |
5546 FBINFO_HWACCEL_YPAN |
5547 FBINFO_HWACCEL_XPAN |
5548 FBINFO_HWACCEL_COPYAREA |
5549 FBINFO_HWACCEL_FILLRECT |
5550 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
5552 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5554 sis_fb_info->var = ivideo->default_var;
5555 sis_fb_info->fix = ivideo->sisfb_fix;
5556 sis_fb_info->screen_base = ivideo->video_vbase;
5557 sis_fb_info->fbops = &sisfb_ops;
5559 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
5560 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
5562 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
5565 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
5568 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
5569 MTRR_TYPE_WRCOMB, 1);
5571 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
5575 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5576 vc_resize_con(1, 1, 0);
5579 if(register_framebuffer(sis_fb_info) < 0) {
5580 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
5581 iounmap(ivideo->video_vbase);
5582 iounmap(ivideo->mmio_vbase);
5583 release_mem_region(ivideo->video_base, ivideo->video_size);
5584 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5585 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5586 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5587 pci_set_drvdata(pdev, NULL);
5592 ivideo->registered = 1;
5595 ivideo->next = card_list;
5598 #ifdef SIS_CONFIG_COMPAT
5601 /* Our ioctls are all "32/64bit compatible" */
5602 if(register_ioctl32_conversion(FBIOGET_VBLANK, NULL)) {
5603 printk(KERN_ERR "sisfb: Error registering FBIOGET_VBLANK ioctl32 translation\n");
5605 ivideo->ioctl32vblankregistered = 1;
5607 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
5608 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
5609 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
5610 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
5611 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
5612 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
5613 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
5614 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
5615 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
5616 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
5617 if(ret) printk(KERN_ERR "sisfb: Error registering ioctl32 translations\n");
5618 else ivideo->ioctl32registered = 1;
5622 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
5623 ivideo->sisfb_accel ? "enabled" : "disabled",
5624 ivideo->sisfb_ypan ?
5625 (ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
5628 printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n",
5629 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5630 GET_FB_IDX(sis_fb_info->node),
5634 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
5636 printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
5638 } /* if mode = "none" */
5643 /*****************************************************/
5644 /* PCI DEVICE HANDLING */
5645 /*****************************************************/
5647 static void __devexit sisfb_remove(struct pci_dev *pdev)
5649 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5650 struct fb_info *sis_fb_info = ivideo->memyselfandi;
5651 int registered = ivideo->registered;
5653 #ifdef SIS_CONFIG_COMPAT
5654 if(ivideo->ioctl32vblankregistered) {
5655 if(unregister_ioctl32_conversion(FBIOGET_VBLANK)) {
5656 printk(KERN_ERR "sisfb: Error unregistering FBIOGET_VBLANK ioctl32 translation\n");
5659 if(ivideo->ioctl32registered) {
5661 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
5662 ret |= unregister_ioctl32_conversion(FBIO_FREE);
5663 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
5664 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
5665 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
5666 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
5667 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
5668 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
5669 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
5670 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
5671 if(ret) printk(KERN_ERR "sisfb: Error unregistering ioctl32 translations\n");
5676 iounmap(ivideo->video_vbase);
5677 iounmap(ivideo->mmio_vbase);
5678 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5679 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5681 /* Release mem regions */
5682 release_mem_region(ivideo->video_base, ivideo->video_size);
5683 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5686 /* Release MTRR region */
5688 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
5692 /* Unregister the framebuffer */
5693 if(ivideo->registered) {
5694 unregister_framebuffer(sis_fb_info);
5695 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5696 framebuffer_release(sis_fb_info);
5702 pci_set_drvdata(pdev, NULL);
5704 /* TODO: Restore the initial mode
5705 * This sounds easy but is as good as impossible
5706 * on many machines with SiS chip and video bridge
5707 * since text modes are always set up differently
5708 * from machine to machine. Depends on the type
5709 * of integration between chipset and bridge.
5712 printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
5716 static struct pci_driver sisfb_driver = {
5718 .id_table = sisfb_pci_table,
5719 .probe = sisfb_probe,
5720 .remove = __devexit_p(sisfb_remove)
5723 int __init sisfb_init(void)
5725 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5727 char *option = NULL;
5729 if (fb_get_options("sisfb", &option))
5731 sisfb_setup(option);
5734 return(pci_module_init(&sisfb_driver));
5737 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5739 module_init(sisfb_init);
5743 /*****************************************************/
5745 /*****************************************************/
5749 static char *mode = NULL;
5750 static int vesa = -1;
5751 static unsigned int rate = 0;
5752 static unsigned int crt1off = 1;
5753 static unsigned int mem = 0;
5754 static char *forcecrt2type = NULL;
5755 static int forcecrt1 = -1;
5756 static int pdc = -1;
5757 static int pdc1 = -1;
5758 static int noaccel = -1;
5759 static int noypan = -1;
5760 static int nomax = -1;
5761 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5762 static int inverse = 0;
5764 static int userom = -1;
5765 static int useoem = -1;
5766 static char *tvstandard = NULL;
5767 static int nocrt2rate = 0;
5768 static int scalelcd = -1;
5769 static char *specialtiming = NULL;
5770 static int lvdshl = -1;
5771 static int tvxposoffset = 0, tvyposoffset = 0;
5772 static int filter = -1;
5773 #if !defined(__i386__) && !defined(__x86_64__)
5774 static int resetcard = 0;
5775 static int videoram = 0;
5778 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
5779 MODULE_LICENSE("GPL");
5780 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
5782 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5783 MODULE_PARM(mem, "i");
5784 MODULE_PARM(noaccel, "i");
5785 MODULE_PARM(noypan, "i");
5786 MODULE_PARM(nomax, "i");
5787 MODULE_PARM(userom, "i");
5788 MODULE_PARM(useoem, "i");
5789 MODULE_PARM(mode, "s");
5790 MODULE_PARM(vesa, "i");
5791 MODULE_PARM(rate, "i");
5792 MODULE_PARM(forcecrt1, "i");
5793 MODULE_PARM(forcecrt2type, "s");
5794 MODULE_PARM(scalelcd, "i");
5795 MODULE_PARM(pdc, "i");
5796 MODULE_PARM(pdc1, "i");
5797 MODULE_PARM(specialtiming, "s");
5798 MODULE_PARM(lvdshl, "i");
5799 MODULE_PARM(tvstandard, "s");
5800 MODULE_PARM(tvxposoffset, "i");
5801 MODULE_PARM(tvyposoffset, "i");
5802 MODULE_PARM(filter, "i");
5803 MODULE_PARM(nocrt2rate, "i");
5804 MODULE_PARM(inverse, "i");
5805 #if !defined(__i386__) && !defined(__x86_64__)
5806 MODULE_PARM(resetcard, "i");
5807 MODULE_PARM(videoram, "i");
5811 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5812 module_param(mem, int, 0);
5813 module_param(noaccel, int, 0);
5814 module_param(noypan, int, 0);
5815 module_param(nomax, int, 0);
5816 module_param(userom, int, 0);
5817 module_param(useoem, int, 0);
5818 module_param(mode, charp, 0);
5819 module_param(vesa, int, 0);
5820 module_param(rate, int, 0);
5821 module_param(forcecrt1, int, 0);
5822 module_param(forcecrt2type, charp, 0);
5823 module_param(scalelcd, int, 0);
5824 module_param(pdc, int, 0);
5825 module_param(pdc1, int, 0);
5826 module_param(specialtiming, charp, 0);
5827 module_param(lvdshl, int, 0);
5828 module_param(tvstandard, charp, 0);
5829 module_param(tvxposoffset, int, 0);
5830 module_param(tvyposoffset, int, 0);
5831 module_param(filter, int, 0);
5832 module_param(nocrt2rate, int, 0);
5833 #if !defined(__i386__) && !defined(__x86_64__)
5834 module_param(resetcard, int, 0);
5835 module_param(videoram, int, 0);
5839 MODULE_PARM_DESC(mem,
5840 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
5841 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
5842 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
5843 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
5844 "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
5845 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
5846 "for XFree86 4.x/X.org 6.7 and later.\n");
5848 MODULE_PARM_DESC(noaccel,
5849 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
5852 MODULE_PARM_DESC(noypan,
5853 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
5854 "will be performed by redrawing the screen. (default: 0)\n");
5856 MODULE_PARM_DESC(nomax,
5857 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
5858 "memory for the virtual screen in order to optimize scrolling performance. If\n"
5859 "this is set to anything other than 0, sisfb will not do this and thereby \n"
5860 "enable the user to positively specify a virtual Y size of the screen using\n"
5861 "fbset. (default: 0)\n");
5863 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5864 MODULE_PARM_DESC(mode,
5865 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
5866 "1024x768x16. Other formats supported include XxY-Depth and\n"
5867 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5868 "number, it will be interpreted as a VESA mode number. (default: none if\n"
5869 "sisfb is a module; this leaves the console untouched and the driver will\n"
5870 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
5871 "is in the kernel)\n");
5872 MODULE_PARM_DESC(vesa,
5873 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
5874 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
5875 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
5876 "0x0103 if sisfb is in the kernel)\n");
5879 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5880 MODULE_PARM_DESC(mode,
5881 "\nSelects the desired default display mode in the format XxYxDepth,\n"
5882 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
5883 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5884 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
5886 MODULE_PARM_DESC(vesa,
5887 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
5888 "0x117 (default: 0x0103)\n");
5891 MODULE_PARM_DESC(rate,
5892 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
5893 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
5894 "will be ignored (default: 60)\n");
5896 MODULE_PARM_DESC(forcecrt1,
5897 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
5898 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
5899 "0=CRT1 OFF) (default: [autodetected])\n");
5901 MODULE_PARM_DESC(forcecrt2type,
5902 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
5903 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
5904 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
5905 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
5906 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
5907 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
5908 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
5909 "depends on the very hardware in use. (default: [autodetected])\n");
5911 MODULE_PARM_DESC(scalelcd,
5912 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
5913 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
5914 "show black bars around the image, TMDS panels will probably do the scaling\n"
5915 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
5917 MODULE_PARM_DESC(pdc,
5918 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
5919 "should detect this correctly in most cases; however, sometimes this is not\n"
5920 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
5921 "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
5922 "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
5923 "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
5925 #ifdef CONFIG_FB_SIS_315
5926 MODULE_PARM_DESC(pdc1,
5927 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
5928 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
5929 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
5930 "implemented yet.\n");
5933 MODULE_PARM_DESC(specialtiming,
5934 "\nPlease refer to documentation for more information on this option.\n");
5936 MODULE_PARM_DESC(lvdshl,
5937 "\nPlease refer to documentation for more information on this option.\n");
5939 MODULE_PARM_DESC(tvstandard,
5940 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
5941 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
5943 MODULE_PARM_DESC(tvxposoffset,
5944 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
5947 MODULE_PARM_DESC(tvyposoffset,
5948 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
5951 MODULE_PARM_DESC(filter,
5952 "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
5953 "(Possible values 0-7, default: [no filter])\n");
5955 MODULE_PARM_DESC(nocrt2rate,
5956 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
5957 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
5959 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5960 MODULE_PARM_DESC(inverse,
5961 "\nSetting this to anything but 0 should invert the display colors, but this\n"
5962 "does not seem to work. (default: 0)\n");
5965 #if !defined(__i386__) && !defined(__x86_64__)
5966 #ifdef CONFIG_FB_SIS_300
5967 MODULE_PARM_DESC(resetcard,
5968 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
5969 "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
5972 MODULE_PARM_DESC(videoram,
5973 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
5974 "some non-x86 architectures where the memory auto detection fails. Only\n"
5975 "relevant if resetcard is set, too. Default: [auto-detect]\n");
5979 int __init sisfb_init_module(void)
5981 sisfb_setdefaultparms();
5983 if(rate) sisfb_parm_rate = rate;
5985 if((scalelcd == 0) || (scalelcd == 1)) {
5986 sisfb_scalelcd = scalelcd ^ 1;
5989 /* Need to check crt2 type first for fstn/dstn */
5992 sisfb_search_crt2type(forcecrt2type);
5995 sisfb_search_tvstd(tvstandard);
5998 sisfb_search_mode(mode, FALSE);
6000 sisfb_search_vesamode(vesa, FALSE);
6002 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6004 sisfb_forcecrt1 = forcecrt1;
6005 if(forcecrt1 == 1) sisfb_crt1off = 0;
6006 else if(forcecrt1 == 0) sisfb_crt1off = 1;
6008 if(noaccel == 1) sisfb_accel = 0;
6009 else if(noaccel == 0) sisfb_accel = 1;
6011 if(noypan == 1) sisfb_ypan = 0;
6012 else if(noypan == 0) sisfb_ypan = 1;
6014 if(nomax == 1) sisfb_max = 0;
6015 else if(nomax == 0) sisfb_max = 1;
6017 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6018 if(inverse) sisfb_inverse = 1;
6021 if(mem) sisfb_parm_mem = mem;
6023 if(userom != -1) sisfb_userom = userom;
6024 if(useoem != -1) sisfb_useoem = useoem;
6026 if(pdc != -1) sisfb_pdc = (pdc & 0x7f);
6027 if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
6029 sisfb_nocrt2rate = nocrt2rate;
6032 sisfb_search_specialtiming(specialtiming);
6034 if((lvdshl >= 0) && (lvdshl <= 3)) sisfb_lvdshl = lvdshl;
6036 if(filter != -1) sisfb_filter = filter;
6038 sisfb_tvxposoffset = tvxposoffset;
6039 sisfb_tvyposoffset = tvyposoffset;
6041 #if !defined(__i386__) && !defined(__x86_64__)
6042 sisfb_resetcard = (resetcard) ? 1 : 0;
6043 if(videoram) sisfb_videoram = videoram;
6046 return(sisfb_init());
6049 static void __exit sisfb_remove_module(void)
6051 pci_unregister_driver(&sisfb_driver);
6052 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6055 module_init(sisfb_init_module);
6056 module_exit(sisfb_remove_module);
6058 #endif /* /MODULE */
6060 EXPORT_SYMBOL(sis_malloc);
6061 EXPORT_SYMBOL(sis_free);