2 * SiS 300/540/630[S]/730[S],
3 * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
5 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
7 * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the named License,
12 * or any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
23 * Author: Thomas Winischhofer <thomas@winischhofer.net>
25 * Author of (practically wiped) code base:
27 * Copyright (C) 1999 Silicon Integrated Systems, Inc.
29 * See http://www.winischhofer.net/ for more information and updates
31 * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
32 * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
36 #include <linux/config.h>
37 #include <linux/version.h>
38 #include <linux/module.h>
39 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
40 #include <linux/moduleparam.h>
42 #include <linux/kernel.h>
43 #include <linux/smp_lock.h>
44 #include <linux/spinlock.h>
45 #include <linux/errno.h>
46 #include <linux/string.h>
48 #include <linux/tty.h>
49 #include <linux/slab.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 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
57 #include <linux/vt_kern.h>
59 #include <linux/capability.h>
61 #include <linux/types.h>
62 #include <asm/uaccess.h>
68 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
69 #include <video/fbcon.h>
70 #include <video/fbcon-cfb8.h>
71 #include <video/fbcon-cfb16.h>
72 #include <video/fbcon-cfb24.h>
73 #include <video/fbcon-cfb32.h>
79 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
80 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
81 #error "This version of sisfb requires at least 2.6.3"
85 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
87 extern struct display_switch fbcon_sis8;
89 #ifdef FBCON_HAS_CFB16
90 extern struct display_switch fbcon_sis16;
92 #ifdef FBCON_HAS_CFB32
93 extern struct display_switch fbcon_sis32;
97 static void sisfb_handle_command(struct sis_video_info *ivideo,
98 struct sisfb_cmd *sisfb_command);
100 /* ------------------ Internal helper routines ----------------- */
103 sisfb_setdefaultparms(void)
113 /* Module: "None" for 2.4, default mode for 2.5+ */
114 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
117 sisfb_mode_idx = MODE_INDEX_NONE;
120 /* Static: Default mode */
123 sisfb_parm_rate = -1;
125 sisfb_forcecrt1 = -1;
131 sisfb_specialtiming = CUT_NONE;
137 sisfb_tvxposoffset = 0;
138 sisfb_tvyposoffset = 0;
139 sisfb_nocrt2rate = 0;
140 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
142 sisfb_fontname[0] = 0;
144 #if !defined(__i386__) && !defined(__x86_64__)
150 /* ------------- Parameter parsing -------------- */
152 static void __devinit
153 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
157 /* We don't know the hardware specs yet and there is no ivideo */
160 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
161 sisfb_mode_idx = MODE_INDEX_NONE;
164 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
166 sisfb_mode_idx = DEFAULT_MODE;
171 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
173 while(sisbios_mode[i++].mode_no[0] != 0) {
174 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
175 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
177 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
178 sisbios_mode[i-1].mode_no[1] == 0x56 ||
179 sisbios_mode[i-1].mode_no[1] == 0x53)
182 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
183 sisbios_mode[i-1].mode_no[1] == 0x5b)
186 sisfb_mode_idx = i - 1;
192 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
195 static void __devinit
196 sisfb_search_mode(char *name, BOOLEAN quiet)
198 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
200 char strbuf[16], strbuf1[20];
201 char *nameptr = name;
203 /* We don't know the hardware specs yet and there is no ivideo */
207 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
209 sisfb_mode_idx = DEFAULT_MODE;
213 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
214 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
216 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
218 sisfb_mode_idx = DEFAULT_MODE;
222 if(strlen(name) <= 19) {
223 strcpy(strbuf1, name);
224 for(i = 0; i < strlen(strbuf1); i++) {
225 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
228 /* This does some fuzzy mode naming detection */
229 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
230 if((rate <= 32) || (depth > 32)) {
231 j = rate; rate = depth; depth = j;
233 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
235 sisfb_parm_rate = rate;
236 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
237 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
241 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
242 sprintf(strbuf, "%ux%ux8", xres, yres);
245 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
252 while(sisbios_mode[i].mode_no[0] != 0) {
253 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
255 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
256 sisbios_mode[i-1].mode_no[1] == 0x56 ||
257 sisbios_mode[i-1].mode_no[1] == 0x53)
260 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
261 sisbios_mode[i-1].mode_no[1] == 0x5b)
264 sisfb_mode_idx = i - 1;
271 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
275 static void __devinit
276 sisfb_get_vga_mode_from_kernel(void)
278 #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
280 int mydepth = screen_info.lfb_depth;
282 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
284 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
285 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
286 (mydepth >= 8) && (mydepth <= 32) ) {
288 if(mydepth == 24) mydepth = 32;
290 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
291 screen_info.lfb_height,
295 "sisfb: Using vga mode %s pre-set by kernel as default\n",
298 sisfb_search_mode(mymode, TRUE);
306 sisfb_search_crt2type(const char *name)
310 /* We don't know the hardware specs yet and there is no ivideo */
312 if(name == NULL) return;
314 while(sis_crt2type[i].type_no != -1) {
315 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
316 sisfb_crt2type = sis_crt2type[i].type_no;
317 sisfb_tvplug = sis_crt2type[i].tvplug_no;
318 sisfb_crt2flags = sis_crt2type[i].flags;
324 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
325 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
327 if(sisfb_crt2type < 0)
328 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
332 sisfb_search_tvstd(const char *name)
336 /* We don't know the hardware specs yet and there is no ivideo */
341 while(sis_tvtype[i].type_no != -1) {
342 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
343 sisfb_tvstd = sis_tvtype[i].type_no;
351 sisfb_search_specialtiming(const char *name)
354 BOOLEAN found = FALSE;
356 /* We don't know the hardware specs yet and there is no ivideo */
361 if(!strnicmp(name, "none", 4)) {
362 sisfb_specialtiming = CUT_FORCENONE;
363 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
365 while(mycustomttable[i].chipID != 0) {
366 if(!strnicmp(name,mycustomttable[i].optionName,
367 strlen(mycustomttable[i].optionName))) {
368 sisfb_specialtiming = mycustomttable[i].SpecialID;
370 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
371 mycustomttable[i].vendorName,
372 mycustomttable[i].cardName,
373 mycustomttable[i].optionName);
379 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
380 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
382 while(mycustomttable[i].chipID != 0) {
383 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
384 mycustomttable[i].optionName,
385 mycustomttable[i].vendorName,
386 mycustomttable[i].cardName);
393 /* ----------- Various detection routines ----------- */
395 static void __devinit
396 sisfb_detect_custom_timing(struct sis_video_info *ivideo)
398 unsigned char *biosver = NULL;
399 unsigned char *biosdate = NULL;
404 if(ivideo->SiS_Pr.UseROM) {
405 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
406 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
407 for(i = 0; i < 32768; i++)
408 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
413 if( (mycustomttable[i].chipID == ivideo->chip) &&
414 ((!strlen(mycustomttable[i].biosversion)) ||
415 (ivideo->SiS_Pr.UseROM &&
416 (!strncmp(mycustomttable[i].biosversion, biosver,
417 strlen(mycustomttable[i].biosversion))))) &&
418 ((!strlen(mycustomttable[i].biosdate)) ||
419 (ivideo->SiS_Pr.UseROM &&
420 (!strncmp(mycustomttable[i].biosdate, biosdate,
421 strlen(mycustomttable[i].biosdate))))) &&
422 ((!mycustomttable[i].bioschksum) ||
423 (ivideo->SiS_Pr.UseROM &&
424 (mycustomttable[i].bioschksum == chksum))) &&
425 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
426 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
428 for(j = 0; j < 5; j++) {
429 if(mycustomttable[i].biosFootprintAddr[j]) {
430 if(ivideo->SiS_Pr.UseROM) {
431 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
432 mycustomttable[i].biosFootprintData[j]) {
440 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
441 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
442 mycustomttable[i].vendorName,
443 mycustomttable[i].cardName);
444 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
445 mycustomttable[i].optionName);
450 } while(mycustomttable[i].chipID);
453 static BOOLEAN __devinit
454 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
456 int i, j, xres, yres, refresh, index;
459 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
460 buffer[2] != 0xff || buffer[3] != 0xff ||
461 buffer[4] != 0xff || buffer[5] != 0xff ||
462 buffer[6] != 0xff || buffer[7] != 0x00) {
463 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
467 if(buffer[0x12] != 0x01) {
468 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
473 monitor->feature = buffer[0x18];
475 if(!buffer[0x14] & 0x80) {
476 if(!(buffer[0x14] & 0x08)) {
478 "sisfb: WARNING: Monitor does not support separate syncs\n");
482 if(buffer[0x13] >= 0x01) {
483 /* EDID V1 rev 1 and 2: Search for monitor descriptor
488 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
489 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
490 buffer[j + 4] == 0x00) {
491 monitor->hmin = buffer[j + 7];
492 monitor->hmax = buffer[j + 8];
493 monitor->vmin = buffer[j + 5];
494 monitor->vmax = buffer[j + 6];
495 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
496 monitor->datavalid = TRUE;
503 if(!monitor->datavalid) {
504 /* Otherwise: Get a range from the list of supported
505 * Estabished Timings. This is not entirely accurate,
506 * because fixed frequency monitors are not supported
509 monitor->hmin = 65535; monitor->hmax = 0;
510 monitor->vmin = 65535; monitor->vmax = 0;
511 monitor->dclockmax = 0;
512 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
513 for(i = 0; i < 13; i++) {
514 if(emodes & sisfb_ddcsmodes[i].mask) {
515 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
516 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
517 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
518 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
519 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
523 for(i = 0; i < 8; i++) {
524 xres = (buffer[index] + 31) * 8;
525 switch(buffer[index + 1] & 0xc0) {
526 case 0xc0: yres = (xres * 9) / 16; break;
527 case 0x80: yres = (xres * 4) / 5; break;
528 case 0x40: yres = (xres * 3) / 4; break;
529 default: yres = xres; break;
531 refresh = (buffer[index + 1] & 0x3f) + 60;
532 if((xres >= 640) && (yres >= 480)) {
533 for(j = 0; j < 8; j++) {
534 if((xres == sisfb_ddcfmodes[j].x) &&
535 (yres == sisfb_ddcfmodes[j].y) &&
536 (refresh == sisfb_ddcfmodes[j].v)) {
537 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
538 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
539 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
540 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
541 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
547 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
548 monitor->datavalid = TRUE;
552 return monitor->datavalid;
555 static void __devinit
556 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
558 unsigned short temp, i, realcrtno = crtno;
559 unsigned char buffer[256];
561 monitor->datavalid = FALSE;
564 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
565 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
569 if((ivideo->sisfb_crt1off) && (!crtno))
572 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
573 realcrtno, 0, &buffer[0], ivideo->vbflags2);
574 if((!temp) || (temp == 0xffff)) {
575 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
578 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
579 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
581 (temp & 0x1a) ? "" : "[none of the supported]",
582 (temp & 0x02) ? "2 " : "",
583 (temp & 0x08) ? "D&P" : "",
584 (temp & 0x10) ? "FPDI-2" : "");
586 i = 3; /* Number of retrys */
588 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
589 realcrtno, 1, &buffer[0], ivideo->vbflags2);
590 } while((temp) && i--);
592 if(sisfb_interpret_edid(monitor, &buffer[0])) {
593 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
594 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
595 monitor->dclockmax / 1000);
597 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
600 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
603 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
608 /* -------------- Mode validation --------------- */
611 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
612 int mode_idx, int rate_idx, int rate)
615 unsigned int dclock, hsync;
617 if(!monitor->datavalid)
623 /* Skip for 320x200, 320x240, 640x400 */
624 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
635 #ifdef CONFIG_FB_SIS_315
638 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
642 if(rate < (monitor->vmin - 1))
644 if(rate > (monitor->vmax + 1))
647 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
648 sisbios_mode[mode_idx].mode_no[ivideo->mni],
649 &htotal, &vtotal, rate_idx)) {
650 dclock = (htotal * vtotal * rate) / 1000;
651 if(dclock > (monitor->dclockmax + 1000))
653 hsync = dclock / htotal;
654 if(hsync < (monitor->hmin - 1))
656 if(hsync > (monitor->hmax + 1))
665 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
667 u16 xres=0, yres, myres;
669 #ifdef CONFIG_FB_SIS_300
670 if(ivideo->sisvga_engine == SIS_300_VGA) {
671 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
675 #ifdef CONFIG_FB_SIS_315
676 if(ivideo->sisvga_engine == SIS_315_VGA) {
677 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
682 myres = sisbios_mode[myindex].yres;
684 switch(vbflags & VB_DISPTYPE_DISP2) {
687 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
689 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
690 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
691 if(sisbios_mode[myindex].xres > xres)
697 if(ivideo->sisfb_fstn) {
698 if(sisbios_mode[myindex].xres == 320) {
700 switch(sisbios_mode[myindex].mode_no[1]) {
701 case 0x50: myindex = MODE_FSTN_8; break;
702 case 0x56: myindex = MODE_FSTN_16; break;
703 case 0x53: return -1;
709 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
710 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
711 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
717 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
718 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
724 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
725 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
735 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
738 u16 xres = sisbios_mode[mode_idx].xres;
739 u16 yres = sisbios_mode[mode_idx].yres;
741 ivideo->rate_idx = 0;
742 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
743 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
744 if(sisfb_vrate[i].refresh == rate) {
745 ivideo->rate_idx = sisfb_vrate[i].idx;
747 } else if(sisfb_vrate[i].refresh > rate) {
748 if((sisfb_vrate[i].refresh - rate) <= 3) {
749 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
750 rate, sisfb_vrate[i].refresh);
751 ivideo->rate_idx = sisfb_vrate[i].idx;
752 ivideo->refresh_rate = sisfb_vrate[i].refresh;
753 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
754 && (sisfb_vrate[i].idx != 1)) {
755 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
756 rate, sisfb_vrate[i-1].refresh);
757 ivideo->rate_idx = sisfb_vrate[i-1].idx;
758 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
761 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
762 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
763 rate, sisfb_vrate[i].refresh);
764 ivideo->rate_idx = sisfb_vrate[i].idx;
770 if(ivideo->rate_idx > 0) {
771 return ivideo->rate_idx;
773 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
780 sisfb_bridgeisslave(struct sis_video_info *ivideo)
784 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
787 inSISIDXREG(SISPART1,0x00,P1_00);
788 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
789 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
797 sisfballowretracecrt1(struct sis_video_info *ivideo)
801 inSISIDXREG(SISCR,0x17,temp);
805 inSISIDXREG(SISSR,0x1f,temp);
813 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
815 if(!sisfballowretracecrt1(ivideo))
818 if(inSISREG(SISINPSTAT) & 0x08)
825 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
829 if(!sisfballowretracecrt1(ivideo))
833 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
835 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
839 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
841 unsigned char temp, reg;
843 switch(ivideo->sisvga_engine) {
844 case SIS_300_VGA: reg = 0x25; break;
845 case SIS_315_VGA: reg = 0x30; break;
846 default: return FALSE;
849 inSISIDXREG(SISPART1, reg, temp);
857 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
859 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
860 if(!sisfb_bridgeisslave(ivideo)) {
861 return sisfbcheckvretracecrt2(ivideo);
864 return sisfbcheckvretracecrt1(ivideo);
868 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
870 u8 idx, reg1, reg2, reg3, reg4;
873 (*vcount) = (*hcount) = 0;
875 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
877 ret |= (FB_VBLANK_HAVE_VSYNC |
878 FB_VBLANK_HAVE_HBLANK |
879 FB_VBLANK_HAVE_VBLANK |
880 FB_VBLANK_HAVE_VCOUNT |
881 FB_VBLANK_HAVE_HCOUNT);
882 switch(ivideo->sisvga_engine) {
883 case SIS_300_VGA: idx = 0x25; break;
885 case SIS_315_VGA: idx = 0x30; break;
887 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
888 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
889 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
890 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
891 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
892 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
893 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
894 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
895 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
897 } else if(sisfballowretracecrt1(ivideo)) {
899 ret |= (FB_VBLANK_HAVE_VSYNC |
900 FB_VBLANK_HAVE_VBLANK |
901 FB_VBLANK_HAVE_VCOUNT |
902 FB_VBLANK_HAVE_HCOUNT);
903 reg1 = inSISREG(SISINPSTAT);
904 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
905 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
906 inSISIDXREG(SISCR,0x20,reg1);
907 inSISIDXREG(SISCR,0x1b,reg1);
908 inSISIDXREG(SISCR,0x1c,reg2);
909 inSISIDXREG(SISCR,0x1d,reg3);
910 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
911 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
918 sisfb_myblank(struct sis_video_info *ivideo, int blank)
920 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
921 BOOLEAN backlight = TRUE;
924 case FB_BLANK_UNBLANK: /* on */
933 case FB_BLANK_NORMAL: /* blank */
942 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
951 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
960 case FB_BLANK_POWERDOWN: /* off */
973 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
975 if( (!ivideo->sisfb_thismonitor.datavalid) ||
976 ((ivideo->sisfb_thismonitor.datavalid) &&
977 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
979 if(ivideo->sisvga_engine == SIS_315_VGA) {
980 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
983 if(!(sisfb_bridgeisslave(ivideo))) {
984 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
985 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
991 if(ivideo->currentvbflags & CRT2_LCD) {
993 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
995 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
997 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
999 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1000 #ifdef CONFIG_FB_SIS_315
1001 if(ivideo->vbflags2 & VB2_CHRONTEL) {
1003 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
1005 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
1011 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
1012 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
1013 ((ivideo->sisvga_engine == SIS_315_VGA) &&
1014 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
1015 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
1018 if(ivideo->sisvga_engine == SIS_300_VGA) {
1019 if((ivideo->vbflags2 & VB2_30xB) &&
1020 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1021 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
1023 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1024 if((ivideo->vbflags2 & VB2_30xB) &&
1025 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1026 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1030 } else if(ivideo->currentvbflags & CRT2_VGA) {
1032 if(ivideo->vbflags2 & VB2_30xB) {
1033 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1041 /* ------------- Callbacks from init.c/init301.c -------------- */
1043 #ifdef CONFIG_FB_SIS_300
1045 sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1047 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1050 pci_read_config_dword(ivideo->nbridge, reg, &val);
1051 return (unsigned int)val;
1055 sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1057 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1059 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1063 sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1065 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1068 if(!ivideo->lpcdev) return 0;
1070 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1071 return (unsigned int)val;
1075 #ifdef CONFIG_FB_SIS_315
1077 sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1079 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1081 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1085 sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1087 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1090 if(!ivideo->lpcdev) return 0;
1092 pci_read_config_word(ivideo->lpcdev, reg, &val);
1093 return (unsigned int)val;
1097 /* ----------- FBDev related routines for all series ----------- */
1100 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1102 return (var->bits_per_pixel == 8) ? 256 : 16;
1106 sisfb_set_vparms(struct sis_video_info *ivideo)
1108 switch(ivideo->video_bpp) {
1110 ivideo->DstColor = 0x0000;
1111 ivideo->SiS310_AccelDepth = 0x00000000;
1112 ivideo->video_cmap_len = 256;
1115 ivideo->DstColor = 0x8000;
1116 ivideo->SiS310_AccelDepth = 0x00010000;
1117 ivideo->video_cmap_len = 16;
1120 ivideo->DstColor = 0xC000;
1121 ivideo->SiS310_AccelDepth = 0x00020000;
1122 ivideo->video_cmap_len = 16;
1125 ivideo->video_cmap_len = 16;
1126 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1132 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1134 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1136 if(maxyres > 32767) maxyres = 32767;
1142 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1144 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1145 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1146 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1147 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1148 ivideo->scrnpitchCRT1 <<= 1;
1154 sisfb_set_pitch(struct sis_video_info *ivideo)
1156 BOOLEAN isslavemode = FALSE;
1157 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1158 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1160 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
1162 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1163 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1164 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1165 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1168 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1169 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1170 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1171 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1172 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1177 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1179 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1181 switch(var->bits_per_pixel) {
1183 var->red.offset = var->green.offset = var->blue.offset = 0;
1184 var->red.length = var->green.length = var->blue.length = 6;
1187 var->red.offset = 11;
1188 var->red.length = 5;
1189 var->green.offset = 5;
1190 var->green.length = 6;
1191 var->blue.offset = 0;
1192 var->blue.length = 5;
1193 var->transp.offset = 0;
1194 var->transp.length = 0;
1197 var->red.offset = 16;
1198 var->red.length = 8;
1199 var->green.offset = 8;
1200 var->green.length = 8;
1201 var->blue.offset = 0;
1202 var->blue.length = 8;
1203 var->transp.offset = 24;
1204 var->transp.length = 8;
1210 sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1212 unsigned short modeno = ivideo->mode_no;
1214 /* >=2.6.12's fbcon clears the screen anyway */
1215 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
1216 if(!clrscrn) modeno |= 0x80;
1221 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1223 sisfb_pre_setmode(ivideo);
1225 if(SiSSetMode(&ivideo->SiS_Pr, modeno) == 0) {
1226 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1230 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1232 sisfb_post_setmode(ivideo);
1239 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1241 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1242 unsigned int htotal = 0, vtotal = 0;
1243 unsigned int drate = 0, hrate = 0;
1244 int found_mode = 0, ret;
1248 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1250 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1252 pixclock = var->pixclock;
1254 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1255 vtotal += var->yres;
1257 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1258 vtotal += var->yres;
1260 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1261 vtotal += var->yres;
1263 } else vtotal += var->yres;
1265 if(!(htotal) || !(vtotal)) {
1266 DPRINTK("sisfb: Invalid 'var' information\n");
1270 if(pixclock && htotal && vtotal) {
1271 drate = 1000000000 / pixclock;
1272 hrate = (drate * 1000) / htotal;
1273 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1275 ivideo->refresh_rate = 60;
1278 old_mode = ivideo->sisfb_mode_idx;
1279 ivideo->sisfb_mode_idx = 0;
1281 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1282 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1283 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1284 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1285 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1286 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1290 ivideo->sisfb_mode_idx++;
1294 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1295 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1296 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1298 ivideo->sisfb_mode_idx = -1;
1301 if(ivideo->sisfb_mode_idx < 0) {
1302 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1303 var->yres, var->bits_per_pixel);
1304 ivideo->sisfb_mode_idx = old_mode;
1308 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1309 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1310 ivideo->refresh_rate = 60;
1313 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1314 if(ivideo->sisfb_thismonitor.datavalid) {
1315 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
1316 ivideo->rate_idx, ivideo->refresh_rate)) {
1317 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1322 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1323 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1327 /* If acceleration to be used? Need to know
1328 * before pre/post_set_mode()
1331 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1332 #ifdef STUPID_ACCELF_TEXT_SHIT
1333 if(var->accel_flags & FB_ACCELF_TEXT) {
1334 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1336 info->flags |= FBINFO_HWACCEL_DISABLED;
1339 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1341 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1344 if((ret = sisfb_set_mode(ivideo, 1))) {
1348 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1349 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1350 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1352 sisfb_calc_pitch(ivideo, var);
1353 sisfb_set_pitch(ivideo);
1355 sisfb_set_vparms(ivideo);
1357 ivideo->current_width = ivideo->video_width;
1358 ivideo->current_height = ivideo->video_height;
1359 ivideo->current_bpp = ivideo->video_bpp;
1360 ivideo->current_htotal = htotal;
1361 ivideo->current_vtotal = vtotal;
1362 ivideo->current_linelength = ivideo->video_linelength;
1363 ivideo->current_pixclock = var->pixclock;
1364 ivideo->current_refresh_rate = ivideo->refresh_rate;
1365 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1366 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1374 sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1376 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1378 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1379 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1380 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1381 if(ivideo->sisvga_engine == SIS_315_VGA) {
1382 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1387 sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1389 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1390 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1391 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1392 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1393 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1394 if(ivideo->sisvga_engine == SIS_315_VGA) {
1395 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1401 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1403 if(var->xoffset > (var->xres_virtual - var->xres)) {
1406 if(var->yoffset > (var->yres_virtual - var->yres)) {
1410 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
1412 /* calculate base bpp dep. */
1413 switch(var->bits_per_pixel) {
1417 ivideo->current_base >>= 1;
1421 ivideo->current_base >>= 2;
1425 ivideo->current_base += (ivideo->video_offset >> 2);
1427 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1428 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1433 /* ------------ FBDev related routines for 2.4 series ----------- */
1435 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1437 #include "sisfb_fbdev_2_4.h"
1441 /* ------------ FBDev related routines for 2.6 series ----------- */
1443 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1446 sisfb_open(struct fb_info *info, int user)
1452 sisfb_release(struct fb_info *info, int user)
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 >= sisfb_get_cmap_len(&info->var))
1466 switch(info->var.bits_per_pixel) {
1468 outSISREG(SISDACA, regno);
1469 outSISREG(SISDACD, (red >> 10));
1470 outSISREG(SISDACD, (green >> 10));
1471 outSISREG(SISDACD, (blue >> 10));
1472 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1473 outSISREG(SISDAC2A, regno);
1474 outSISREG(SISDAC2D, (red >> 8));
1475 outSISREG(SISDAC2D, (green >> 8));
1476 outSISREG(SISDAC2D, (blue >> 8));
1480 ((u32 *)(info->pseudo_palette))[regno] =
1482 ((green & 0xfc00) >> 5) |
1483 ((blue & 0xf800) >> 11);
1489 ((u32 *)(info->pseudo_palette))[regno] =
1490 (red << 16) | (green << 8) | (blue);
1497 sisfb_set_par(struct fb_info *info)
1501 if((err = sisfb_do_set_var(&info->var, 1, info)))
1504 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1505 sisfb_get_fix(&info->fix, info->currcon, info);
1507 sisfb_get_fix(&info->fix, -1, info);
1513 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1515 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1516 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1517 unsigned int drate = 0, hrate = 0, maxyres;
1519 int refresh_rate, search_idx, tidx;
1520 BOOLEAN recalc_clock = FALSE;
1523 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1525 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1527 pixclock = var->pixclock;
1529 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1530 vtotal += var->yres;
1532 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1533 vtotal += var->yres;
1535 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1536 vtotal += var->yres;
1539 vtotal += var->yres;
1541 if(!(htotal) || !(vtotal)) {
1542 SISFAIL("sisfb: no valid timing data");
1546 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1547 (sisbios_mode[search_idx].xres <= var->xres) ) {
1548 if( (sisbios_mode[search_idx].xres == var->xres) &&
1549 (sisbios_mode[search_idx].yres == var->yres) &&
1550 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1551 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1552 ivideo->currentvbflags)) > 0) {
1563 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1564 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1565 (var->yres <= sisbios_mode[search_idx].yres) &&
1566 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1567 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1568 ivideo->currentvbflags)) > 0) {
1578 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1579 var->xres, var->yres, var->bits_per_pixel,
1580 sisbios_mode[search_idx].xres,
1581 sisbios_mode[search_idx].yres,
1582 var->bits_per_pixel);
1583 var->xres = sisbios_mode[search_idx].xres;
1584 var->yres = sisbios_mode[search_idx].yres;
1587 "sisfb: Failed to find supported mode near %dx%dx%d\n",
1588 var->xres, var->yres, var->bits_per_pixel);
1593 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1594 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1595 (var->bits_per_pixel == 8) ) {
1596 /* Slave modes on LVDS and 301B-DH */
1598 recalc_clock = TRUE;
1599 } else if( (ivideo->current_htotal == htotal) &&
1600 (ivideo->current_vtotal == vtotal) &&
1601 (ivideo->current_pixclock == pixclock) ) {
1602 /* x=x & y=y & c=c -> assume depth change */
1603 drate = 1000000000 / pixclock;
1604 hrate = (drate * 1000) / htotal;
1605 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1606 } else if( ( (ivideo->current_htotal != htotal) ||
1607 (ivideo->current_vtotal != vtotal) ) &&
1608 (ivideo->current_pixclock == var->pixclock) ) {
1609 /* x!=x | y!=y & c=c -> invalid pixclock */
1610 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1612 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1613 } else if(ivideo->sisfb_parm_rate != -1) {
1614 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1615 refresh_rate = ivideo->sisfb_parm_rate;
1619 recalc_clock = TRUE;
1620 } else if((pixclock) && (htotal) && (vtotal)) {
1621 drate = 1000000000 / pixclock;
1622 hrate = (drate * 1000) / htotal;
1623 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1624 } else if(ivideo->current_refresh_rate) {
1625 refresh_rate = ivideo->current_refresh_rate;
1626 recalc_clock = TRUE;
1629 recalc_clock = TRUE;
1632 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1634 /* Eventually recalculate timing and clock */
1636 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1637 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1638 sisbios_mode[search_idx].mode_no[ivideo->mni],
1640 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1641 sisbios_mode[search_idx].mode_no[ivideo->mni],
1643 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1644 var->pixclock <<= 1;
1648 if(ivideo->sisfb_thismonitor.datavalid) {
1649 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1650 myrateindex, refresh_rate)) {
1652 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1656 /* Adapt RGB settings */
1657 sisfb_bpp_to_var(ivideo, var);
1659 /* Sanity check for offsets */
1660 if(var->xoffset < 0) var->xoffset = 0;
1661 if(var->yoffset < 0) var->yoffset = 0;
1663 if(var->xres > var->xres_virtual)
1664 var->xres_virtual = var->xres;
1666 if(ivideo->sisfb_ypan) {
1667 maxyres = sisfb_calc_maxyres(ivideo, var);
1668 if(ivideo->sisfb_max) {
1669 var->yres_virtual = maxyres;
1671 if(var->yres_virtual > maxyres) {
1672 var->yres_virtual = maxyres;
1675 if(var->yres_virtual <= var->yres) {
1676 var->yres_virtual = var->yres;
1679 if(var->yres != var->yres_virtual) {
1680 var->yres_virtual = var->yres;
1686 /* Truncate offsets to maximum if too high */
1687 if(var->xoffset > var->xres_virtual - var->xres) {
1688 var->xoffset = var->xres_virtual - var->xres - 1;
1691 if(var->yoffset > var->yres_virtual - var->yres) {
1692 var->yoffset = var->yres_virtual - var->yres - 1;
1695 /* Set everything else to 0 */
1696 var->red.msb_right =
1697 var->green.msb_right =
1698 var->blue.msb_right =
1699 var->transp.offset =
1700 var->transp.length =
1701 var->transp.msb_right = 0;
1707 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1709 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1712 if(var->xoffset > (var->xres_virtual - var->xres))
1715 if(var->yoffset > (var->yres_virtual - var->yres))
1718 if(var->vmode & FB_VMODE_YWRAP)
1721 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
1722 var->yoffset + info->var.yres > info->var.yres_virtual)
1725 if((err = sisfb_pan_var(ivideo, var)) < 0)
1728 info->var.xoffset = var->xoffset;
1729 info->var.yoffset = var->yoffset;
1735 sisfb_blank(int blank, struct fb_info *info)
1737 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1739 return sisfb_myblank(ivideo, blank);
1744 /* ----------- FBDev related routines for all series ---------- */
1747 sisfb_ioctl(struct inode *inode, struct file *file,
1748 unsigned int cmd, unsigned long arg,
1749 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1752 struct fb_info *info)
1754 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1755 struct sis_memreq sismemreq;
1756 struct fb_vblank sisvbblank;
1761 u32 __user *argp = (u32 __user *)arg;
1765 if(!capable(CAP_SYS_RAWIO))
1768 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1771 sis_malloc(&sismemreq);
1773 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1774 sis_free((u32)sismemreq.offset);
1780 if(!capable(CAP_SYS_RAWIO))
1783 if(get_user(gpu32, argp))
1789 case FBIOGET_VBLANK:
1790 sisvbblank.count = 0;
1791 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1793 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1798 case SISFB_GET_INFO_SIZE:
1799 return put_user(sizeof(struct sisfb_info), argp);
1801 case SISFB_GET_INFO_OLD:
1802 if(ivideo->warncount++ < 10)
1804 "sisfb: Deprecated ioctl call received - update your application!\n");
1805 case SISFB_GET_INFO: /* For communication with X driver */
1806 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1807 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1808 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1809 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1810 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1811 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1812 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1813 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1814 if(ivideo->modechanged) {
1815 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1817 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1819 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1820 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1821 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1822 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1823 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1824 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1825 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1826 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1827 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1828 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1829 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1830 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1831 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1832 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1833 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1834 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1835 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1836 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1837 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1838 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1839 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1840 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1841 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1842 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1843 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1844 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1845 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1846 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1848 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1849 sizeof(ivideo->sisfb_infoblock)))
1854 case SISFB_GET_VBRSTATUS_OLD:
1855 if(ivideo->warncount++ < 10)
1857 "sisfb: Deprecated ioctl call received - update your application!\n");
1858 case SISFB_GET_VBRSTATUS:
1859 if(sisfb_CheckVBRetrace(ivideo))
1860 return put_user((u32)1, argp);
1862 return put_user((u32)0, argp);
1864 case SISFB_GET_AUTOMAXIMIZE_OLD:
1865 if(ivideo->warncount++ < 10)
1867 "sisfb: Deprecated ioctl call received - update your application!\n");
1868 case SISFB_GET_AUTOMAXIMIZE:
1869 if(ivideo->sisfb_max)
1870 return put_user((u32)1, argp);
1872 return put_user((u32)0, argp);
1874 case SISFB_SET_AUTOMAXIMIZE_OLD:
1875 if(ivideo->warncount++ < 10)
1877 "sisfb: Deprecated ioctl call received - update your application!\n");
1878 case SISFB_SET_AUTOMAXIMIZE:
1879 if(get_user(gpu32, argp))
1882 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1885 case SISFB_SET_TVPOSOFFSET:
1886 if(get_user(gpu32, argp))
1889 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1890 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1893 case SISFB_GET_TVPOSOFFSET:
1894 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1898 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1899 sizeof(struct sisfb_cmd)))
1902 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1904 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1905 sizeof(struct sisfb_cmd)))
1910 case SISFB_SET_LOCK:
1911 if(get_user(gpu32, argp))
1914 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1918 #ifdef SIS_NEW_CONFIG_COMPAT
1919 return -ENOIOCTLCMD;
1927 #ifdef SIS_NEW_CONFIG_COMPAT
1929 sisfb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg, struct fb_info *info)
1934 ret = sisfb_ioctl(NULL, f, cmd, arg, info);
1941 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1943 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1945 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1947 strcpy(fix->id, ivideo->myid);
1949 fix->smem_start = ivideo->video_base + ivideo->video_offset;
1950 fix->smem_len = ivideo->sisfb_mem;
1951 fix->type = FB_TYPE_PACKED_PIXELS;
1953 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1955 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1957 fix->line_length = ivideo->video_linelength;
1958 fix->mmio_start = ivideo->mmio_base;
1959 fix->mmio_len = ivideo->mmio_size;
1960 if(ivideo->sisvga_engine == SIS_300_VGA) {
1961 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1962 } else if((ivideo->chip == SIS_330) ||
1963 (ivideo->chip == SIS_760) ||
1964 (ivideo->chip == SIS_761)) {
1965 fix->accel = FB_ACCEL_SIS_XABRE;
1966 } else if(ivideo->chip == XGI_20) {
1967 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1968 } else if(ivideo->chip >= XGI_40) {
1969 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1971 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1977 /* ---------------- fb_ops structures ----------------- */
1979 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1980 static struct fb_ops sisfb_ops = {
1981 .owner = THIS_MODULE,
1982 .fb_get_fix = sisfb_get_fix,
1983 .fb_get_var = sisfb_get_var,
1984 .fb_set_var = sisfb_set_var,
1985 .fb_get_cmap = sisfb_get_cmap,
1986 .fb_set_cmap = sisfb_set_cmap,
1987 .fb_pan_display = sisfb_pan_display,
1988 .fb_ioctl = sisfb_ioctl
1992 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1993 static struct fb_ops sisfb_ops = {
1994 .owner = THIS_MODULE,
1995 .fb_open = sisfb_open,
1996 .fb_release = sisfb_release,
1997 .fb_check_var = sisfb_check_var,
1998 .fb_set_par = sisfb_set_par,
1999 .fb_setcolreg = sisfb_setcolreg,
2000 .fb_pan_display = sisfb_pan_display,
2001 .fb_blank = sisfb_blank,
2002 .fb_fillrect = fbcon_sis_fillrect,
2003 .fb_copyarea = fbcon_sis_copyarea,
2004 .fb_imageblit = cfb_imageblit,
2005 .fb_cursor = soft_cursor,
2006 .fb_sync = fbcon_sis_sync,
2007 #ifdef SIS_NEW_CONFIG_COMPAT
2008 .fb_compat_ioctl= sisfb_compat_ioctl,
2010 .fb_ioctl = sisfb_ioctl
2014 /* ---------------- Chip generation dependent routines ---------------- */
2016 static struct pci_dev * __devinit
2017 sisfb_get_northbridge(int basechipid)
2019 struct pci_dev *pdev = NULL;
2020 int nbridgenum, nbridgeidx, i;
2021 static const unsigned short nbridgeids[] = {
2022 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2023 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2024 PCI_DEVICE_ID_SI_730,
2025 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2026 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2027 PCI_DEVICE_ID_SI_651,
2028 PCI_DEVICE_ID_SI_740,
2029 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
2030 PCI_DEVICE_ID_SI_741,
2031 PCI_DEVICE_ID_SI_660,
2032 PCI_DEVICE_ID_SI_760,
2033 PCI_DEVICE_ID_SI_761
2036 switch(basechipid) {
2037 #ifdef CONFIG_FB_SIS_300
2038 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2039 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2041 #ifdef CONFIG_FB_SIS_315
2042 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2043 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
2044 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
2046 default: return NULL;
2048 for(i = 0; i < nbridgenum; i++) {
2049 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2050 nbridgeids[nbridgeidx+i], NULL)))
2056 static int __devinit
2057 sisfb_get_dram_size(struct sis_video_info *ivideo)
2059 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2063 ivideo->video_size = 0;
2064 ivideo->UMAsize = ivideo->LFBsize = 0;
2066 switch(ivideo->chip) {
2067 #ifdef CONFIG_FB_SIS_300
2069 inSISIDXREG(SISSR, 0x14, reg);
2070 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2075 if(!ivideo->nbridge)
2077 pci_read_config_byte(ivideo->nbridge, 0x63, ®);
2078 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2081 #ifdef CONFIG_FB_SIS_315
2085 inSISIDXREG(SISSR, 0x14, reg);
2086 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2087 switch((reg >> 2) & 0x03) {
2090 ivideo->video_size <<= 1;
2093 ivideo->video_size += (ivideo->video_size/2);
2097 inSISIDXREG(SISSR, 0x14, reg);
2098 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2099 if(reg & 0x0c) ivideo->video_size <<= 1;
2104 inSISIDXREG(SISSR, 0x14, reg);
2105 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2109 inSISIDXREG(SISCR, 0x79, reg);
2110 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2115 inSISIDXREG(SISCR, 0x79, reg);
2116 reg = (reg & 0xf0) >> 4;
2118 ivideo->video_size = (1 << reg) << 20;
2119 ivideo->UMAsize = ivideo->video_size;
2121 inSISIDXREG(SISCR, 0x78, reg);
2125 ivideo->LFBsize = (32 << 20);
2127 ivideo->LFBsize = (64 << 20);
2129 ivideo->video_size += ivideo->LFBsize;
2135 inSISIDXREG(SISSR, 0x14, reg);
2136 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2137 if(ivideo->chip != XGI_20) {
2138 reg = (reg & 0x0c) >> 2;
2139 if(ivideo->revision_id == 2) {
2140 if(reg & 0x01) reg = 0x02;
2143 if(reg == 0x02) ivideo->video_size <<= 1;
2144 else if(reg == 0x03) ivideo->video_size <<= 2;
2154 /* -------------- video bridge device detection --------------- */
2156 static void __devinit
2157 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2161 /* No CRT2 on XGI Z7 */
2162 if(ivideo->chip == XGI_20) {
2163 ivideo->sisfb_crt1off = 0;
2167 #ifdef CONFIG_FB_SIS_300
2168 if(ivideo->sisvga_engine == SIS_300_VGA) {
2169 inSISIDXREG(SISSR, 0x17, temp);
2170 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2171 /* PAL/NTSC is stored on SR16 on such machines */
2172 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2173 inSISIDXREG(SISSR, 0x16, temp);
2175 ivideo->vbflags |= TV_PAL;
2177 ivideo->vbflags |= TV_NTSC;
2183 inSISIDXREG(SISCR, 0x32, cr32);
2185 if(cr32 & SIS_CRT1) {
2186 ivideo->sisfb_crt1off = 0;
2188 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2191 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2193 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2194 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2195 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2197 /* Check given parms for hardware compatibility.
2198 * (Cannot do this in the search_xx routines since we don't
2199 * know what hardware we are running on then)
2202 if(ivideo->chip != SIS_550) {
2203 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2206 if(ivideo->sisfb_tvplug != -1) {
2207 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2208 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2209 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2210 ivideo->sisfb_tvplug = -1;
2211 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2215 if(ivideo->sisfb_tvplug != -1) {
2216 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2217 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2218 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2219 ivideo->sisfb_tvplug = -1;
2220 printk(KERN_ERR "sisfb: HiVision not supported\n");
2224 if(ivideo->sisfb_tvstd != -1) {
2225 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2226 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2227 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2228 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2229 ivideo->sisfb_tvstd = -1;
2230 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2235 /* Detect/set TV plug & type */
2236 if(ivideo->sisfb_tvplug != -1) {
2237 ivideo->vbflags |= ivideo->sisfb_tvplug;
2239 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2240 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2241 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2243 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2244 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2248 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2249 if(ivideo->sisfb_tvstd != -1) {
2250 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2251 ivideo->vbflags |= ivideo->sisfb_tvstd;
2253 if(ivideo->vbflags & TV_SCART) {
2254 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2255 ivideo->vbflags |= TV_PAL;
2257 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2258 if(ivideo->sisvga_engine == SIS_300_VGA) {
2259 inSISIDXREG(SISSR, 0x38, temp);
2260 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2261 else ivideo->vbflags |= TV_NTSC;
2262 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2263 inSISIDXREG(SISSR, 0x38, temp);
2264 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2265 else ivideo->vbflags |= TV_NTSC;
2267 inSISIDXREG(SISCR, 0x79, temp);
2268 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2269 else ivideo->vbflags |= TV_NTSC;
2274 /* Copy forceCRT1 option to CRT1off if option is given */
2275 if(ivideo->sisfb_forcecrt1 != -1) {
2276 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2280 /* ------------------ Sensing routines ------------------ */
2282 static BOOLEAN __devinit
2283 sisfb_test_DDC1(struct sis_video_info *ivideo)
2288 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2290 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2292 return (count == -1) ? FALSE : TRUE;
2295 static void __devinit
2296 sisfb_sense_crt1(struct sis_video_info *ivideo)
2298 BOOLEAN mustwait = FALSE;
2300 #ifdef CONFIG_FB_SIS_315
2306 inSISIDXREG(SISSR,0x1F,sr1F);
2307 orSISIDXREG(SISSR,0x1F,0x04);
2308 andSISIDXREG(SISSR,0x1F,0x3F);
2309 if(sr1F & 0xc0) mustwait = TRUE;
2311 #ifdef CONFIG_FB_SIS_315
2312 if(ivideo->sisvga_engine == SIS_315_VGA) {
2313 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2315 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2319 inSISIDXREG(SISCR,0x17,cr17);
2322 orSISIDXREG(SISCR,0x17,0x80);
2324 outSISIDXREG(SISSR, 0x00, 0x01);
2325 outSISIDXREG(SISSR, 0x00, 0x03);
2329 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2332 #ifdef CONFIG_FB_SIS_315
2333 if(ivideo->chip >= SIS_330) {
2334 andSISIDXREG(SISCR,0x32,~0x20);
2335 if(ivideo->chip >= SIS_340) {
2336 outSISIDXREG(SISCR, 0x57, 0x4a);
2338 outSISIDXREG(SISCR, 0x57, 0x5f);
2340 orSISIDXREG(SISCR, 0x53, 0x02);
2341 while((inSISREG(SISINPSTAT)) & 0x01) break;
2342 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2343 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2344 andSISIDXREG(SISCR, 0x53, 0xfd);
2345 andSISIDXREG(SISCR, 0x57, 0x00);
2349 if(temp == 0xffff) {
2352 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2353 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2354 } while(((temp == 0) || (temp == 0xffff)) && i--);
2356 if((temp == 0) || (temp == 0xffff)) {
2357 if(sisfb_test_DDC1(ivideo)) temp = 1;
2361 if((temp) && (temp != 0xffff)) {
2362 orSISIDXREG(SISCR,0x32,0x20);
2365 #ifdef CONFIG_FB_SIS_315
2366 if(ivideo->sisvga_engine == SIS_315_VGA) {
2367 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2371 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2373 outSISIDXREG(SISSR,0x1F,sr1F);
2376 /* Determine and detect attached devices on SiS30x */
2377 static void __devinit
2378 SiS_SenseLCD(struct sis_video_info *ivideo)
2380 unsigned char buffer[256];
2381 unsigned short temp, realcrtno, i;
2382 u8 reg, cr37 = 0, paneltype = 0;
2385 ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2387 /* LCD detection only for TMDS bridges */
2388 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2390 if(ivideo->vbflags2 & VB2_30xBDH)
2393 /* If LCD already set up by BIOS, skip it */
2394 inSISIDXREG(SISCR, 0x32, reg);
2399 if(ivideo->SiS_Pr.DDCPortMixup)
2402 /* Check DDC capabilities */
2403 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2404 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2406 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2410 i = 3; /* Number of retrys */
2412 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2413 ivideo->sisvga_engine, realcrtno, 1,
2414 &buffer[0], ivideo->vbflags2);
2415 } while((temp) && i--);
2420 /* No digital device */
2421 if(!(buffer[0x14] & 0x80))
2424 /* First detailed timing preferred timing? */
2425 if(!(buffer[0x18] & 0x02))
2428 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2429 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2441 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2452 if((buffer[0x47] & 0x18) == 0x18)
2453 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2457 outSISIDXREG(SISCR, 0x36, paneltype);
2459 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2460 orSISIDXREG(SISCR, 0x32, 0x08);
2462 ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2465 static int __devinit
2466 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2468 int temp, mytest, result, i, j;
2470 for(j = 0; j < 10; j++) {
2472 for(i = 0; i < 3; i++) {
2474 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2475 temp = (type >> 8) | (mytest & 0x00ff);
2476 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2477 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2480 inSISIDXREG(SISPART4,0x03,temp);
2483 if(temp == mytest) result++;
2485 outSISIDXREG(SISPART4,0x11,0x00);
2486 andSISIDXREG(SISPART4,0x10,0xe0);
2487 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2490 if((result == 0) || (result >= 2)) break;
2495 static void __devinit
2496 SiS_Sense30x(struct sis_video_info *ivideo)
2498 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2499 u16 svhs=0, svhs_c=0;
2500 u16 cvbs=0, cvbs_c=0;
2501 u16 vga2=0, vga2_c=0;
2503 char stdstr[] = "sisfb: Detected";
2504 char tvstr[] = "TV connected to";
2506 if(ivideo->vbflags2 & VB2_301) {
2507 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2508 inSISIDXREG(SISPART4,0x01,myflag);
2510 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2512 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2513 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2514 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2515 svhs = 0x0200; cvbs = 0x0100;
2516 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2517 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2521 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2522 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2523 svhs_c = 0x0408; cvbs_c = 0x0808;
2527 if(ivideo->haveXGIROM) {
2528 biosflag = ivideo->bios_abase[0x58] & 0x03;
2529 } else if(ivideo->newrom) {
2530 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2531 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2532 if(ivideo->bios_abase) {
2533 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2537 if(ivideo->chip == SIS_300) {
2538 inSISIDXREG(SISSR,0x3b,myflag);
2539 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2542 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2546 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2547 orSISIDXREG(SISSR,0x1e,0x20);
2549 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2550 if(ivideo->vbflags2 & VB2_30xC) {
2551 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2553 orSISIDXREG(SISPART4,0x0d,0x04);
2555 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2557 inSISIDXREG(SISPART2,0x00,backupP2_00);
2558 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2560 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2561 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2562 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2565 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2566 SISDoSense(ivideo, 0, 0);
2569 andSISIDXREG(SISCR, 0x32, ~0x14);
2571 if(vga2_c || vga2) {
2572 if(SISDoSense(ivideo, vga2, vga2_c)) {
2573 if(biosflag & 0x01) {
2574 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2575 orSISIDXREG(SISCR, 0x32, 0x04);
2577 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2578 orSISIDXREG(SISCR, 0x32, 0x10);
2583 andSISIDXREG(SISCR, 0x32, 0x3f);
2585 if(ivideo->vbflags2 & VB2_30xCLV) {
2586 orSISIDXREG(SISPART4,0x0d,0x04);
2589 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2590 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2591 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2592 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2593 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2594 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2595 orSISIDXREG(SISCR,0x32,0x80);
2598 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2601 andSISIDXREG(SISCR, 0x32, ~0x03);
2603 if(!(ivideo->vbflags & TV_YPBPR)) {
2604 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2605 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2606 orSISIDXREG(SISCR, 0x32, 0x02);
2608 if((biosflag & 0x02) || (!result)) {
2609 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2610 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2611 orSISIDXREG(SISCR, 0x32, 0x01);
2616 SISDoSense(ivideo, 0, 0);
2618 outSISIDXREG(SISPART2,0x00,backupP2_00);
2619 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2620 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2622 if(ivideo->vbflags2 & VB2_30xCLV) {
2623 inSISIDXREG(SISPART2,0x00,biosflag);
2624 if(biosflag & 0x20) {
2625 for(myflag = 2; myflag > 0; myflag--) {
2627 outSISIDXREG(SISPART2,0x00,biosflag);
2632 outSISIDXREG(SISPART2,0x00,backupP2_00);
2635 /* Determine and detect attached TV's on Chrontel */
2636 static void __devinit
2637 SiS_SenseCh(struct sis_video_info *ivideo)
2639 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2641 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2643 #ifdef CONFIG_FB_SIS_300
2644 unsigned char test[3];
2648 if(ivideo->chip < SIS_315H) {
2650 #ifdef CONFIG_FB_SIS_300
2651 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2652 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2653 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2654 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2655 /* See Chrontel TB31 for explanation */
2656 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2657 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2658 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2659 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2661 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2662 if(temp2 != temp1) temp1 = temp2;
2664 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2665 /* Read power status */
2666 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2667 if((temp1 & 0x03) != 0x03) {
2668 /* Power all outputs */
2669 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2670 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2672 /* Sense connected TV devices */
2673 for(i = 0; i < 3; i++) {
2674 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2675 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2676 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2677 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2678 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2679 if(!(temp1 & 0x08)) test[i] = 0x02;
2680 else if(!(temp1 & 0x02)) test[i] = 0x01;
2682 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2685 if(test[0] == test[1]) temp1 = test[0];
2686 else if(test[0] == test[2]) temp1 = test[0];
2687 else if(test[1] == test[2]) temp1 = test[1];
2690 "sisfb: TV detection unreliable - test results varied\n");
2694 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2695 ivideo->vbflags |= TV_SVIDEO;
2696 orSISIDXREG(SISCR, 0x32, 0x02);
2697 andSISIDXREG(SISCR, 0x32, ~0x05);
2698 } else if (temp1 == 0x01) {
2699 printk(KERN_INFO "%s CVBS output\n", stdstr);
2700 ivideo->vbflags |= TV_AVIDEO;
2701 orSISIDXREG(SISCR, 0x32, 0x01);
2702 andSISIDXREG(SISCR, 0x32, ~0x06);
2704 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2705 andSISIDXREG(SISCR, 0x32, ~0x07);
2707 } else if(temp1 == 0) {
2708 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2709 andSISIDXREG(SISCR, 0x32, ~0x07);
2711 /* Set general purpose IO for Chrontel communication */
2712 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2717 #ifdef CONFIG_FB_SIS_315
2718 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2719 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2720 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2721 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2722 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2724 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2725 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2727 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2728 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2729 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2730 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2732 if(temp2 & 0x02) temp1 |= 0x01;
2733 if(temp2 & 0x10) temp1 |= 0x01;
2734 if(temp2 & 0x04) temp1 |= 0x02;
2735 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2738 printk(KERN_INFO "%s CVBS output\n", stdstr);
2739 ivideo->vbflags |= TV_AVIDEO;
2740 orSISIDXREG(SISCR, 0x32, 0x01);
2741 andSISIDXREG(SISCR, 0x32, ~0x06);
2744 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2745 ivideo->vbflags |= TV_SVIDEO;
2746 orSISIDXREG(SISCR, 0x32, 0x02);
2747 andSISIDXREG(SISCR, 0x32, ~0x05);
2750 printk(KERN_INFO "%s SCART output\n", stdstr);
2751 orSISIDXREG(SISCR, 0x32, 0x04);
2752 andSISIDXREG(SISCR, 0x32, ~0x03);
2755 andSISIDXREG(SISCR, 0x32, ~0x07);
2761 static void __devinit
2762 sisfb_get_VB_type(struct sis_video_info *ivideo)
2764 char stdstr[] = "sisfb: Detected";
2765 char bridgestr[] = "video bridge";
2769 /* No CRT2 on XGI Z7 */
2770 if(ivideo->chip == XGI_20)
2773 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2776 inSISIDXREG(SISPART4, 0x01, reg);
2778 ivideo->vbflags |= VB_301; /* Deprecated */
2779 ivideo->vbflags2 |= VB2_301;
2780 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2781 } else if(reg < 0xc0) {
2782 ivideo->vbflags |= VB_301B; /* Deprecated */
2783 ivideo->vbflags2 |= VB2_301B;
2784 inSISIDXREG(SISPART4,0x23,reg);
2786 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2787 ivideo->vbflags2 |= VB2_30xBDH;
2788 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2790 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2792 } else if(reg < 0xd0) {
2793 ivideo->vbflags |= VB_301C; /* Deprecated */
2794 ivideo->vbflags2 |= VB2_301C;
2795 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2796 } else if(reg < 0xe0) {
2797 ivideo->vbflags |= VB_301LV; /* Deprecated */
2798 ivideo->vbflags2 |= VB2_301LV;
2799 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2800 } else if(reg <= 0xe1) {
2801 inSISIDXREG(SISPART4,0x39,reg);
2803 ivideo->vbflags |= VB_302LV; /* Deprecated */
2804 ivideo->vbflags2 |= VB2_302LV;
2805 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2807 ivideo->vbflags |= VB_301C; /* Deprecated */
2808 ivideo->vbflags2 |= VB2_301C;
2809 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2811 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2812 ivideo->vbflags2 |= VB2_302ELV;
2813 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2819 ivideo->vbflags |= VB_302B; /* Deprecated */
2820 ivideo->vbflags2 |= VB2_302B;
2821 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2825 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2826 inSISIDXREG(SISCR, 0x37, reg);
2827 reg &= SIS_EXTERNAL_CHIP_MASK;
2829 if(ivideo->sisvga_engine == SIS_300_VGA) {
2830 #ifdef CONFIG_FB_SIS_300
2832 case SIS_EXTERNAL_CHIP_LVDS:
2833 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2834 ivideo->vbflags2 |= VB2_LVDS;
2836 case SIS_EXTERNAL_CHIP_TRUMPION:
2837 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2838 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2840 case SIS_EXTERNAL_CHIP_CHRONTEL:
2841 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2842 ivideo->vbflags2 |= VB2_CHRONTEL;
2844 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2845 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2846 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2849 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2851 } else if(ivideo->chip < SIS_661) {
2852 #ifdef CONFIG_FB_SIS_315
2854 case SIS310_EXTERNAL_CHIP_LVDS:
2855 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2856 ivideo->vbflags2 |= VB2_LVDS;
2858 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2859 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2860 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2863 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2865 } else if(ivideo->chip >= SIS_661) {
2866 #ifdef CONFIG_FB_SIS_315
2867 inSISIDXREG(SISCR, 0x38, reg);
2871 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2872 ivideo->vbflags2 |= VB2_LVDS;
2875 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2876 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2879 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2880 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2883 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2886 if(ivideo->vbflags2 & VB2_LVDS) {
2887 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2889 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2890 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2892 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2893 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2895 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2896 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2900 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2901 SiS_SenseLCD(ivideo);
2902 SiS_Sense30x(ivideo);
2903 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2904 SiS_SenseCh(ivideo);
2908 /* ---------- Engine initialization routines ------------ */
2911 sisfb_engine_init(struct sis_video_info *ivideo)
2914 /* Initialize command queue (we use MMIO only) */
2916 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2918 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2919 MMIO_CMD_QUEUE_CAP |
2923 #ifdef CONFIG_FB_SIS_300
2924 if(ivideo->sisvga_engine == SIS_300_VGA) {
2928 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2930 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2933 tq_state |= (u8)(tqueue_pos >> 8);
2934 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2936 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2938 ivideo->caps |= TURBO_QUEUE_CAP;
2942 #ifdef CONFIG_FB_SIS_315
2943 if(ivideo->sisvga_engine == SIS_315_VGA) {
2944 u32 tempq = 0, templ;
2947 if(ivideo->chip == XGI_20) {
2948 switch(ivideo->cmdQueueSize) {
2950 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2954 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2957 switch(ivideo->cmdQueueSize) {
2958 case (4 * 1024 * 1024):
2959 temp = SIS_CMD_QUEUE_SIZE_4M;
2961 case (2 * 1024 * 1024):
2962 temp = SIS_CMD_QUEUE_SIZE_2M;
2964 case (1 * 1024 * 1024):
2965 temp = SIS_CMD_QUEUE_SIZE_1M;
2969 temp = SIS_CMD_QUEUE_SIZE_512k;
2973 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2974 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2976 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2977 /* Must disable dual pipe on XGI_40. Can't do
2978 * this in MMIO mode, because it requires
2979 * setting/clearing a bit in the MMIO fire trigger
2982 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2984 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2986 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2988 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2989 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2991 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2992 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2994 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2995 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2996 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2997 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2999 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
3001 sisfb_syncaccel(ivideo);
3003 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3008 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3009 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3011 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3012 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3014 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3015 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3017 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3021 ivideo->engineok = 1;
3024 static void __devinit
3025 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3030 inSISIDXREG(SISCR, 0x36, reg);
3032 if(ivideo->sisvga_engine == SIS_300_VGA) {
3033 ivideo->CRT2LCDType = sis300paneltype[reg];
3034 } else if(ivideo->chip >= SIS_661) {
3035 ivideo->CRT2LCDType = sis661paneltype[reg];
3037 ivideo->CRT2LCDType = sis310paneltype[reg];
3038 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3039 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3040 (ivideo->CRT2LCDType != LCD_320x240_3)) {
3041 ivideo->CRT2LCDType = LCD_320x240;
3046 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3047 /* For broken BIOSes: Assume 1024x768, RGB18 */
3048 ivideo->CRT2LCDType = LCD_1024x768;
3049 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3050 setSISIDXREG(SISCR,0x37,0xee,0x01);
3051 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3054 for(i = 0; i < SIS_LCD_NUMBER; i++) {
3055 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3056 ivideo->lcdxres = sis_lcd_data[i].xres;
3057 ivideo->lcdyres = sis_lcd_data[i].yres;
3058 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3063 #ifdef CONFIG_FB_SIS_300
3064 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3065 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3066 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3067 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3068 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
3069 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3070 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3071 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
3072 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3076 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3077 ivideo->lcdxres, ivideo->lcdyres);
3080 static void __devinit
3081 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3083 #ifdef CONFIG_FB_SIS_300
3084 /* Save the current PanelDelayCompensation if the LCD is currently used */
3085 if(ivideo->sisvga_engine == SIS_300_VGA) {
3086 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3088 inSISIDXREG(SISCR,0x30,tmp);
3090 /* Currently on LCD? If yes, read current pdc */
3091 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3092 ivideo->detectedpdc &= 0x3c;
3093 if(ivideo->SiS_Pr.PDC == -1) {
3094 /* Let option override detection */
3095 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3097 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3098 ivideo->detectedpdc);
3100 if((ivideo->SiS_Pr.PDC != -1) &&
3101 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3102 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3103 ivideo->SiS_Pr.PDC);
3109 #ifdef CONFIG_FB_SIS_315
3110 if(ivideo->sisvga_engine == SIS_315_VGA) {
3112 /* Try to find about LCDA */
3113 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3115 inSISIDXREG(SISPART1,0x13,tmp);
3117 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3118 ivideo->detectedlcda = 0x03;
3123 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3125 inSISIDXREG(SISCR,0x30,tmp);
3126 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3127 /* Currently on LCD? If yes, read current pdc */
3129 inSISIDXREG(SISPART1,0x2D,pdc);
3130 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3131 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3132 inSISIDXREG(SISPART1,0x35,pdc);
3133 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3134 inSISIDXREG(SISPART1,0x20,pdc);
3135 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3136 if(ivideo->newrom) {
3137 /* New ROM invalidates other PDC resp. */
3138 if(ivideo->detectedlcda != 0xff) {
3139 ivideo->detectedpdc = 0xff;
3141 ivideo->detectedpdca = 0xff;
3144 if(ivideo->SiS_Pr.PDC == -1) {
3145 if(ivideo->detectedpdc != 0xff) {
3146 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3149 if(ivideo->SiS_Pr.PDCA == -1) {
3150 if(ivideo->detectedpdca != 0xff) {
3151 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3154 if(ivideo->detectedpdc != 0xff) {
3156 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3157 ivideo->detectedpdc);
3159 if(ivideo->detectedpdca != 0xff) {
3161 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3162 ivideo->detectedpdca);
3167 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3168 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3169 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3170 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3171 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3172 ivideo->SiS_Pr.HaveEMI = TRUE;
3173 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3174 ivideo->SiS_Pr.HaveEMILCD = TRUE;
3179 /* Let user override detected PDCs (all bridges) */
3180 if(ivideo->vbflags2 & VB2_30xBLV) {
3181 if((ivideo->SiS_Pr.PDC != -1) &&
3182 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3183 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3184 ivideo->SiS_Pr.PDC);
3186 if((ivideo->SiS_Pr.PDCA != -1) &&
3187 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3188 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3189 ivideo->SiS_Pr.PDCA);
3197 /* -------------------- Memory manager routines ---------------------- */
3199 static u32 __devinit
3200 sisfb_getheapstart(struct sis_video_info *ivideo)
3202 u32 ret = ivideo->sisfb_parm_mem * 1024;
3203 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3206 /* Calculate heap start = end of memory for console
3208 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3209 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3211 * On 76x in UMA+LFB mode, the layout is as follows:
3212 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3213 * where the heap is the entire UMA area, eventually
3214 * into the LFB area if the given mem parameter is
3215 * higher than the size of the UMA memory.
3217 * Basically given by "mem" parameter
3219 * maximum = videosize - cmd_queue - hwcursor
3220 * (results in a heap of size 0)
3221 * default = SiS 300: depends on videosize
3222 * SiS 315/330/340/XGI: 32k below max
3225 if(ivideo->sisvga_engine == SIS_300_VGA) {
3226 if(ivideo->video_size > 0x1000000) {
3228 } else if(ivideo->video_size > 0x800000) {
3233 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3236 def = maxoffs - 0x8000;
3239 /* Use default for secondary card for now (FIXME) */
3240 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3246 static u32 __devinit
3247 sisfb_getheapsize(struct sis_video_info *ivideo)
3249 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3252 if(ivideo->UMAsize && ivideo->LFBsize) {
3253 if( (!ivideo->sisfb_parm_mem) ||
3254 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3255 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3256 ret = ivideo->UMAsize;
3257 max -= ivideo->UMAsize;
3259 ret = max - (ivideo->sisfb_parm_mem * 1024);
3260 max = ivideo->sisfb_parm_mem * 1024;
3262 ivideo->video_offset = ret;
3263 ivideo->sisfb_mem = max;
3265 ret = max - ivideo->heapstart;
3266 ivideo->sisfb_mem = ivideo->heapstart;
3272 static int __devinit
3273 sisfb_heap_init(struct sis_video_info *ivideo)
3277 ivideo->video_offset = 0;
3278 if(ivideo->sisfb_parm_mem) {
3279 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3280 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3281 ivideo->sisfb_parm_mem = 0;
3285 ivideo->heapstart = sisfb_getheapstart(ivideo);
3286 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3288 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3289 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3291 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3292 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3294 ivideo->sisfb_heap.vinfo = ivideo;
3296 ivideo->sisfb_heap.poha_chain = NULL;
3297 ivideo->sisfb_heap.poh_freelist = NULL;
3299 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3303 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3304 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3305 poh->size = ivideo->sisfb_heap_size;
3306 poh->offset = ivideo->heapstart;
3308 ivideo->sisfb_heap.oh_free.poh_next = poh;
3309 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3310 ivideo->sisfb_heap.oh_free.size = 0;
3311 ivideo->sisfb_heap.max_freesize = poh->size;
3313 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3314 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3315 ivideo->sisfb_heap.oh_used.size = SENTINEL;
3317 if(ivideo->cardnumber == 0) {
3318 /* For the first card, make this heap the "global" one
3319 * for old DRM (which could handle only one card)
3321 sisfb_heap = &ivideo->sisfb_heap;
3327 static struct SIS_OH *
3328 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3330 struct SIS_OHALLOC *poha;
3335 if(memheap->poh_freelist == NULL) {
3336 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3340 poha->poha_next = memheap->poha_chain;
3341 memheap->poha_chain = poha;
3343 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3345 poh = &poha->aoh[0];
3346 for(i = cOhs - 1; i != 0; i--) {
3347 poh->poh_next = poh + 1;
3351 poh->poh_next = NULL;
3352 memheap->poh_freelist = &poha->aoh[0];
3355 poh = memheap->poh_freelist;
3356 memheap->poh_freelist = poh->poh_next;
3361 static struct SIS_OH *
3362 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3364 struct SIS_OH *pohThis;
3365 struct SIS_OH *pohRoot;
3368 if(size > memheap->max_freesize) {
3369 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3370 (unsigned int) size / 1024);
3374 pohThis = memheap->oh_free.poh_next;
3376 while(pohThis != &memheap->oh_free) {
3377 if(size <= pohThis->size) {
3381 pohThis = pohThis->poh_next;
3385 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3386 (unsigned int) size / 1024);
3390 if(size == pohThis->size) {
3392 sisfb_delete_node(pohThis);
3394 pohRoot = sisfb_poh_new_node(memheap);
3398 pohRoot->offset = pohThis->offset;
3399 pohRoot->size = size;
3401 pohThis->offset += size;
3402 pohThis->size -= size;
3405 memheap->max_freesize -= size;
3407 pohThis = &memheap->oh_used;
3408 sisfb_insert_node(pohThis, pohRoot);
3414 sisfb_delete_node(struct SIS_OH *poh)
3416 poh->poh_prev->poh_next = poh->poh_next;
3417 poh->poh_next->poh_prev = poh->poh_prev;
3421 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3423 struct SIS_OH *pohTemp = pohList->poh_next;
3425 pohList->poh_next = poh;
3426 pohTemp->poh_prev = poh;
3428 poh->poh_prev = pohList;
3429 poh->poh_next = pohTemp;
3432 static struct SIS_OH *
3433 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3435 struct SIS_OH *pohThis;
3436 struct SIS_OH *poh_freed;
3437 struct SIS_OH *poh_prev;
3438 struct SIS_OH *poh_next;
3443 poh_freed = memheap->oh_used.poh_next;
3445 while(poh_freed != &memheap->oh_used) {
3446 if(poh_freed->offset == base) {
3451 poh_freed = poh_freed->poh_next;
3457 memheap->max_freesize += poh_freed->size;
3459 poh_prev = poh_next = NULL;
3460 ulUpper = poh_freed->offset + poh_freed->size;
3461 ulLower = poh_freed->offset;
3463 pohThis = memheap->oh_free.poh_next;
3465 while(pohThis != &memheap->oh_free) {
3466 if(pohThis->offset == ulUpper) {
3468 } else if((pohThis->offset + pohThis->size) == ulLower) {
3471 pohThis = pohThis->poh_next;
3474 sisfb_delete_node(poh_freed);
3476 if(poh_prev && poh_next) {
3477 poh_prev->size += (poh_freed->size + poh_next->size);
3478 sisfb_delete_node(poh_next);
3479 sisfb_free_node(memheap, poh_freed);
3480 sisfb_free_node(memheap, poh_next);
3485 poh_prev->size += poh_freed->size;
3486 sisfb_free_node(memheap, poh_freed);
3491 poh_next->size += poh_freed->size;
3492 poh_next->offset = poh_freed->offset;
3493 sisfb_free_node(memheap, poh_freed);
3497 sisfb_insert_node(&memheap->oh_free, poh_freed);
3503 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3508 poh->poh_next = memheap->poh_freelist;
3509 memheap->poh_freelist = poh;
3513 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3515 struct SIS_OH *poh = NULL;
3517 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3518 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3521 req->offset = req->size = 0;
3522 DPRINTK("sisfb: Video RAM allocation failed\n");
3524 req->offset = poh->offset;
3525 req->size = poh->size;
3526 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3527 (poh->offset + ivideo->video_vbase));
3532 sis_malloc(struct sis_memreq *req)
3534 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3536 if(&ivideo->sisfb_heap == sisfb_heap)
3537 sis_int_malloc(ivideo, req);
3539 req->offset = req->size = 0;
3543 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3545 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3547 sis_int_malloc(ivideo, req);
3550 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3553 sis_int_free(struct sis_video_info *ivideo, u32 base)
3557 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3560 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3563 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3564 (unsigned int) base);
3571 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3573 sis_int_free(ivideo, base);
3577 sis_free_new(struct pci_dev *pdev, u32 base)
3579 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3581 sis_int_free(ivideo, base);
3584 /* --------------------- SetMode routines ------------------------- */
3587 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3591 /* Check if MMIO and engines are enabled,
3592 * and sync in case they are. Can't use
3593 * ivideo->accel here, as this might have
3594 * been changed before this is called.
3596 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3597 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3598 /* MMIO and 2D/3D engine enabled? */
3599 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3600 #ifdef CONFIG_FB_SIS_300
3601 if(ivideo->sisvga_engine == SIS_300_VGA) {
3602 /* Don't care about TurboQueue. It's
3603 * enough to know that the engines
3606 sisfb_syncaccel(ivideo);
3609 #ifdef CONFIG_FB_SIS_315
3610 if(ivideo->sisvga_engine == SIS_315_VGA) {
3611 /* Check that any queue mode is
3612 * enabled, and that the queue
3613 * is not in the state of "reset"
3615 inSISIDXREG(SISSR, 0x26, cr30);
3616 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3617 sisfb_syncaccel(ivideo);
3625 sisfb_pre_setmode(struct sis_video_info *ivideo)
3627 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3630 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3632 outSISIDXREG(SISSR, 0x05, 0x86);
3634 inSISIDXREG(SISCR, 0x31, cr31);
3638 cr33 = ivideo->rate_idx & 0x0F;
3640 #ifdef CONFIG_FB_SIS_315
3641 if(ivideo->sisvga_engine == SIS_315_VGA) {
3642 if(ivideo->chip >= SIS_661) {
3643 inSISIDXREG(SISCR, 0x38, cr38);
3644 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3647 inSISIDXREG(SISCR, tvregnum, cr38);
3648 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3652 #ifdef CONFIG_FB_SIS_300
3653 if(ivideo->sisvga_engine == SIS_300_VGA) {
3655 inSISIDXREG(SISCR, tvregnum, cr38);
3659 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3660 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3661 ivideo->curFSTN = ivideo->curDSTN = 0;
3663 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3666 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3667 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3668 #ifdef CONFIG_FB_SIS_315
3669 if(ivideo->chip >= SIS_661) {
3671 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3672 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3673 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3674 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3676 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3677 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3678 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3680 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3681 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3682 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3684 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3687 } else if((ivideo->vbflags & TV_HIVISION) &&
3688 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3689 if(ivideo->chip >= SIS_661) {
3695 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3698 ivideo->currentvbflags |= TV_HIVISION;
3699 } else if(ivideo->vbflags & TV_SCART) {
3700 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3703 ivideo->currentvbflags |= TV_SCART;
3705 if(ivideo->vbflags & TV_SVIDEO) {
3706 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3707 ivideo->currentvbflags |= TV_SVIDEO;
3709 if(ivideo->vbflags & TV_AVIDEO) {
3710 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3711 ivideo->currentvbflags |= TV_AVIDEO;
3714 cr31 |= SIS_DRIVER_MODE;
3716 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3717 if(ivideo->vbflags & TV_PAL) {
3718 cr31 |= 0x01; cr35 |= 0x01;
3719 ivideo->currentvbflags |= TV_PAL;
3720 if(ivideo->vbflags & TV_PALM) {
3721 cr38 |= 0x40; cr35 |= 0x04;
3722 ivideo->currentvbflags |= TV_PALM;
3723 } else if(ivideo->vbflags & TV_PALN) {
3724 cr38 |= 0x80; cr35 |= 0x08;
3725 ivideo->currentvbflags |= TV_PALN;
3728 cr31 &= ~0x01; cr35 &= ~0x01;
3729 ivideo->currentvbflags |= TV_NTSC;
3730 if(ivideo->vbflags & TV_NTSCJ) {
3731 cr38 |= 0x40; cr35 |= 0x02;
3732 ivideo->currentvbflags |= TV_NTSCJ;
3739 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3740 cr31 |= SIS_DRIVER_MODE;
3741 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3742 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3743 ivideo->curFSTN = ivideo->sisfb_fstn;
3744 ivideo->curDSTN = ivideo->sisfb_dstn;
3748 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3749 cr31 |= SIS_DRIVER_MODE;
3750 if(ivideo->sisfb_nocrt2rate) {
3751 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3753 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3757 default: /* disable CRT2 */
3759 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3762 outSISIDXREG(SISCR, 0x30, cr30);
3763 outSISIDXREG(SISCR, 0x33, cr33);
3765 if(ivideo->chip >= SIS_661) {
3766 #ifdef CONFIG_FB_SIS_315
3767 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3768 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3769 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3770 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3772 } else if(ivideo->chip != SIS_300) {
3773 outSISIDXREG(SISCR, tvregnum, cr38);
3775 outSISIDXREG(SISCR, 0x31, cr31);
3777 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3779 sisfb_check_engine_and_sync(ivideo);
3782 /* Fix SR11 for 661 and later */
3783 #ifdef CONFIG_FB_SIS_315
3785 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3789 if(ivideo->chip >= SIS_661) {
3790 inSISIDXREG(SISSR,0x11,tmpreg);
3792 inSISIDXREG(SISSR,0x3e,tmpreg);
3793 tmpreg = (tmpreg + 1) & 0xff;
3794 outSISIDXREG(SISSR,0x3e,tmpreg);
3795 inSISIDXREG(SISSR,0x11,tmpreg);
3798 andSISIDXREG(SISSR,0x11,0x0f);
3805 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3807 if(val > 32) val = 32;
3808 if(val < -32) val = -32;
3809 ivideo->tvxpos = val;
3811 if(ivideo->sisfblocked) return;
3812 if(!ivideo->modechanged) return;
3814 if(ivideo->currentvbflags & CRT2_TV) {
3816 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3818 int x = ivideo->tvx;
3820 switch(ivideo->chronteltype) {
3824 outSISIDXREG(SISSR,0x05,0x86);
3825 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3826 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3829 /* Not supported by hardware */
3833 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3835 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3836 unsigned short temp;
3838 p2_1f = ivideo->p2_1f;
3839 p2_20 = ivideo->p2_20;
3840 p2_2b = ivideo->p2_2b;
3841 p2_42 = ivideo->p2_42;
3842 p2_43 = ivideo->p2_43;
3844 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3846 p2_1f = temp & 0xff;
3847 p2_20 = (temp & 0xf00) >> 4;
3848 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3849 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3851 p2_43 = temp & 0xff;
3852 p2_42 = (temp & 0xf00) >> 4;
3853 outSISIDXREG(SISPART2,0x1f,p2_1f);
3854 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3855 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3856 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3857 outSISIDXREG(SISPART2,0x43,p2_43);
3863 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3865 if(val > 32) val = 32;
3866 if(val < -32) val = -32;
3867 ivideo->tvypos = val;
3869 if(ivideo->sisfblocked) return;
3870 if(!ivideo->modechanged) return;
3872 if(ivideo->currentvbflags & CRT2_TV) {
3874 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3876 int y = ivideo->tvy;
3878 switch(ivideo->chronteltype) {
3882 outSISIDXREG(SISSR,0x05,0x86);
3883 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3884 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3887 /* Not supported by hardware */
3891 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3895 p2_01 = ivideo->p2_01;
3896 p2_02 = ivideo->p2_02;
3900 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3901 while((p2_01 <= 0) || (p2_02 <= 0)) {
3906 outSISIDXREG(SISPART2,0x01,p2_01);
3907 outSISIDXREG(SISPART2,0x02,p2_02);
3913 sisfb_post_setmode(struct sis_video_info *ivideo)
3915 BOOLEAN crt1isoff = FALSE;
3916 BOOLEAN doit = TRUE;
3917 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3920 #ifdef CONFIG_FB_SIS_315
3924 outSISIDXREG(SISSR, 0x05, 0x86);
3926 #ifdef CONFIG_FB_SIS_315
3927 sisfb_fixup_SR11(ivideo);
3930 /* Now we actually HAVE changed the display mode */
3931 ivideo->modechanged = 1;
3933 /* We can't switch off CRT1 if bridge is in slave mode */
3934 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3935 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3937 ivideo->sisfb_crt1off = 0;
3939 #ifdef CONFIG_FB_SIS_300
3940 if(ivideo->sisvga_engine == SIS_300_VGA) {
3941 if((ivideo->sisfb_crt1off) && (doit)) {
3948 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3951 #ifdef CONFIG_FB_SIS_315
3952 if(ivideo->sisvga_engine == SIS_315_VGA) {
3953 if((ivideo->sisfb_crt1off) && (doit)) {
3962 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3963 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3968 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3969 ivideo->currentvbflags |= VB_SINGLE_MODE;
3971 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3972 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3973 ivideo->currentvbflags |= VB_MIRROR_MODE;
3975 ivideo->currentvbflags |= VB_SINGLE_MODE;
3979 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3981 if(ivideo->currentvbflags & CRT2_TV) {
3982 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3983 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3984 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3985 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3986 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3987 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3988 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3989 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3990 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3991 if(ivideo->chronteltype == 1) {
3992 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3993 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3994 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3995 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
4000 if(ivideo->tvxpos) {
4001 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
4003 if(ivideo->tvypos) {
4004 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
4007 /* Eventually sync engines */
4008 sisfb_check_engine_and_sync(ivideo);
4010 /* (Re-)Initialize chip engines */
4012 sisfb_engine_init(ivideo);
4014 ivideo->engineok = 0;
4019 sisfb_reset_mode(struct sis_video_info *ivideo)
4021 if(sisfb_set_mode(ivideo, 0))
4024 sisfb_set_pitch(ivideo);
4025 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4026 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
4032 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4036 switch(sisfb_command->sisfb_cmd) {
4037 case SISFB_CMD_GETVBFLAGS:
4038 if(!ivideo->modechanged) {
4039 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4041 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4042 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4043 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
4046 case SISFB_CMD_SWITCHCRT1:
4047 /* arg[0]: 0 = off, 1 = on, 99 = query */
4048 if(!ivideo->modechanged) {
4049 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4050 } else if(sisfb_command->sisfb_arg[0] == 99) {
4052 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4053 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4054 } else if(ivideo->sisfblocked) {
4055 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4056 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4057 (sisfb_command->sisfb_arg[0] == 0)) {
4058 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4060 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4061 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4062 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4063 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4064 ivideo->sisfb_crt1off = mycrt1off;
4065 if(sisfb_reset_mode(ivideo)) {
4066 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
4069 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4074 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4075 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4076 sisfb_command->sisfb_cmd);
4081 SISINITSTATIC int __init
4082 sisfb_setup(char *options)
4086 sisfb_setdefaultparms();
4088 if(!options || !(*options))
4091 while((this_opt = strsep(&options, ",")) != NULL) {
4093 if(!(*this_opt)) continue;
4095 if(!strnicmp(this_opt, "off", 3)) {
4097 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4098 /* Need to check crt2 type first for fstn/dstn */
4099 sisfb_search_crt2type(this_opt + 14);
4100 } else if(!strnicmp(this_opt, "tvmode:",7)) {
4101 sisfb_search_tvstd(this_opt + 7);
4102 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4103 sisfb_search_tvstd(this_opt + 11);
4104 } else if(!strnicmp(this_opt, "mode:", 5)) {
4105 sisfb_search_mode(this_opt + 5, FALSE);
4106 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4107 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4108 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4109 } else if(!strnicmp(this_opt, "inverse", 7)) {
4111 /* fb_invert_cmaps(); */
4112 } else if(!strnicmp(this_opt, "font:", 5)) {
4113 if(strlen(this_opt + 5) < 40) {
4114 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4115 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4118 } else if(!strnicmp(this_opt, "rate:", 5)) {
4119 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4120 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4121 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4122 } else if(!strnicmp(this_opt, "mem:",4)) {
4123 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4124 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4125 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4126 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4127 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4128 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4130 } else if(!strnicmp(this_opt, "accel", 5)) {
4132 } else if(!strnicmp(this_opt, "noypan", 6)) {
4134 } else if(!strnicmp(this_opt, "ypan", 4)) {
4136 } else if(!strnicmp(this_opt, "nomax", 5)) {
4138 } else if(!strnicmp(this_opt, "max", 3)) {
4140 } else if(!strnicmp(this_opt, "userom:", 7)) {
4141 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4142 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4143 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4144 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4145 sisfb_nocrt2rate = 1;
4146 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4147 unsigned long temp = 2;
4148 temp = simple_strtoul(this_opt + 9, NULL, 0);
4149 if((temp == 0) || (temp == 1)) {
4150 sisfb_scalelcd = temp ^ 1;
4152 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4154 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4155 if((temp >= -32) && (temp <= 32)) {
4156 sisfb_tvxposoffset = temp;
4158 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4160 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4161 if((temp >= -32) && (temp <= 32)) {
4162 sisfb_tvyposoffset = temp;
4164 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4165 sisfb_search_specialtiming(this_opt + 14);
4166 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4168 temp = simple_strtoul(this_opt + 7, NULL, 0);
4169 if((temp >= 0) && (temp <= 3)) {
4170 sisfb_lvdshl = temp;
4172 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4173 sisfb_search_mode(this_opt, TRUE);
4174 #if !defined(__i386__) && !defined(__x86_64__)
4175 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4176 sisfb_resetcard = 1;
4177 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4178 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4181 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4190 static int __devinit
4191 sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4196 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4199 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4200 if(romptr > (0x10000 - 8))
4203 rom = rom_base + romptr;
4205 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4206 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4209 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4212 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4218 static unsigned char * __devinit
4219 sisfb_find_rom(struct pci_dev *pdev)
4221 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4222 SIS_IOTYPE1 *rom_base;
4223 unsigned char *myrombase = NULL;
4225 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4228 /* First, try the official pci ROM functions (except
4229 * on integrated chipsets which have no ROM).
4232 if(!ivideo->nbridge) {
4234 if((rom_base = pci_map_rom(pdev, &romsize))) {
4236 if(sisfb_check_rom(rom_base, ivideo)) {
4238 if((myrombase = vmalloc(65536))) {
4240 /* Work around bug in pci/rom.c: Folks forgot to check
4241 * whether the size retrieved from the BIOS image eventually
4242 * is larger than the mapped size
4244 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4245 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4247 memcpy_fromio(myrombase, rom_base,
4248 (romsize > 65536) ? 65536 : romsize);
4251 pci_unmap_rom(pdev, rom_base);
4255 if(myrombase) return myrombase;
4258 /* Otherwise do it the conventional way. */
4260 #if defined(__i386__) || defined(__x86_64__)
4262 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4264 rom_base = ioremap(temp, 65536);
4268 if(!sisfb_check_rom(rom_base, ivideo)) {
4273 if((myrombase = vmalloc(65536)))
4274 memcpy_fromio(myrombase, rom_base, 65536);
4283 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4284 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4285 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4287 rom_base = ioremap(ivideo->video_base, 65536);
4289 if(sisfb_check_rom(rom_base, ivideo)) {
4290 if((myrombase = vmalloc(65536)))
4291 memcpy_fromio(myrombase, rom_base, 65536);
4296 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4303 static void __devinit
4304 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4307 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4309 if(!ivideo->video_vbase) {
4311 "sisfb: Unable to map maximum video RAM for size detection\n");
4313 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4315 if((*mapsize) < (min << 20))
4318 if(ivideo->video_vbase) {
4320 "sisfb: Video RAM size detection limited to %dMB\n",
4321 (int)((*mapsize) >> 20));
4326 #ifdef CONFIG_FB_SIS_300
4327 static int __devinit
4328 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4330 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4331 unsigned short temp;
4335 andSISIDXREG(SISSR, 0x15, 0xFB);
4336 orSISIDXREG(SISSR, 0x15, 0x04);
4337 outSISIDXREG(SISSR, 0x13, 0x00);
4338 outSISIDXREG(SISSR, 0x14, 0xBF);
4340 for(i = 0; i < 2; i++) {
4342 for(j = 0; j < 4; j++) {
4343 writew(temp, FBAddress);
4344 if(readw(FBAddress) == temp)
4346 orSISIDXREG(SISSR, 0x3c, 0x01);
4347 inSISIDXREG(SISSR, 0x05, reg);
4348 inSISIDXREG(SISSR, 0x05, reg);
4349 andSISIDXREG(SISSR, 0x3c, 0xfe);
4350 inSISIDXREG(SISSR, 0x05, reg);
4351 inSISIDXREG(SISSR, 0x05, reg);
4356 writel(0x01234567L, FBAddress);
4357 writel(0x456789ABL, (FBAddress + 4));
4358 writel(0x89ABCDEFL, (FBAddress + 8));
4359 writel(0xCDEF0123L, (FBAddress + 12));
4361 inSISIDXREG(SISSR, 0x3b, reg);
4363 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4364 return 4; /* Channel A 128bit */
4367 if(readl((FBAddress + 4)) == 0x456789ABL)
4368 return 2; /* Channel B 64bit */
4370 return 1; /* 32bit */
4373 static int __devinit
4374 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4375 int PseudoRankCapacity, int PseudoAdrPinCount,
4376 unsigned int mapsize)
4378 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4379 unsigned short sr14;
4380 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4381 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4382 static const unsigned short SiS_DRAMType[17][5] = {
4383 {0x0C,0x0A,0x02,0x40,0x39},
4384 {0x0D,0x0A,0x01,0x40,0x48},
4385 {0x0C,0x09,0x02,0x20,0x35},
4386 {0x0D,0x09,0x01,0x20,0x44},
4387 {0x0C,0x08,0x02,0x10,0x31},
4388 {0x0D,0x08,0x01,0x10,0x40},
4389 {0x0C,0x0A,0x01,0x20,0x34},
4390 {0x0C,0x09,0x01,0x08,0x32},
4391 {0x0B,0x08,0x02,0x08,0x21},
4392 {0x0C,0x08,0x01,0x08,0x30},
4393 {0x0A,0x08,0x02,0x04,0x11},
4394 {0x0B,0x0A,0x01,0x10,0x28},
4395 {0x09,0x08,0x02,0x02,0x01},
4396 {0x0B,0x09,0x01,0x08,0x24},
4397 {0x0B,0x08,0x01,0x04,0x20},
4398 {0x0A,0x08,0x01,0x02,0x10},
4399 {0x09,0x08,0x01,0x01,0x00}
4402 for(k = 0; k <= 16; k++) {
4404 RankCapacity = buswidth * SiS_DRAMType[k][3];
4406 if(RankCapacity != PseudoRankCapacity)
4409 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4412 BankNumHigh = RankCapacity * 16 * iteration - 1;
4413 if(iteration == 3) { /* Rank No */
4414 BankNumMid = RankCapacity * 16 - 1;
4416 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4419 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4420 PhysicalAdrHigh = BankNumHigh;
4421 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4422 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4424 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4425 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4426 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4427 if(buswidth == 4) sr14 |= 0x80;
4428 else if(buswidth == 2) sr14 |= 0x40;
4429 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4430 outSISIDXREG(SISSR, 0x14, sr14);
4435 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4436 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4437 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4438 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4442 writew(((unsigned short)PhysicalAdrHigh),
4443 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4444 writew(((unsigned short)BankNumMid),
4445 (FBAddr + BankNumMid + PhysicalAdrHigh));
4446 writew(((unsigned short)PhysicalAdrHalfPage),
4447 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4448 writew(((unsigned short)PhysicalAdrOtherPage),
4449 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4452 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4459 static void __devinit
4460 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4462 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4464 int PseudoRankCapacity, PseudoAdrPinCount;
4466 buswidth = sisfb_post_300_buswidth(ivideo);
4468 for(i = 6; i >= 0; i--) {
4469 PseudoRankCapacity = 1 << i;
4470 for(j = 4; j >= 1; j--) {
4471 PseudoAdrPinCount = 15 - j;
4472 if((PseudoRankCapacity * j) <= 64) {
4473 if(sisfb_post_300_rwtest(ivideo,
4485 static void __devinit
4486 sisfb_post_sis300(struct pci_dev *pdev)
4488 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4489 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4490 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4491 u16 index, rindex, memtype = 0;
4492 unsigned int mapsize;
4494 if(!ivideo->SiS_Pr.UseROM)
4497 outSISIDXREG(SISSR, 0x05, 0x86);
4500 if(bios[0x52] & 0x80) {
4501 memtype = bios[0x52];
4503 inSISIDXREG(SISSR, 0x3a, memtype);
4508 v3 = 0x80; v6 = 0x80;
4509 if(ivideo->revision_id <= 0x13) {
4510 v1 = 0x44; v2 = 0x42;
4511 v4 = 0x44; v5 = 0x42;
4513 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4514 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4516 index = memtype * 5;
4517 rindex = index + 0x54;
4518 v1 = bios[rindex++];
4519 v2 = bios[rindex++];
4520 v3 = bios[rindex++];
4521 rindex = index + 0x7c;
4522 v4 = bios[rindex++];
4523 v5 = bios[rindex++];
4524 v6 = bios[rindex++];
4527 outSISIDXREG(SISSR, 0x28, v1);
4528 outSISIDXREG(SISSR, 0x29, v2);
4529 outSISIDXREG(SISSR, 0x2a, v3);
4530 outSISIDXREG(SISSR, 0x2e, v4);
4531 outSISIDXREG(SISSR, 0x2f, v5);
4532 outSISIDXREG(SISSR, 0x30, v6);
4537 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4539 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4541 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4542 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4546 v2 = bios[memtype + 8];
4547 v3 = bios[memtype + 16];
4548 v4 = bios[memtype + 24];
4549 v5 = bios[memtype + 32];
4550 v6 = bios[memtype + 40];
4551 v7 = bios[memtype + 48];
4552 v8 = bios[memtype + 56];
4554 if(ivideo->revision_id >= 0x80)
4556 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4557 outSISIDXREG(SISSR, 0x16, v2);
4558 outSISIDXREG(SISSR, 0x17, v3);
4559 outSISIDXREG(SISSR, 0x18, v4);
4560 outSISIDXREG(SISSR, 0x19, v5);
4561 outSISIDXREG(SISSR, 0x1a, v6);
4562 outSISIDXREG(SISSR, 0x1b, v7);
4563 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4564 andSISIDXREG(SISSR, 0x15 ,0xfb);
4565 orSISIDXREG(SISSR, 0x15, 0x04);
4567 if(bios[0x53] & 0x02) {
4568 orSISIDXREG(SISSR, 0x19, 0x20);
4571 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4572 if(ivideo->revision_id >= 0x80)
4574 outSISIDXREG(SISSR, 0x1f, v1);
4575 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4576 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4582 outSISIDXREG(SISSR, 0x23, v1);
4583 outSISIDXREG(SISSR, 0x24, v2);
4584 outSISIDXREG(SISSR, 0x25, v3);
4585 outSISIDXREG(SISSR, 0x21, 0x84);
4586 outSISIDXREG(SISSR, 0x22, 0x00);
4587 outSISIDXREG(SISCR, 0x37, 0x00);
4588 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4589 outSISIDXREG(SISPART1, 0x00, 0x00);
4590 v1 = 0x40; v2 = 0x11;
4595 outSISIDXREG(SISPART1, 0x02, v1);
4597 if(ivideo->revision_id >= 0x80)
4600 inSISIDXREG(SISPART4, 0x00, reg);
4601 if((reg == 1) || (reg == 2)) {
4602 outSISIDXREG(SISCR, 0x37, 0x02);
4603 outSISIDXREG(SISPART2, 0x00, 0x1c);
4604 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4605 if(ivideo->SiS_Pr.UseROM) {
4610 outSISIDXREG(SISPART4, 0x0d, v4);
4611 outSISIDXREG(SISPART4, 0x0e, v5);
4612 outSISIDXREG(SISPART4, 0x10, v6);
4613 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4614 inSISIDXREG(SISPART4, 0x01, reg);
4616 inSISIDXREG(SISPART4, 0x23, reg);
4619 outSISIDXREG(SISPART4, 0x23, reg);
4624 outSISIDXREG(SISSR, 0x32, v2);
4626 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4628 inSISIDXREG(SISSR, 0x16, reg);
4630 outSISIDXREG(SISCR, 0x35, reg);
4631 outSISIDXREG(SISCR, 0x83, 0x00);
4632 #if !defined(__i386__) && !defined(__x86_64__)
4633 if(sisfb_videoram) {
4634 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4635 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4636 outSISIDXREG(SISSR, 0x14, reg);
4639 /* Need to map max FB size for finding out about RAM size */
4641 sisfb_post_map_vram(ivideo, &mapsize, 4);
4643 if(ivideo->video_vbase) {
4644 sisfb_post_300_ramsize(pdev, mapsize);
4645 iounmap(ivideo->video_vbase);
4648 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4649 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4650 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4652 #if !defined(__i386__) && !defined(__x86_64__)
4659 inSISIDXREG(SISSR, 0x3a, reg);
4660 if((reg & 0x30) == 0x30) {
4661 v1 = 0x04; /* PCI */
4664 v1 = 0x14; /* AGP */
4668 outSISIDXREG(SISSR, 0x21, v1);
4669 outSISIDXREG(SISSR, 0x22, v2);
4672 sisfb_sense_crt1(ivideo);
4674 /* Set default mode, don't clear screen */
4675 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4676 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4677 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4678 ivideo->curFSTN = ivideo->curDSTN = 0;
4679 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4680 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4682 outSISIDXREG(SISSR, 0x05, 0x86);
4685 orSISIDXREG(SISSR, 0x01, 0x20);
4687 /* Save mode number in CR34 */
4688 outSISIDXREG(SISCR, 0x34, 0x2e);
4690 /* Let everyone know what the current mode is */
4691 ivideo->modeprechange = 0x2e;
4695 #ifdef CONFIG_FB_SIS_315
4697 static void __devinit
4698 sisfb_post_sis315330(struct pci_dev *pdev)
4704 static void __devinit
4705 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4710 for(i = 0; i <= (delay * 10 * 36); i++) {
4711 inSISIDXREG(SISSR, 0x05, reg);
4716 static int __devinit
4717 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4718 unsigned short pcivendor)
4720 struct pci_dev *pdev = NULL;
4721 unsigned short temp;
4724 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4725 temp = pdev->vendor;
4726 SIS_PCI_PUT_DEVICE(pdev);
4727 if(temp == pcivendor) {
4736 static int __devinit
4737 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4738 unsigned int enda, unsigned int mapsize)
4743 writel(0, ivideo->video_vbase);
4745 for(i = starta; i <= enda; i++) {
4748 writel(pos, ivideo->video_vbase + pos);
4751 sisfb_post_xgi_delay(ivideo, 150);
4753 if(readl(ivideo->video_vbase) != 0)
4756 for(i = starta; i <= enda; i++) {
4759 if(readl(ivideo->video_vbase + pos) != pos)
4768 static void __devinit
4769 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4771 unsigned int buswidth, ranksize, channelab, mapsize;
4774 static const u8 dramsr13[12 * 5] = {
4775 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4776 0x02, 0x0e, 0x0a, 0x40, 0x59,
4777 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4778 0x02, 0x0e, 0x09, 0x20, 0x55,
4779 0x02, 0x0d, 0x0a, 0x20, 0x49,
4780 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4781 0x02, 0x0e, 0x08, 0x10, 0x51,
4782 0x02, 0x0d, 0x09, 0x10, 0x45,
4783 0x02, 0x0c, 0x0a, 0x10, 0x39,
4784 0x02, 0x0d, 0x08, 0x08, 0x41,
4785 0x02, 0x0c, 0x09, 0x08, 0x35,
4786 0x02, 0x0c, 0x08, 0x04, 0x31
4788 static const u8 dramsr13_4[4 * 5] = {
4789 0x02, 0x0d, 0x09, 0x40, 0x45,
4790 0x02, 0x0c, 0x09, 0x20, 0x35,
4791 0x02, 0x0c, 0x08, 0x10, 0x31,
4792 0x02, 0x0b, 0x08, 0x08, 0x21
4795 /* Enable linear mode, disable 0xa0000 address decoding */
4796 /* We disable a0000 address decoding, because
4797 * - if running on x86, if the card is disabled, it means
4798 * that another card is in the system. We don't want
4799 * to interphere with that primary card's textmode.
4800 * - if running on non-x86, there usually is no VGA window
4803 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4805 /* Need to map max FB size for finding out about RAM size */
4806 mapsize = 256 << 20;
4807 sisfb_post_map_vram(ivideo, &mapsize, 32);
4809 if(!ivideo->video_vbase) {
4810 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4811 outSISIDXREG(SISSR, 0x13, 0x35);
4812 outSISIDXREG(SISSR, 0x14, 0x41);
4817 /* Non-interleaving */
4818 outSISIDXREG(SISSR, 0x15, 0x00);
4820 outSISIDXREG(SISSR, 0x1c, 0x00);
4822 if(ivideo->chip == XGI_20) {
4825 inSISIDXREG(SISCR, 0x97, reg);
4826 if(!(reg & 0x01)) { /* Single 32/16 */
4828 outSISIDXREG(SISSR, 0x13, 0xb1);
4829 outSISIDXREG(SISSR, 0x14, 0x52);
4830 sisfb_post_xgi_delay(ivideo, 1);
4832 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4835 outSISIDXREG(SISSR, 0x13, 0x31);
4836 outSISIDXREG(SISSR, 0x14, 0x42);
4837 sisfb_post_xgi_delay(ivideo, 1);
4838 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4842 outSISIDXREG(SISSR, 0x13, 0xb1);
4843 outSISIDXREG(SISSR, 0x14, 0x41);
4844 sisfb_post_xgi_delay(ivideo, 1);
4846 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4849 outSISIDXREG(SISSR, 0x13, 0x31);
4850 } else { /* Dual 16/8 */
4852 outSISIDXREG(SISSR, 0x13, 0xb1);
4853 outSISIDXREG(SISSR, 0x14, 0x41);
4854 sisfb_post_xgi_delay(ivideo, 1);
4856 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4859 outSISIDXREG(SISSR, 0x13, 0x31);
4860 outSISIDXREG(SISSR, 0x14, 0x31);
4861 sisfb_post_xgi_delay(ivideo, 1);
4862 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4866 outSISIDXREG(SISSR, 0x13, 0xb1);
4867 outSISIDXREG(SISSR, 0x14, 0x30);
4868 sisfb_post_xgi_delay(ivideo, 1);
4870 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4873 outSISIDXREG(SISSR, 0x13, 0x31);
4876 } else { /* XGI_40 */
4878 inSISIDXREG(SISCR, 0x97, reg);
4880 inSISIDXREG(SISSR, 0x39, reg);
4884 if(reg & 0x01) { /* DDRII */
4886 if(ivideo->revision_id == 2) {
4888 outSISIDXREG(SISSR, 0x13, 0xa1);
4889 outSISIDXREG(SISSR, 0x14, 0x44);
4891 sisfb_post_xgi_delay(ivideo, 1);
4892 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4895 outSISIDXREG(SISSR, 0x13, 0x21);
4896 outSISIDXREG(SISSR, 0x14, 0x34);
4897 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4901 outSISIDXREG(SISSR, 0x13, 0xa1);
4902 outSISIDXREG(SISSR, 0x14, 0x40);
4904 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4907 outSISIDXREG(SISSR, 0x13, 0x21);
4908 outSISIDXREG(SISSR, 0x14, 0x30);
4911 outSISIDXREG(SISSR, 0x13, 0xa1);
4912 outSISIDXREG(SISSR, 0x14, 0x4c);
4914 sisfb_post_xgi_delay(ivideo, 1);
4915 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4919 outSISIDXREG(SISSR, 0x14, 0x48);
4920 sisfb_post_xgi_delay(ivideo, 1);
4922 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4925 outSISIDXREG(SISSR, 0x13, 0x21);
4926 outSISIDXREG(SISSR, 0x14, 0x3c);
4929 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4933 outSISIDXREG(SISSR, 0x14, 0x38);
4937 sisfb_post_xgi_delay(ivideo, 1);
4942 if(ivideo->revision_id == 2) {
4944 outSISIDXREG(SISSR, 0x13, 0xa1);
4945 outSISIDXREG(SISSR, 0x14, 0x52);
4946 sisfb_post_xgi_delay(ivideo, 1);
4948 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4951 outSISIDXREG(SISSR, 0x13, 0x21);
4952 outSISIDXREG(SISSR, 0x14, 0x42);
4955 outSISIDXREG(SISSR, 0x13, 0xa1);
4956 outSISIDXREG(SISSR, 0x14, 0x5a);
4957 sisfb_post_xgi_delay(ivideo, 1);
4959 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4962 outSISIDXREG(SISSR, 0x13, 0x21);
4963 outSISIDXREG(SISSR, 0x14, 0x4a);
4965 sisfb_post_xgi_delay(ivideo, 1);
4971 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4972 sisfb_post_xgi_delay(ivideo, 1);
4974 j = (ivideo->chip == XGI_20) ? 5 : 9;
4975 k = (ivideo->chip == XGI_20) ? 12 : 4;
4977 for(i = 0; i < k; i++) {
4979 reg = (ivideo->chip == XGI_20) ?
4980 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4981 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4982 sisfb_post_xgi_delay(ivideo, 50);
4984 ranksize = (ivideo->chip == XGI_20) ?
4985 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4987 inSISIDXREG(SISSR, 0x13, reg);
4988 if(reg & 0x80) ranksize <<= 1;
4990 if(ivideo->chip == XGI_20) {
4991 if(buswidth == 16) ranksize <<= 1;
4992 else if(buswidth == 32) ranksize <<= 2;
4994 if(buswidth == 64) ranksize <<= 1;
5000 if((ranksize * l) <= 256) {
5001 while((ranksize >>= 1)) reg += 0x10;
5006 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
5007 sisfb_post_xgi_delay(ivideo, 1);
5009 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5013 iounmap(ivideo->video_vbase);
5016 static void __devinit
5017 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5021 static const u8 cs90[8 * 3] = {
5031 static const u8 csb8[8 * 3] = {
5045 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5046 if(ivideo->haveXGIROM) {
5047 v1 = ivideo->bios_abase[0x90 + index];
5048 v2 = ivideo->bios_abase[0x90 + index + 1];
5049 v3 = ivideo->bios_abase[0x90 + index + 2];
5051 outSISIDXREG(SISSR, 0x28, v1);
5052 outSISIDXREG(SISSR, 0x29, v2);
5053 outSISIDXREG(SISSR, 0x2a, v3);
5054 sisfb_post_xgi_delay(ivideo, 0x43);
5055 sisfb_post_xgi_delay(ivideo, 0x43);
5056 sisfb_post_xgi_delay(ivideo, 0x43);
5058 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5059 if(ivideo->haveXGIROM) {
5060 v1 = ivideo->bios_abase[0xb8 + index];
5061 v2 = ivideo->bios_abase[0xb8 + index + 1];
5062 v3 = ivideo->bios_abase[0xb8 + index + 2];
5064 outSISIDXREG(SISSR, 0x2e, v1);
5065 outSISIDXREG(SISSR, 0x2f, v2);
5066 outSISIDXREG(SISSR, 0x30, v3);
5067 sisfb_post_xgi_delay(ivideo, 0x43);
5068 sisfb_post_xgi_delay(ivideo, 0x43);
5069 sisfb_post_xgi_delay(ivideo, 0x43);
5072 static int __devinit
5073 sisfb_post_xgi(struct pci_dev *pdev)
5075 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5076 unsigned char *bios = ivideo->bios_abase;
5077 struct pci_dev *mypdev = NULL;
5078 const u8 *ptr, *ptr2;
5079 u8 v1, v2, v3, v4, v5, reg, ramtype;
5080 u32 rega, regb, regd;
5082 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5083 static const u8 cs76[2] = { 0xa3, 0xfb };
5084 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5085 static const u8 cs158[8] = {
5086 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5088 static const u8 cs160[8] = {
5089 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5091 static const u8 cs168[8] = {
5092 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5094 static const u8 cs128[3 * 8] = {
5095 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5096 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5097 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5099 static const u8 cs148[2 * 8] = {
5100 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5103 static const u8 cs31a[8 * 4] = {
5104 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5105 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5109 static const u8 cs33a[8 * 4] = {
5110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5115 static const u8 cs45a[8 * 2] = {
5116 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5119 static const u8 cs170[7 * 8] = {
5120 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5121 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5122 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5123 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5124 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5125 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5126 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5128 static const u8 cs1a8[3 * 8] = {
5129 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5130 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5133 static const u8 cs100[2 * 8] = {
5134 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5135 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5139 reg = inSISREG(SISVGAENABLE) | 0x01;
5140 outSISREG(SISVGAENABLE, reg);
5143 reg = inSISREG(SISMISCR) | 0x01;
5144 outSISREG(SISMISCW, reg);
5147 outSISIDXREG(SISSR, 0x05, 0x86);
5148 inSISIDXREG(SISSR, 0x05, reg);
5152 /* Clear some regs */
5153 for(i = 0; i < 0x22; i++) {
5154 if(0x06 + i == 0x20) continue;
5155 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5157 for(i = 0; i < 0x0b; i++) {
5158 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5160 for(i = 0; i < 0x10; i++) {
5161 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5165 if(ivideo->haveXGIROM) {
5166 ptr = (const u8 *)&bios[0x78];
5168 for(i = 0; i < 3; i++) {
5169 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5173 if(ivideo->haveXGIROM) {
5174 ptr = (const u8 *)&bios[0x76];
5176 for(i = 0; i < 2; i++) {
5177 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5180 v1 = 0x18; v2 = 0x00;
5181 if(ivideo->haveXGIROM) {
5185 outSISIDXREG(SISSR, 0x07, v1);
5186 outSISIDXREG(SISSR, 0x11, 0x0f);
5187 outSISIDXREG(SISSR, 0x1f, v2);
5188 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5189 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5190 outSISIDXREG(SISSR, 0x27, 0x74);
5193 if(ivideo->haveXGIROM) {
5194 ptr = (const u8 *)&bios[0x7b];
5196 for(i = 0; i < 3; i++) {
5197 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5200 if(ivideo->chip == XGI_40) {
5201 if(ivideo->revision_id == 2) {
5202 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5204 outSISIDXREG(SISCR, 0x7d, 0xfe);
5205 outSISIDXREG(SISCR, 0x7e, 0x0f);
5207 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5208 andSISIDXREG(SISCR, 0x58, 0xd7);
5209 inSISIDXREG(SISCR, 0xcb, reg);
5211 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5215 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5216 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5218 if(ivideo->chip == XGI_20) {
5219 outSISIDXREG(SISSR, 0x36, 0x70);
5221 outSISIDXREG(SISVID, 0x00, 0x86);
5222 outSISIDXREG(SISVID, 0x32, 0x00);
5223 outSISIDXREG(SISVID, 0x30, 0x00);
5224 outSISIDXREG(SISVID, 0x32, 0x01);
5225 outSISIDXREG(SISVID, 0x30, 0x00);
5226 andSISIDXREG(SISVID, 0x2f, 0xdf);
5227 andSISIDXREG(SISCAP, 0x00, 0x3f);
5229 outSISIDXREG(SISPART1, 0x2f, 0x01);
5230 outSISIDXREG(SISPART1, 0x00, 0x00);
5231 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5232 outSISIDXREG(SISPART1, 0x2e, 0x08);
5233 andSISIDXREG(SISPART1, 0x35, 0x7f);
5234 andSISIDXREG(SISPART1, 0x50, 0xfe);
5236 inSISIDXREG(SISPART4, 0x00, reg);
5237 if(reg == 1 || reg == 2) {
5238 outSISIDXREG(SISPART2, 0x00, 0x1c);
5239 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5240 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5241 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5242 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5244 inSISIDXREG(SISPART4, 0x01, reg);
5245 if((reg & 0xf0) >= 0xb0) {
5246 inSISIDXREG(SISPART4, 0x23, reg);
5247 if(reg & 0x20) reg |= 0x40;
5248 outSISIDXREG(SISPART4, 0x23, reg);
5249 reg = (reg & 0x20) ? 0x02 : 0x00;
5250 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5256 inSISIDXREG(SISSR, 0x3b, reg);
5258 inSISIDXREG(SISSR, 0x3a, reg);
5259 v2 = (reg & 0x30) >> 3;
5260 if(!(v2 & 0x04)) v2 ^= 0x02;
5261 inSISIDXREG(SISSR, 0x39, reg);
5262 if(reg & 0x80) v2 |= 0x80;
5265 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5266 SIS_PCI_PUT_DEVICE(mypdev);
5267 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5272 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5274 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5276 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5278 pci_read_config_dword(mypdev, 0x94, ®d);
5280 pci_write_config_dword(mypdev, 0x94, regd);
5282 SIS_PCI_PUT_DEVICE(mypdev);
5283 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5285 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5286 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5287 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5288 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5289 if((v2 & 0x06) == 4)
5294 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5296 outSISIDXREG(SISSR, 0x22, v1);
5298 if(ivideo->revision_id == 2) {
5299 inSISIDXREG(SISSR, 0x3b, v1);
5300 inSISIDXREG(SISSR, 0x3a, v2);
5301 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5302 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5303 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5305 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5306 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5310 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5311 SIS_PCI_PUT_DEVICE(mypdev);
5316 inSISIDXREG(SISSR, 0x3b, reg);
5317 inSISIDXREG(SISCR, 0x5f, v2);
5318 if((!(reg & 0x02)) && (v2 & 0x0e))
5320 outSISIDXREG(SISSR, 0x27, v1);
5322 if(bios[0x64] & 0x01) {
5323 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5327 pci_read_config_dword(pdev, 0x50, ®d);
5328 regd = (regd >> 20) & 0x0f;
5331 orSISIDXREG(SISCR, 0x5f, 0x08);
5333 outSISIDXREG(SISCR, 0x48, v1);
5335 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5336 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5337 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5338 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5339 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5340 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5341 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5342 outSISIDXREG(SISCR, 0x74, 0xd0);
5343 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5344 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5345 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5347 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5349 SIS_PCI_PUT_DEVICE(mypdev);
5351 outSISIDXREG(SISCR, 0x77, v1);
5359 if(ivideo->haveXGIROM) {
5360 v1 = bios[0x140 + regb];
5362 outSISIDXREG(SISCR, 0x6d, v1);
5365 if(ivideo->haveXGIROM) {
5366 ptr = (const u8 *)&bios[0x128];
5368 for(i = 0, j = 0; i < 3; i++, j += 8) {
5369 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5374 if(ivideo->haveXGIROM) {
5375 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5376 ptr = (const u8 *)&bios[index];
5377 ptr2 = (const u8 *)&bios[index + 0x20];
5379 for(i = 0; i < 2; i++) {
5381 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5384 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5388 for(j = 0; j < 16; j++) {
5390 if(regd & 0x01) reg |= 0x04;
5391 if(regd & 0x02) reg |= 0x08;
5393 outSISIDXREG(SISCR, rega, reg);
5394 inSISIDXREG(SISCR, rega, reg);
5395 inSISIDXREG(SISCR, rega, reg);
5400 andSISIDXREG(SISCR, 0x6e, 0xfc);
5403 if(ivideo->haveXGIROM) {
5404 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5405 ptr = (const u8 *)&bios[index];
5407 for(i = 0; i < 4; i++) {
5408 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5410 for(j = 0; j < 2; j++) {
5413 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5417 for(k = 0; k < 16; k++) {
5419 if(regd & 0x01) reg |= 0x01;
5420 if(regd & 0x02) reg |= 0x02;
5422 outSISIDXREG(SISCR, 0x6f, reg);
5423 inSISIDXREG(SISCR, 0x6f, reg);
5424 inSISIDXREG(SISCR, 0x6f, reg);
5431 if(ivideo->haveXGIROM) {
5432 ptr = (const u8 *)&bios[0x148];
5434 for(i = 0, j = 0; i < 2; i++, j += 8) {
5435 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5438 andSISIDXREG(SISCR, 0x89, 0x8f);
5441 if(ivideo->haveXGIROM) {
5442 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5443 ptr = (const u8 *)&bios[index];
5445 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5447 for(i = 0; i < 5; i++) {
5449 if(regd & 0x01) reg |= 0x01;
5450 if(regd & 0x02) reg |= 0x02;
5452 outSISIDXREG(SISCR, 0x89, reg);
5453 inSISIDXREG(SISCR, 0x89, reg);
5454 inSISIDXREG(SISCR, 0x89, reg);
5458 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5459 if(ivideo->haveXGIROM) {
5460 v1 = bios[0x118 + regb];
5461 v2 = bios[0xf8 + regb];
5462 v3 = bios[0x120 + regb];
5465 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5466 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5467 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5468 outSISIDXREG(SISCR, 0x41, v2);
5471 if(ivideo->haveXGIROM) {
5472 ptr = (const u8 *)&bios[0x170];
5474 for(i = 0, j = 0; i < 7; i++, j += 8) {
5475 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5478 outSISIDXREG(SISCR, 0x59, v3);
5481 if(ivideo->haveXGIROM) {
5482 ptr = (const u8 *)&bios[0x1a8];
5484 for(i = 0, j = 0; i < 3; i++, j += 8) {
5485 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5489 if(ivideo->haveXGIROM) {
5490 ptr = (const u8 *)&bios[0x100];
5492 for(i = 0, j = 0; i < 2; i++, j += 8) {
5493 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5496 outSISIDXREG(SISCR, 0xcf, v4);
5498 outSISIDXREG(SISCR, 0x83, 0x09);
5499 outSISIDXREG(SISCR, 0x87, 0x00);
5501 if(ivideo->chip == XGI_40) {
5502 if( (ivideo->revision_id == 1) ||
5503 (ivideo->revision_id == 2) ) {
5504 outSISIDXREG(SISCR, 0x8c, 0x87);
5508 outSISIDXREG(SISSR, 0x17, 0x00);
5509 outSISIDXREG(SISSR, 0x1a, 0x87);
5511 if(ivideo->chip == XGI_20) {
5512 outSISIDXREG(SISSR, 0x15, 0x00);
5513 outSISIDXREG(SISSR, 0x1c, 0x00);
5516 ramtype = 0x00; v1 = 0x10;
5517 if(ivideo->haveXGIROM) {
5518 ramtype = bios[0x62];
5521 if(!(ramtype & 0x80)) {
5522 if(ivideo->chip == XGI_20) {
5523 outSISIDXREG(SISCR, 0x97, v1);
5524 inSISIDXREG(SISCR, 0x97, reg);
5526 ramtype = (reg & 0x01) << 1;
5529 inSISIDXREG(SISSR, 0x39, reg);
5530 ramtype = reg & 0x02;
5532 inSISIDXREG(SISSR, 0x3a, reg);
5533 ramtype = (reg >> 1) & 0x01;
5543 sisfb_post_xgi_setclocks(ivideo, regb);
5544 if((ivideo->chip == XGI_20) ||
5545 (ivideo->revision_id == 1) ||
5546 (ivideo->revision_id == 2)) {
5547 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5548 if(ivideo->haveXGIROM) {
5549 v1 = bios[regb + 0x158];
5550 v2 = bios[regb + 0x160];
5551 v3 = bios[regb + 0x168];
5553 outSISIDXREG(SISCR, 0x82, v1);
5554 outSISIDXREG(SISCR, 0x85, v2);
5555 outSISIDXREG(SISCR, 0x86, v3);
5557 outSISIDXREG(SISCR, 0x82, 0x88);
5558 outSISIDXREG(SISCR, 0x86, 0x00);
5559 inSISIDXREG(SISCR, 0x86, reg);
5560 outSISIDXREG(SISCR, 0x86, 0x88);
5561 inSISIDXREG(SISCR, 0x86, reg);
5562 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5563 outSISIDXREG(SISCR, 0x82, 0x77);
5564 outSISIDXREG(SISCR, 0x85, 0x00);
5565 inSISIDXREG(SISCR, 0x85, reg);
5566 outSISIDXREG(SISCR, 0x85, 0x88);
5567 inSISIDXREG(SISCR, 0x85, reg);
5568 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5569 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5571 if(ivideo->chip == XGI_40) {
5572 outSISIDXREG(SISCR, 0x97, 0x00);
5574 outSISIDXREG(SISCR, 0x98, 0x01);
5575 outSISIDXREG(SISCR, 0x9a, 0x02);
5577 outSISIDXREG(SISSR, 0x18, 0x01);
5578 if((ivideo->chip == XGI_20) ||
5579 (ivideo->revision_id == 2)) {
5580 outSISIDXREG(SISSR, 0x19, 0x40);
5582 outSISIDXREG(SISSR, 0x19, 0x20);
5584 outSISIDXREG(SISSR, 0x16, 0x00);
5585 outSISIDXREG(SISSR, 0x16, 0x80);
5586 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5587 sisfb_post_xgi_delay(ivideo, 0x43);
5588 sisfb_post_xgi_delay(ivideo, 0x43);
5589 sisfb_post_xgi_delay(ivideo, 0x43);
5590 outSISIDXREG(SISSR, 0x18, 0x00);
5591 if((ivideo->chip == XGI_20) ||
5592 (ivideo->revision_id == 2)) {
5593 outSISIDXREG(SISSR, 0x19, 0x40);
5595 outSISIDXREG(SISSR, 0x19, 0x20);
5597 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5598 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5600 outSISIDXREG(SISSR, 0x16, 0x00);
5601 outSISIDXREG(SISSR, 0x16, 0x80);
5602 sisfb_post_xgi_delay(ivideo, 4);
5603 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5604 if(ivideo->haveXGIROM) {
5606 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5608 v3 = bios[index + 1];
5609 v4 = bios[index + 2];
5610 v5 = bios[index + 3];
5612 outSISIDXREG(SISSR, 0x18, v1);
5613 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5614 outSISIDXREG(SISSR, 0x16, v2);
5615 outSISIDXREG(SISSR, 0x16, v3);
5616 sisfb_post_xgi_delay(ivideo, 0x43);
5617 outSISIDXREG(SISSR, 0x1b, 0x03);
5618 sisfb_post_xgi_delay(ivideo, 0x22);
5619 outSISIDXREG(SISSR, 0x18, v1);
5620 outSISIDXREG(SISSR, 0x19, 0x00);
5621 outSISIDXREG(SISSR, 0x16, v4);
5622 outSISIDXREG(SISSR, 0x16, v5);
5623 outSISIDXREG(SISSR, 0x1b, 0x00);
5626 outSISIDXREG(SISCR, 0x82, 0x77);
5627 outSISIDXREG(SISCR, 0x86, 0x00);
5628 inSISIDXREG(SISCR, 0x86, reg);
5629 outSISIDXREG(SISCR, 0x86, 0x88);
5630 inSISIDXREG(SISCR, 0x86, reg);
5631 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5632 if(ivideo->haveXGIROM) {
5633 v1 = bios[regb + 0x168];
5634 v2 = bios[regb + 0x160];
5635 v3 = bios[regb + 0x158];
5637 outSISIDXREG(SISCR, 0x86, v1);
5638 outSISIDXREG(SISCR, 0x82, 0x77);
5639 outSISIDXREG(SISCR, 0x85, 0x00);
5640 inSISIDXREG(SISCR, 0x85, reg);
5641 outSISIDXREG(SISCR, 0x85, 0x88);
5642 inSISIDXREG(SISCR, 0x85, reg);
5643 outSISIDXREG(SISCR, 0x85, v2);
5644 outSISIDXREG(SISCR, 0x82, v3);
5645 outSISIDXREG(SISCR, 0x98, 0x01);
5646 outSISIDXREG(SISCR, 0x9a, 0x02);
5648 outSISIDXREG(SISSR, 0x28, 0x64);
5649 outSISIDXREG(SISSR, 0x29, 0x63);
5650 sisfb_post_xgi_delay(ivideo, 15);
5651 outSISIDXREG(SISSR, 0x18, 0x00);
5652 outSISIDXREG(SISSR, 0x19, 0x20);
5653 outSISIDXREG(SISSR, 0x16, 0x00);
5654 outSISIDXREG(SISSR, 0x16, 0x80);
5655 outSISIDXREG(SISSR, 0x18, 0xc5);
5656 outSISIDXREG(SISSR, 0x19, 0x23);
5657 outSISIDXREG(SISSR, 0x16, 0x00);
5658 outSISIDXREG(SISSR, 0x16, 0x80);
5659 sisfb_post_xgi_delay(ivideo, 1);
5660 outSISIDXREG(SISCR, 0x97,0x11);
5661 sisfb_post_xgi_setclocks(ivideo, regb);
5662 sisfb_post_xgi_delay(ivideo, 0x46);
5663 outSISIDXREG(SISSR, 0x18, 0xc5);
5664 outSISIDXREG(SISSR, 0x19, 0x23);
5665 outSISIDXREG(SISSR, 0x16, 0x00);
5666 outSISIDXREG(SISSR, 0x16, 0x80);
5667 sisfb_post_xgi_delay(ivideo, 1);
5668 outSISIDXREG(SISSR, 0x1b, 0x04);
5669 sisfb_post_xgi_delay(ivideo, 1);
5670 outSISIDXREG(SISSR, 0x1b, 0x00);
5671 sisfb_post_xgi_delay(ivideo, 1);
5673 if(ivideo->haveXGIROM) {
5676 outSISIDXREG(SISSR, 0x18, v1);
5677 outSISIDXREG(SISSR, 0x19, 0x06);
5678 outSISIDXREG(SISSR, 0x16, 0x04);
5679 outSISIDXREG(SISSR, 0x16, 0x84);
5680 sisfb_post_xgi_delay(ivideo, 1);
5683 sisfb_post_xgi_setclocks(ivideo, regb);
5684 if((ivideo->chip == XGI_40) &&
5685 ((ivideo->revision_id == 1) ||
5686 (ivideo->revision_id == 2))) {
5687 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5688 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5689 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5691 outSISIDXREG(SISCR, 0x82, 0x88);
5692 outSISIDXREG(SISCR, 0x86, 0x00);
5693 inSISIDXREG(SISCR, 0x86, reg);
5694 outSISIDXREG(SISCR, 0x86, 0x88);
5695 outSISIDXREG(SISCR, 0x82, 0x77);
5696 outSISIDXREG(SISCR, 0x85, 0x00);
5697 inSISIDXREG(SISCR, 0x85, reg);
5698 outSISIDXREG(SISCR, 0x85, 0x88);
5699 inSISIDXREG(SISCR, 0x85, reg);
5700 v1 = cs160[regb]; v2 = cs158[regb];
5701 if(ivideo->haveXGIROM) {
5702 v1 = bios[regb + 0x160];
5703 v2 = bios[regb + 0x158];
5705 outSISIDXREG(SISCR, 0x85, v1);
5706 outSISIDXREG(SISCR, 0x82, v2);
5708 if(ivideo->chip == XGI_40) {
5709 outSISIDXREG(SISCR, 0x97, 0x11);
5711 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5712 outSISIDXREG(SISCR, 0x98, 0x01);
5714 outSISIDXREG(SISCR, 0x98, 0x03);
5716 outSISIDXREG(SISCR, 0x9a, 0x02);
5718 if(ivideo->chip == XGI_40) {
5719 outSISIDXREG(SISSR, 0x18, 0x01);
5721 outSISIDXREG(SISSR, 0x18, 0x00);
5723 outSISIDXREG(SISSR, 0x19, 0x40);
5724 outSISIDXREG(SISSR, 0x16, 0x00);
5725 outSISIDXREG(SISSR, 0x16, 0x80);
5726 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5727 sisfb_post_xgi_delay(ivideo, 0x43);
5728 sisfb_post_xgi_delay(ivideo, 0x43);
5729 sisfb_post_xgi_delay(ivideo, 0x43);
5730 outSISIDXREG(SISSR, 0x18, 0x00);
5731 outSISIDXREG(SISSR, 0x19, 0x40);
5732 outSISIDXREG(SISSR, 0x16, 0x00);
5733 outSISIDXREG(SISSR, 0x16, 0x80);
5735 sisfb_post_xgi_delay(ivideo, 4);
5737 if(ivideo->haveXGIROM) {
5740 outSISIDXREG(SISSR, 0x18, v1);
5741 outSISIDXREG(SISSR, 0x19, 0x01);
5742 if(ivideo->chip == XGI_40) {
5743 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5744 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5746 outSISIDXREG(SISSR, 0x16, 0x05);
5747 outSISIDXREG(SISSR, 0x16, 0x85);
5749 sisfb_post_xgi_delay(ivideo, 0x43);
5750 if(ivideo->chip == XGI_40) {
5751 outSISIDXREG(SISSR, 0x1b, 0x01);
5753 outSISIDXREG(SISSR, 0x1b, 0x03);
5755 sisfb_post_xgi_delay(ivideo, 0x22);
5756 outSISIDXREG(SISSR, 0x18, v1);
5757 outSISIDXREG(SISSR, 0x19, 0x00);
5758 if(ivideo->chip == XGI_40) {
5759 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5760 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5762 outSISIDXREG(SISSR, 0x16, 0x05);
5763 outSISIDXREG(SISSR, 0x16, 0x85);
5765 outSISIDXREG(SISSR, 0x1b, 0x00);
5770 if(ivideo->haveXGIROM) {
5771 v1 = bios[0x110 + regb];
5773 outSISIDXREG(SISSR, 0x1b, v1);
5776 v1 = 0x00; v2 = 0x00;
5777 if(ivideo->haveXGIROM) {
5783 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5785 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5786 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5790 /* Set default mode, don't clear screen */
5791 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5792 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5793 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5794 ivideo->curFSTN = ivideo->curDSTN = 0;
5795 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5796 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5798 outSISIDXREG(SISSR, 0x05, 0x86);
5800 /* Disable read-cache */
5801 andSISIDXREG(SISSR, 0x21, 0xdf);
5802 sisfb_post_xgi_ramsize(ivideo);
5803 /* Enable read-cache */
5804 orSISIDXREG(SISSR, 0x21, 0x20);
5809 printk(KERN_DEBUG "-----------------\n");
5810 for(i = 0; i < 0xff; i++) {
5811 inSISIDXREG(SISCR, i, reg);
5812 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5814 for(i = 0; i < 0x40; i++) {
5815 inSISIDXREG(SISSR, i, reg);
5816 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5818 printk(KERN_DEBUG "-----------------\n");
5822 if(ivideo->chip == XGI_20) {
5823 orSISIDXREG(SISCR, 0x32, 0x20);
5825 inSISIDXREG(SISPART4, 0x00, reg);
5826 if((reg == 1) || (reg == 2)) {
5827 sisfb_sense_crt1(ivideo);
5829 orSISIDXREG(SISCR, 0x32, 0x20);
5833 /* Set default mode, don't clear screen */
5834 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5835 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5836 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5837 ivideo->curFSTN = ivideo->curDSTN = 0;
5838 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5840 outSISIDXREG(SISSR, 0x05, 0x86);
5843 orSISIDXREG(SISSR, 0x01, 0x20);
5845 /* Save mode number in CR34 */
5846 outSISIDXREG(SISCR, 0x34, 0x2e);
5848 /* Let everyone know what the current mode is */
5849 ivideo->modeprechange = 0x2e;
5851 if(ivideo->chip == XGI_40) {
5852 inSISIDXREG(SISCR, 0xca, reg);
5853 inSISIDXREG(SISCR, 0xcc, v1);
5854 if((reg & 0x10) && (!(v1 & 0x04))) {
5856 "sisfb: Please connect power to the card.\n");
5865 static int __devinit
5866 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5868 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5869 struct sis_video_info *ivideo = NULL;
5870 struct fb_info *sis_fb_info = NULL;
5878 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5879 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5883 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
5886 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5887 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5890 ivideo = (struct sis_video_info *)sis_fb_info->par;
5891 ivideo->memyselfandi = sis_fb_info;
5893 ivideo->sisfb_id = SISFB_ID;
5895 if(card_list == NULL) {
5896 ivideo->cardnumber = 0;
5898 struct sis_video_info *countvideo = card_list;
5899 ivideo->cardnumber = 1;
5900 while((countvideo = countvideo->next) != 0)
5901 ivideo->cardnumber++;
5904 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5906 ivideo->warncount = 0;
5907 ivideo->chip_id = pdev->device;
5908 ivideo->chip_vendor = pdev->vendor;
5909 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
5910 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5911 pci_read_config_word(pdev, PCI_COMMAND, ®16);
5912 ivideo->sisvga_enabled = reg16 & 0x01;
5913 ivideo->pcibus = pdev->bus->number;
5914 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5915 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5916 ivideo->subsysvendor = pdev->subsystem_vendor;
5917 ivideo->subsysdevice = pdev->subsystem_device;
5918 #ifdef SIS_OLD_CONFIG_COMPAT
5919 ivideo->ioctl32registered = 0;
5923 if(sisfb_mode_idx == -1) {
5924 sisfb_get_vga_mode_from_kernel();
5928 ivideo->chip = chipinfo->chip;
5929 ivideo->sisvga_engine = chipinfo->vgaengine;
5930 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5931 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5932 ivideo->mni = chipinfo->mni;
5934 ivideo->detectedpdc = 0xff;
5935 ivideo->detectedpdca = 0xff;
5936 ivideo->detectedlcda = 0xff;
5938 ivideo->sisfb_thismonitor.datavalid = FALSE;
5940 ivideo->current_base = 0;
5942 ivideo->engineok = 0;
5944 ivideo->sisfb_was_boot_device = 0;
5945 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5946 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5947 if(ivideo->sisvga_enabled)
5948 ivideo->sisfb_was_boot_device = 1;
5950 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5951 "but marked as boot video device ???\n");
5952 printk(KERN_DEBUG "sisfb: I will not accept this "
5953 "as the primary VGA device\n");
5958 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5959 ivideo->sisfb_accel = sisfb_accel;
5960 ivideo->sisfb_ypan = sisfb_ypan;
5961 ivideo->sisfb_max = sisfb_max;
5962 ivideo->sisfb_userom = sisfb_userom;
5963 ivideo->sisfb_useoem = sisfb_useoem;
5964 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5965 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5966 ivideo->sisfb_crt1off = sisfb_crt1off;
5967 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5968 ivideo->sisfb_crt2type = sisfb_crt2type;
5969 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5970 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5971 ivideo->sisfb_dstn = sisfb_dstn;
5972 ivideo->sisfb_fstn = sisfb_fstn;
5973 ivideo->sisfb_tvplug = sisfb_tvplug;
5974 ivideo->sisfb_tvstd = sisfb_tvstd;
5975 ivideo->tvxpos = sisfb_tvxposoffset;
5976 ivideo->tvypos = sisfb_tvyposoffset;
5977 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5978 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5979 ivideo->sisfb_inverse = sisfb_inverse;
5982 ivideo->refresh_rate = 0;
5983 if(ivideo->sisfb_parm_rate != -1) {
5984 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5987 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5988 ivideo->SiS_Pr.CenterScreen = -1;
5989 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5990 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5992 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5993 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5994 ivideo->SiS_Pr.SiS_ChSW = FALSE;
5995 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5996 ivideo->SiS_Pr.HaveEMI = FALSE;
5997 ivideo->SiS_Pr.HaveEMILCD = FALSE;
5998 ivideo->SiS_Pr.OverruleEMI = FALSE;
5999 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
6000 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
6001 ivideo->SiS_Pr.PDC = -1;
6002 ivideo->SiS_Pr.PDCA = -1;
6003 ivideo->SiS_Pr.DDCPortMixup = FALSE;
6004 #ifdef CONFIG_FB_SIS_315
6005 if(ivideo->chip >= SIS_330) {
6006 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
6007 if(ivideo->chip >= SIS_661) {
6008 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
6013 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6015 pci_set_drvdata(pdev, ivideo);
6017 /* Patch special cases */
6018 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6019 switch(ivideo->nbridge->device) {
6020 #ifdef CONFIG_FB_SIS_300
6021 case PCI_DEVICE_ID_SI_730:
6022 ivideo->chip = SIS_730;
6023 strcpy(ivideo->myid, "SiS 730");
6026 #ifdef CONFIG_FB_SIS_315
6027 case PCI_DEVICE_ID_SI_651:
6028 /* ivideo->chip is ok */
6029 strcpy(ivideo->myid, "SiS 651");
6031 case PCI_DEVICE_ID_SI_740:
6032 ivideo->chip = SIS_740;
6033 strcpy(ivideo->myid, "SiS 740");
6035 case PCI_DEVICE_ID_SI_661:
6036 ivideo->chip = SIS_661;
6037 strcpy(ivideo->myid, "SiS 661");
6039 case PCI_DEVICE_ID_SI_741:
6040 ivideo->chip = SIS_741;
6041 strcpy(ivideo->myid, "SiS 741");
6043 case PCI_DEVICE_ID_SI_760:
6044 ivideo->chip = SIS_760;
6045 strcpy(ivideo->myid, "SiS 760");
6047 case PCI_DEVICE_ID_SI_761:
6048 ivideo->chip = SIS_761;
6049 strcpy(ivideo->myid, "SiS 761");
6057 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6058 strcpy(sis_fb_info->modename, ivideo->myid);
6061 ivideo->SiS_Pr.ChipType = ivideo->chip;
6063 ivideo->SiS_Pr.ivideo = (void *)ivideo;
6065 #ifdef CONFIG_FB_SIS_315
6066 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6067 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6068 ivideo->SiS_Pr.ChipType = SIS_315H;
6072 if(!ivideo->sisvga_enabled) {
6073 if(pci_enable_device(pdev)) {
6074 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6075 pci_set_drvdata(pdev, NULL);
6081 ivideo->video_base = pci_resource_start(pdev, 0);
6082 ivideo->mmio_base = pci_resource_start(pdev, 1);
6083 ivideo->mmio_size = pci_resource_len(pdev, 1);
6084 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
6085 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
6087 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
6089 #ifdef CONFIG_FB_SIS_300
6090 /* Find PCI systems for Chrontel/GPIO communication setup */
6091 if(ivideo->chip == SIS_630) {
6094 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6095 mychswtable[i].subsysCard == ivideo->subsysdevice) {
6096 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6097 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6098 "requiring Chrontel/GPIO setup\n",
6099 mychswtable[i].vendorName,
6100 mychswtable[i].cardName);
6101 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6105 } while(mychswtable[i].subsysVendor != 0);
6109 #ifdef CONFIG_FB_SIS_315
6110 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6111 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
6115 outSISIDXREG(SISSR, 0x05, 0x86);
6117 if( (!ivideo->sisvga_enabled)
6118 #if !defined(__i386__) && !defined(__x86_64__)
6119 || (sisfb_resetcard)
6122 for(i = 0x30; i <= 0x3f; i++) {
6123 outSISIDXREG(SISCR, i, 0x00);
6127 /* Find out about current video mode */
6128 ivideo->modeprechange = 0x03;
6129 inSISIDXREG(SISCR, 0x34, reg);
6131 ivideo->modeprechange = reg & 0x7f;
6132 } else if(ivideo->sisvga_enabled) {
6133 #if defined(__i386__) || defined(__x86_64__)
6134 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
6136 ivideo->modeprechange = readb(tt + 0x49);
6142 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6144 if((reg & 0x80) && (reg != 0xff)) {
6145 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6147 printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6148 "X server is active\n");
6156 /* Search and copy ROM image */
6157 ivideo->bios_abase = NULL;
6158 ivideo->SiS_Pr.VirtualRomBase = NULL;
6159 ivideo->SiS_Pr.UseROM = FALSE;
6160 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
6161 if(ivideo->sisfb_userom) {
6162 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6163 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6164 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6165 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6166 ivideo->SiS_Pr.UseROM ? "" : "not ");
6167 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6168 ivideo->SiS_Pr.UseROM = FALSE;
6169 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6170 if( (ivideo->revision_id == 2) &&
6171 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6172 ivideo->SiS_Pr.DDCPortMixup = TRUE;
6176 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6179 /* Find systems for special custom timing */
6180 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6181 sisfb_detect_custom_timing(ivideo);
6184 /* POST card in case this has not been done by the BIOS */
6185 if( (!ivideo->sisvga_enabled)
6186 #if !defined(__i386__) && !defined(__x86_64__)
6187 || (sisfb_resetcard)
6190 #ifdef CONFIG_FB_SIS_300
6191 if(ivideo->sisvga_engine == SIS_300_VGA) {
6192 if(ivideo->chip == SIS_300) {
6193 sisfb_post_sis300(pdev);
6194 ivideo->sisfb_can_post = 1;
6199 #ifdef CONFIG_FB_SIS_315
6200 if(ivideo->sisvga_engine == SIS_315_VGA) {
6202 /* if((ivideo->chip == SIS_315H) ||
6203 (ivideo->chip == SIS_315) ||
6204 (ivideo->chip == SIS_315PRO) ||
6205 (ivideo->chip == SIS_330)) {
6206 sisfb_post_sis315330(pdev);
6207 } else */ if(ivideo->chip == XGI_20) {
6208 result = sisfb_post_xgi(pdev);
6209 ivideo->sisfb_can_post = 1;
6210 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6211 result = sisfb_post_xgi(pdev);
6212 ivideo->sisfb_can_post = 1;
6214 printk(KERN_INFO "sisfb: Card is not "
6215 "POSTed and sisfb can't do this either.\n");
6218 printk(KERN_ERR "sisfb: Failed to POST card\n");
6226 ivideo->sisfb_card_posted = 1;
6228 /* Find out about RAM size */
6229 if(sisfb_get_dram_size(ivideo)) {
6230 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6236 /* Enable PCI addressing and MMIO */
6237 if((ivideo->sisfb_mode_idx < 0) ||
6238 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6239 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6240 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6241 /* Enable 2D accelerator engine */
6242 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6245 if(sisfb_pdc != 0xff) {
6246 if(ivideo->sisvga_engine == SIS_300_VGA)
6250 ivideo->SiS_Pr.PDC = sisfb_pdc;
6252 #ifdef CONFIG_FB_SIS_315
6253 if(ivideo->sisvga_engine == SIS_315_VGA) {
6254 if(sisfb_pdca != 0xff)
6255 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6259 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6260 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6261 (int)(ivideo->video_size >> 20));
6262 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6267 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6268 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6273 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6274 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6275 if(!ivideo->video_vbase) {
6276 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6281 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6282 if(!ivideo->mmio_vbase) {
6283 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6285 error_0: iounmap(ivideo->video_vbase);
6286 error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6287 error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6288 error_3: vfree(ivideo->bios_abase);
6289 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6293 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6295 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6296 pci_set_drvdata(pdev, NULL);
6297 if(!ivideo->sisvga_enabled)
6298 pci_disable_device(pdev);
6303 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6304 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6306 if(ivideo->video_offset) {
6307 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6308 ivideo->video_offset / 1024);
6311 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6312 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6315 /* Determine the size of the command queue */
6316 if(ivideo->sisvga_engine == SIS_300_VGA) {
6317 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6319 if(ivideo->chip == XGI_20) {
6320 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6322 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6326 /* Engines are no longer initialized here; this is
6327 * now done after the first mode-switch (if the
6328 * submitted var has its acceleration flags set).
6331 /* Calculate the base of the (unused) hw cursor */
6332 ivideo->hwcursor_vbase = ivideo->video_vbase
6333 + ivideo->video_size
6334 - ivideo->cmdQueueSize
6335 - ivideo->hwcursor_size;
6336 ivideo->caps |= HW_CURSOR_CAP;
6338 /* Initialize offscreen memory manager */
6339 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6340 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6343 /* Used for clearing the screen only, therefore respect our mem limit */
6344 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6345 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6349 ivideo->vbflags = 0;
6350 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6351 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6352 ivideo->defmodeidx = DEFAULT_MODE;
6355 if(ivideo->chip < XGI_20) {
6356 if(ivideo->bios_abase) {
6357 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6361 if((ivideo->sisfb_mode_idx < 0) ||
6362 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6364 sisfb_sense_crt1(ivideo);
6366 sisfb_get_VB_type(ivideo);
6368 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6369 sisfb_detect_VB_connect(ivideo);
6372 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6374 /* Decide on which CRT2 device to use */
6375 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6376 if(ivideo->sisfb_crt2type != -1) {
6377 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6378 (ivideo->vbflags & CRT2_LCD)) {
6379 ivideo->currentvbflags |= CRT2_LCD;
6380 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6381 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6384 /* Chrontel 700x TV detection often unreliable, therefore
6385 * use a different default order on such machines
6387 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6388 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6389 if(ivideo->vbflags & CRT2_LCD)
6390 ivideo->currentvbflags |= CRT2_LCD;
6391 else if(ivideo->vbflags & CRT2_TV)
6392 ivideo->currentvbflags |= CRT2_TV;
6393 else if(ivideo->vbflags & CRT2_VGA)
6394 ivideo->currentvbflags |= CRT2_VGA;
6396 if(ivideo->vbflags & CRT2_TV)
6397 ivideo->currentvbflags |= CRT2_TV;
6398 else if(ivideo->vbflags & CRT2_LCD)
6399 ivideo->currentvbflags |= CRT2_LCD;
6400 else if(ivideo->vbflags & CRT2_VGA)
6401 ivideo->currentvbflags |= CRT2_VGA;
6406 if(ivideo->vbflags & CRT2_LCD) {
6407 sisfb_detect_lcd_type(ivideo);
6410 sisfb_save_pdc_emi(ivideo);
6412 if(!ivideo->sisfb_crt1off) {
6413 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6415 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6416 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6417 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6421 if(ivideo->sisfb_mode_idx >= 0) {
6422 int bu = ivideo->sisfb_mode_idx;
6423 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6424 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6425 if(bu != ivideo->sisfb_mode_idx) {
6426 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6427 sisbios_mode[bu].xres,
6428 sisbios_mode[bu].yres,
6429 sisbios_mode[bu].bpp);
6433 if(ivideo->sisfb_mode_idx < 0) {
6434 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6436 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6439 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6442 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6447 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6449 if(ivideo->refresh_rate != 0) {
6450 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6451 ivideo->sisfb_mode_idx);
6454 if(ivideo->rate_idx == 0) {
6455 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6456 ivideo->refresh_rate = 60;
6459 if(ivideo->sisfb_thismonitor.datavalid) {
6460 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6461 ivideo->sisfb_mode_idx,
6463 ivideo->refresh_rate)) {
6464 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6465 "exceeds monitor specs!\n");
6469 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6470 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6471 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6473 sisfb_set_vparms(ivideo);
6475 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6477 /* ---------------- For 2.4: Now switch the mode ------------------ */
6479 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6480 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6481 ivideo->refresh_rate);
6483 /* Determine whether or not acceleration is to be
6484 * used. Need to know before pre/post_set_mode()
6487 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6488 if(ivideo->sisfb_accel) {
6490 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6493 /* Now switch the mode */
6494 sisfb_pre_setmode(ivideo);
6496 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
6497 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6500 iounmap(ivideo->mmio_vbase);
6504 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6506 sisfb_post_setmode(ivideo);
6508 /* Maximize regardless of sisfb_max at startup */
6509 ivideo->default_var.yres_virtual = 32767;
6511 /* Force reset of x virtual in crtc_to_var */
6512 ivideo->default_var.xres_virtual = 0;
6514 /* Copy mode timing to var */
6515 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6517 /* Find out about screen pitch */
6518 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6519 sisfb_set_pitch(ivideo);
6521 /* Init the accelerator (does nothing currently) */
6522 sisfb_initaccel(ivideo);
6524 /* Init some fbinfo entries */
6525 sis_fb_info->node = -1;
6526 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6527 sis_fb_info->fbops = &sisfb_ops;
6528 sis_fb_info->disp = &ivideo->sis_disp;
6529 sis_fb_info->blank = &sisfb_blank;
6530 sis_fb_info->switch_con = &sisfb_switch;
6531 sis_fb_info->updatevar = &sisfb_update_var;
6532 sis_fb_info->changevar = NULL;
6533 strcpy(sis_fb_info->fontname, sisfb_fontname);
6535 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6537 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6539 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6540 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6541 ivideo->refresh_rate);
6543 /* Set up the default var according to chosen default display mode */
6544 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6545 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6546 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6548 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6550 ivideo->default_var.pixclock = (u32) (1000000000 /
6551 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6553 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6554 ivideo->rate_idx, &ivideo->default_var)) {
6555 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6556 ivideo->default_var.pixclock <<= 1;
6560 if(ivideo->sisfb_ypan) {
6561 /* Maximize regardless of sisfb_max at startup */
6562 ivideo->default_var.yres_virtual =
6563 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6564 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6565 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6569 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6572 if(ivideo->sisfb_accel) {
6574 #ifdef STUPID_ACCELF_TEXT_SHIT
6575 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6578 sisfb_initaccel(ivideo);
6580 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6581 sis_fb_info->flags = FBINFO_DEFAULT |
6582 FBINFO_HWACCEL_YPAN |
6583 FBINFO_HWACCEL_XPAN |
6584 FBINFO_HWACCEL_COPYAREA |
6585 FBINFO_HWACCEL_FILLRECT |
6586 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6588 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6590 sis_fb_info->var = ivideo->default_var;
6591 sis_fb_info->fix = ivideo->sisfb_fix;
6592 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6593 sis_fb_info->fbops = &sisfb_ops;
6595 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6596 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6598 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6601 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6604 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6605 MTRR_TYPE_WRCOMB, 1);
6606 if(ivideo->mtrr < 0) {
6607 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6611 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6612 vc_resize_con(1, 1, 0);
6615 if(register_framebuffer(sis_fb_info) < 0) {
6616 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6618 iounmap(ivideo->mmio_vbase);
6622 ivideo->registered = 1;
6625 ivideo->next = card_list;
6628 #ifdef SIS_OLD_CONFIG_COMPAT
6631 /* Our ioctls are all "32/64bit compatible" */
6632 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6633 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6634 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6635 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6636 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6637 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6638 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6639 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6640 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6641 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6642 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6643 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6646 "sisfb: Error registering ioctl32 translations\n");
6648 ivideo->ioctl32registered = 1;
6652 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6653 ivideo->sisfb_accel ? "enabled" : "disabled",
6654 ivideo->sisfb_ypan ?
6655 (ivideo->sisfb_max ? "enabled (auto-max)" :
6656 "enabled (no auto-max)") :
6660 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6661 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6662 GET_FB_IDX(sis_fb_info->node),
6666 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6668 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6670 } /* if mode = "none" */
6675 /*****************************************************/
6676 /* PCI DEVICE HANDLING */
6677 /*****************************************************/
6679 static void __devexit sisfb_remove(struct pci_dev *pdev)
6681 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6682 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6683 int registered = ivideo->registered;
6684 int modechanged = ivideo->modechanged;
6686 #ifdef SIS_OLD_CONFIG_COMPAT
6687 if(ivideo->ioctl32registered) {
6689 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6690 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6691 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6692 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6693 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6694 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6695 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6696 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6697 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6698 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6699 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6700 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6703 "sisfb: Error unregistering ioctl32 translations\n");
6708 iounmap(ivideo->mmio_vbase);
6709 iounmap(ivideo->video_vbase);
6711 /* Release mem regions */
6712 release_mem_region(ivideo->video_base, ivideo->video_size);
6713 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6715 vfree(ivideo->bios_abase);
6718 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6721 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6724 /* Release MTRR region */
6725 if(ivideo->mtrr >= 0)
6726 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6729 pci_set_drvdata(pdev, NULL);
6731 /* If device was disabled when starting, disable
6734 if(!ivideo->sisvga_enabled)
6735 pci_disable_device(pdev);
6737 /* Unregister the framebuffer */
6738 if(ivideo->registered) {
6739 unregister_framebuffer(sis_fb_info);
6740 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6741 framebuffer_release(sis_fb_info);
6747 /* OK, our ivideo is gone for good from here. */
6749 /* TODO: Restore the initial mode
6750 * This sounds easy but is as good as impossible
6751 * on many machines with SiS chip and video bridge
6752 * since text modes are always set up differently
6753 * from machine to machine. Depends on the type
6754 * of integration between chipset and bridge.
6756 if(registered && modechanged)
6758 "sisfb: Restoring of text mode not supported yet\n");
6761 static struct pci_driver sisfb_driver = {
6763 .id_table = sisfb_pci_table,
6764 .probe = sisfb_probe,
6765 .remove = __devexit_p(sisfb_remove)
6768 SISINITSTATIC int __init sisfb_init(void)
6770 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6772 char *options = NULL;
6774 if(fb_get_options("sisfb", &options))
6777 sisfb_setup(options);
6780 return pci_register_driver(&sisfb_driver);
6783 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6785 module_init(sisfb_init);
6789 /*****************************************************/
6791 /*****************************************************/
6795 static char *mode = NULL;
6796 static int vesa = -1;
6797 static unsigned int rate = 0;
6798 static unsigned int crt1off = 1;
6799 static unsigned int mem = 0;
6800 static char *forcecrt2type = NULL;
6801 static int forcecrt1 = -1;
6802 static int pdc = -1;
6803 static int pdc1 = -1;
6804 static int noaccel = -1;
6805 static int noypan = -1;
6806 static int nomax = -1;
6807 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6808 static int inverse = 0;
6810 static int userom = -1;
6811 static int useoem = -1;
6812 static char *tvstandard = NULL;
6813 static int nocrt2rate = 0;
6814 static int scalelcd = -1;
6815 static char *specialtiming = NULL;
6816 static int lvdshl = -1;
6817 static int tvxposoffset = 0, tvyposoffset = 0;
6818 #if !defined(__i386__) && !defined(__x86_64__)
6819 static int resetcard = 0;
6820 static int videoram = 0;
6823 static int __init sisfb_init_module(void)
6825 sisfb_setdefaultparms();
6828 sisfb_parm_rate = rate;
6830 if((scalelcd == 0) || (scalelcd == 1))
6831 sisfb_scalelcd = scalelcd ^ 1;
6833 /* Need to check crt2 type first for fstn/dstn */
6836 sisfb_search_crt2type(forcecrt2type);
6839 sisfb_search_tvstd(tvstandard);
6842 sisfb_search_mode(mode, FALSE);
6844 sisfb_search_vesamode(vesa, FALSE);
6846 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6848 sisfb_forcecrt1 = forcecrt1;
6851 else if(forcecrt1 == 0)
6856 else if(noaccel == 0)
6861 else if(noypan == 0)
6869 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6870 if(inverse) sisfb_inverse = 1;
6874 sisfb_parm_mem = mem;
6877 sisfb_userom = userom;
6880 sisfb_useoem = useoem;
6883 sisfb_pdc = (pdc & 0x7f);
6886 sisfb_pdca = (pdc1 & 0x1f);
6888 sisfb_nocrt2rate = nocrt2rate;
6891 sisfb_search_specialtiming(specialtiming);
6893 if((lvdshl >= 0) && (lvdshl <= 3))
6894 sisfb_lvdshl = lvdshl;
6896 sisfb_tvxposoffset = tvxposoffset;
6897 sisfb_tvyposoffset = tvyposoffset;
6899 #if !defined(__i386__) && !defined(__x86_64__)
6900 sisfb_resetcard = (resetcard) ? 1 : 0;
6902 sisfb_videoram = videoram;
6905 return sisfb_init();
6908 static void __exit sisfb_remove_module(void)
6910 pci_unregister_driver(&sisfb_driver);
6911 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6914 module_init(sisfb_init_module);
6915 module_exit(sisfb_remove_module);
6917 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6918 MODULE_LICENSE("GPL");
6919 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6921 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6922 MODULE_PARM(mem, "i");
6923 MODULE_PARM(noaccel, "i");
6924 MODULE_PARM(noypan, "i");
6925 MODULE_PARM(nomax, "i");
6926 MODULE_PARM(userom, "i");
6927 MODULE_PARM(useoem, "i");
6928 MODULE_PARM(mode, "s");
6929 MODULE_PARM(vesa, "i");
6930 MODULE_PARM(rate, "i");
6931 MODULE_PARM(forcecrt1, "i");
6932 MODULE_PARM(forcecrt2type, "s");
6933 MODULE_PARM(scalelcd, "i");
6934 MODULE_PARM(pdc, "i");
6935 MODULE_PARM(pdc1, "i");
6936 MODULE_PARM(specialtiming, "s");
6937 MODULE_PARM(lvdshl, "i");
6938 MODULE_PARM(tvstandard, "s");
6939 MODULE_PARM(tvxposoffset, "i");
6940 MODULE_PARM(tvyposoffset, "i");
6941 MODULE_PARM(nocrt2rate, "i");
6942 MODULE_PARM(inverse, "i");
6943 #if !defined(__i386__) && !defined(__x86_64__)
6944 MODULE_PARM(resetcard, "i");
6945 MODULE_PARM(videoram, "i");
6949 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6950 module_param(mem, int, 0);
6951 module_param(noaccel, int, 0);
6952 module_param(noypan, int, 0);
6953 module_param(nomax, int, 0);
6954 module_param(userom, int, 0);
6955 module_param(useoem, int, 0);
6956 module_param(mode, charp, 0);
6957 module_param(vesa, int, 0);
6958 module_param(rate, int, 0);
6959 module_param(forcecrt1, int, 0);
6960 module_param(forcecrt2type, charp, 0);
6961 module_param(scalelcd, int, 0);
6962 module_param(pdc, int, 0);
6963 module_param(pdc1, int, 0);
6964 module_param(specialtiming, charp, 0);
6965 module_param(lvdshl, int, 0);
6966 module_param(tvstandard, charp, 0);
6967 module_param(tvxposoffset, int, 0);
6968 module_param(tvyposoffset, int, 0);
6969 module_param(nocrt2rate, int, 0);
6970 #if !defined(__i386__) && !defined(__x86_64__)
6971 module_param(resetcard, int, 0);
6972 module_param(videoram, int, 0);
6976 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6977 MODULE_PARM_DESC(mem,
6978 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6979 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6980 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6981 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6982 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6983 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6984 "for XFree86 4.x/X.org 6.7 and later.\n");
6986 MODULE_PARM_DESC(mem,
6987 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6988 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6989 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6990 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6991 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6992 "The value is to be specified without 'KB'.\n");
6995 MODULE_PARM_DESC(noaccel,
6996 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6999 MODULE_PARM_DESC(noypan,
7000 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
7001 "will be performed by redrawing the screen. (default: 0)\n");
7003 MODULE_PARM_DESC(nomax,
7004 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
7005 "memory for the virtual screen in order to optimize scrolling performance. If\n"
7006 "this is set to anything other than 0, sisfb will not do this and thereby \n"
7007 "enable the user to positively specify a virtual Y size of the screen using\n"
7008 "fbset. (default: 0)\n");
7010 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7011 MODULE_PARM_DESC(mode,
7012 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7013 "1024x768x16. Other formats supported include XxY-Depth and\n"
7014 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7015 "number, it will be interpreted as a VESA mode number. (default: none if\n"
7016 "sisfb is a module; this leaves the console untouched and the driver will\n"
7017 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7018 "is in the kernel)\n");
7019 MODULE_PARM_DESC(vesa,
7020 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7021 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
7022 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7023 "0x0103 if sisfb is in the kernel)\n");
7026 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7027 MODULE_PARM_DESC(mode,
7028 "\nSelects the desired default display mode in the format XxYxDepth,\n"
7029 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
7030 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7031 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7033 MODULE_PARM_DESC(vesa,
7034 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7035 "0x117 (default: 0x0103)\n");
7038 MODULE_PARM_DESC(rate,
7039 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7040 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7041 "will be ignored (default: 60)\n");
7043 MODULE_PARM_DESC(forcecrt1,
7044 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7045 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7046 "0=CRT1 OFF) (default: [autodetected])\n");
7048 MODULE_PARM_DESC(forcecrt2type,
7049 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7050 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7051 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7052 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7053 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7054 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7055 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7056 "depends on the very hardware in use. (default: [autodetected])\n");
7058 MODULE_PARM_DESC(scalelcd,
7059 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7060 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7061 "show black bars around the image, TMDS panels will probably do the scaling\n"
7062 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7064 MODULE_PARM_DESC(pdc,
7065 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
7066 "should detect this correctly in most cases; however, sometimes this is not\n"
7067 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
7068 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7069 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7070 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
7072 #ifdef CONFIG_FB_SIS_315
7073 MODULE_PARM_DESC(pdc1,
7074 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
7075 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7076 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7077 "implemented yet.\n");
7080 MODULE_PARM_DESC(specialtiming,
7081 "\nPlease refer to documentation for more information on this option.\n");
7083 MODULE_PARM_DESC(lvdshl,
7084 "\nPlease refer to documentation for more information on this option.\n");
7086 MODULE_PARM_DESC(tvstandard,
7087 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7088 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7090 MODULE_PARM_DESC(tvxposoffset,
7091 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7094 MODULE_PARM_DESC(tvyposoffset,
7095 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7098 MODULE_PARM_DESC(nocrt2rate,
7099 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7100 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7102 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7103 MODULE_PARM_DESC(inverse,
7104 "\nSetting this to anything but 0 should invert the display colors, but this\n"
7105 "does not seem to work. (default: 0)\n");
7108 #if !defined(__i386__) && !defined(__x86_64__)
7109 #ifdef CONFIG_FB_SIS_300
7110 MODULE_PARM_DESC(resetcard,
7111 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
7112 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7113 "currently). Default: 0\n");
7115 MODULE_PARM_DESC(videoram,
7116 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7117 "some non-x86 architectures where the memory auto detection fails. Only\n"
7118 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
7122 #endif /* /MODULE */
7124 /* _GPL only for new symbols. */
7125 EXPORT_SYMBOL(sis_malloc);
7126 EXPORT_SYMBOL(sis_free);
7127 EXPORT_SYMBOL_GPL(sis_malloc_new);
7128 EXPORT_SYMBOL_GPL(sis_free_new);