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 ---------- */
1746 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1747 static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1750 static int sisfb_ioctl(struct inode *inode, struct file *file,
1751 unsigned int cmd, unsigned long arg,
1752 struct fb_info *info)
1755 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1756 struct sis_memreq sismemreq;
1757 struct fb_vblank sisvbblank;
1762 u32 __user *argp = (u32 __user *)arg;
1766 if(!capable(CAP_SYS_RAWIO))
1769 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1772 sis_malloc(&sismemreq);
1774 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1775 sis_free((u32)sismemreq.offset);
1781 if(!capable(CAP_SYS_RAWIO))
1784 if(get_user(gpu32, argp))
1790 case FBIOGET_VBLANK:
1791 sisvbblank.count = 0;
1792 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1794 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1799 case SISFB_GET_INFO_SIZE:
1800 return put_user(sizeof(struct sisfb_info), argp);
1802 case SISFB_GET_INFO_OLD:
1803 if(ivideo->warncount++ < 10)
1805 "sisfb: Deprecated ioctl call received - update your application!\n");
1806 case SISFB_GET_INFO: /* For communication with X driver */
1807 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1808 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1809 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1810 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1811 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1812 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1813 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1814 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1815 if(ivideo->modechanged) {
1816 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1818 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1820 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1821 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1822 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1823 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1824 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1825 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1826 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1827 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1828 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1829 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1830 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1831 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1832 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1833 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1834 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1835 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1836 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1837 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1838 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1839 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1840 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1841 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1842 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1843 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1844 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1845 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1846 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1847 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1849 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1850 sizeof(ivideo->sisfb_infoblock)))
1855 case SISFB_GET_VBRSTATUS_OLD:
1856 if(ivideo->warncount++ < 10)
1858 "sisfb: Deprecated ioctl call received - update your application!\n");
1859 case SISFB_GET_VBRSTATUS:
1860 if(sisfb_CheckVBRetrace(ivideo))
1861 return put_user((u32)1, argp);
1863 return put_user((u32)0, argp);
1865 case SISFB_GET_AUTOMAXIMIZE_OLD:
1866 if(ivideo->warncount++ < 10)
1868 "sisfb: Deprecated ioctl call received - update your application!\n");
1869 case SISFB_GET_AUTOMAXIMIZE:
1870 if(ivideo->sisfb_max)
1871 return put_user((u32)1, argp);
1873 return put_user((u32)0, argp);
1875 case SISFB_SET_AUTOMAXIMIZE_OLD:
1876 if(ivideo->warncount++ < 10)
1878 "sisfb: Deprecated ioctl call received - update your application!\n");
1879 case SISFB_SET_AUTOMAXIMIZE:
1880 if(get_user(gpu32, argp))
1883 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1886 case SISFB_SET_TVPOSOFFSET:
1887 if(get_user(gpu32, argp))
1890 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1891 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1894 case SISFB_GET_TVPOSOFFSET:
1895 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1899 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1900 sizeof(struct sisfb_cmd)))
1903 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1905 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1906 sizeof(struct sisfb_cmd)))
1911 case SISFB_SET_LOCK:
1912 if(get_user(gpu32, argp))
1915 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1919 #ifdef SIS_NEW_CONFIG_COMPAT
1920 return -ENOIOCTLCMD;
1929 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1931 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1933 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1935 strcpy(fix->id, ivideo->myid);
1937 fix->smem_start = ivideo->video_base + ivideo->video_offset;
1938 fix->smem_len = ivideo->sisfb_mem;
1939 fix->type = FB_TYPE_PACKED_PIXELS;
1941 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1943 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1945 fix->line_length = ivideo->video_linelength;
1946 fix->mmio_start = ivideo->mmio_base;
1947 fix->mmio_len = ivideo->mmio_size;
1948 if(ivideo->sisvga_engine == SIS_300_VGA) {
1949 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1950 } else if((ivideo->chip == SIS_330) ||
1951 (ivideo->chip == SIS_760) ||
1952 (ivideo->chip == SIS_761)) {
1953 fix->accel = FB_ACCEL_SIS_XABRE;
1954 } else if(ivideo->chip == XGI_20) {
1955 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1956 } else if(ivideo->chip >= XGI_40) {
1957 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1959 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1965 /* ---------------- fb_ops structures ----------------- */
1967 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1968 static struct fb_ops sisfb_ops = {
1969 .owner = THIS_MODULE,
1970 .fb_get_fix = sisfb_get_fix,
1971 .fb_get_var = sisfb_get_var,
1972 .fb_set_var = sisfb_set_var,
1973 .fb_get_cmap = sisfb_get_cmap,
1974 .fb_set_cmap = sisfb_set_cmap,
1975 .fb_pan_display = sisfb_pan_display,
1976 .fb_ioctl = sisfb_ioctl
1980 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1981 static struct fb_ops sisfb_ops = {
1982 .owner = THIS_MODULE,
1983 .fb_open = sisfb_open,
1984 .fb_release = sisfb_release,
1985 .fb_check_var = sisfb_check_var,
1986 .fb_set_par = sisfb_set_par,
1987 .fb_setcolreg = sisfb_setcolreg,
1988 .fb_pan_display = sisfb_pan_display,
1989 .fb_blank = sisfb_blank,
1990 .fb_fillrect = fbcon_sis_fillrect,
1991 .fb_copyarea = fbcon_sis_copyarea,
1992 .fb_imageblit = cfb_imageblit,
1993 #ifdef CONFIG_FB_SOFT_CURSOR
1994 .fb_cursor = soft_cursor,
1996 .fb_sync = fbcon_sis_sync,
1997 #ifdef SIS_NEW_CONFIG_COMPAT
1998 .fb_compat_ioctl= sisfb_ioctl,
2000 .fb_ioctl = sisfb_ioctl
2004 /* ---------------- Chip generation dependent routines ---------------- */
2006 static struct pci_dev * __devinit
2007 sisfb_get_northbridge(int basechipid)
2009 struct pci_dev *pdev = NULL;
2010 int nbridgenum, nbridgeidx, i;
2011 static const unsigned short nbridgeids[] = {
2012 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2013 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2014 PCI_DEVICE_ID_SI_730,
2015 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2016 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2017 PCI_DEVICE_ID_SI_651,
2018 PCI_DEVICE_ID_SI_740,
2019 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
2020 PCI_DEVICE_ID_SI_741,
2021 PCI_DEVICE_ID_SI_660,
2022 PCI_DEVICE_ID_SI_760,
2023 PCI_DEVICE_ID_SI_761
2026 switch(basechipid) {
2027 #ifdef CONFIG_FB_SIS_300
2028 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2029 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2031 #ifdef CONFIG_FB_SIS_315
2032 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2033 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
2034 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
2036 default: return NULL;
2038 for(i = 0; i < nbridgenum; i++) {
2039 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2040 nbridgeids[nbridgeidx+i], NULL)))
2046 static int __devinit
2047 sisfb_get_dram_size(struct sis_video_info *ivideo)
2049 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2053 ivideo->video_size = 0;
2054 ivideo->UMAsize = ivideo->LFBsize = 0;
2056 switch(ivideo->chip) {
2057 #ifdef CONFIG_FB_SIS_300
2059 inSISIDXREG(SISSR, 0x14, reg);
2060 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2065 if(!ivideo->nbridge)
2067 pci_read_config_byte(ivideo->nbridge, 0x63, ®);
2068 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2071 #ifdef CONFIG_FB_SIS_315
2075 inSISIDXREG(SISSR, 0x14, reg);
2076 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2077 switch((reg >> 2) & 0x03) {
2080 ivideo->video_size <<= 1;
2083 ivideo->video_size += (ivideo->video_size/2);
2087 inSISIDXREG(SISSR, 0x14, reg);
2088 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2089 if(reg & 0x0c) ivideo->video_size <<= 1;
2094 inSISIDXREG(SISSR, 0x14, reg);
2095 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2099 inSISIDXREG(SISCR, 0x79, reg);
2100 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2105 inSISIDXREG(SISCR, 0x79, reg);
2106 reg = (reg & 0xf0) >> 4;
2108 ivideo->video_size = (1 << reg) << 20;
2109 ivideo->UMAsize = ivideo->video_size;
2111 inSISIDXREG(SISCR, 0x78, reg);
2115 ivideo->LFBsize = (32 << 20);
2117 ivideo->LFBsize = (64 << 20);
2119 ivideo->video_size += ivideo->LFBsize;
2125 inSISIDXREG(SISSR, 0x14, reg);
2126 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2127 if(ivideo->chip != XGI_20) {
2128 reg = (reg & 0x0c) >> 2;
2129 if(ivideo->revision_id == 2) {
2130 if(reg & 0x01) reg = 0x02;
2133 if(reg == 0x02) ivideo->video_size <<= 1;
2134 else if(reg == 0x03) ivideo->video_size <<= 2;
2144 /* -------------- video bridge device detection --------------- */
2146 static void __devinit
2147 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2151 /* No CRT2 on XGI Z7 */
2152 if(ivideo->chip == XGI_20) {
2153 ivideo->sisfb_crt1off = 0;
2157 #ifdef CONFIG_FB_SIS_300
2158 if(ivideo->sisvga_engine == SIS_300_VGA) {
2159 inSISIDXREG(SISSR, 0x17, temp);
2160 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2161 /* PAL/NTSC is stored on SR16 on such machines */
2162 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2163 inSISIDXREG(SISSR, 0x16, temp);
2165 ivideo->vbflags |= TV_PAL;
2167 ivideo->vbflags |= TV_NTSC;
2173 inSISIDXREG(SISCR, 0x32, cr32);
2175 if(cr32 & SIS_CRT1) {
2176 ivideo->sisfb_crt1off = 0;
2178 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2181 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2183 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2184 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2185 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2187 /* Check given parms for hardware compatibility.
2188 * (Cannot do this in the search_xx routines since we don't
2189 * know what hardware we are running on then)
2192 if(ivideo->chip != SIS_550) {
2193 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2196 if(ivideo->sisfb_tvplug != -1) {
2197 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2198 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2199 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2200 ivideo->sisfb_tvplug = -1;
2201 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2205 if(ivideo->sisfb_tvplug != -1) {
2206 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2207 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2208 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2209 ivideo->sisfb_tvplug = -1;
2210 printk(KERN_ERR "sisfb: HiVision not supported\n");
2214 if(ivideo->sisfb_tvstd != -1) {
2215 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2216 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2217 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2218 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2219 ivideo->sisfb_tvstd = -1;
2220 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2225 /* Detect/set TV plug & type */
2226 if(ivideo->sisfb_tvplug != -1) {
2227 ivideo->vbflags |= ivideo->sisfb_tvplug;
2229 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2230 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2231 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2233 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2234 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2238 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2239 if(ivideo->sisfb_tvstd != -1) {
2240 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2241 ivideo->vbflags |= ivideo->sisfb_tvstd;
2243 if(ivideo->vbflags & TV_SCART) {
2244 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2245 ivideo->vbflags |= TV_PAL;
2247 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2248 if(ivideo->sisvga_engine == SIS_300_VGA) {
2249 inSISIDXREG(SISSR, 0x38, temp);
2250 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2251 else ivideo->vbflags |= TV_NTSC;
2252 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2253 inSISIDXREG(SISSR, 0x38, temp);
2254 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2255 else ivideo->vbflags |= TV_NTSC;
2257 inSISIDXREG(SISCR, 0x79, temp);
2258 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2259 else ivideo->vbflags |= TV_NTSC;
2264 /* Copy forceCRT1 option to CRT1off if option is given */
2265 if(ivideo->sisfb_forcecrt1 != -1) {
2266 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2270 /* ------------------ Sensing routines ------------------ */
2272 static BOOLEAN __devinit
2273 sisfb_test_DDC1(struct sis_video_info *ivideo)
2278 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2280 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2282 return (count == -1) ? FALSE : TRUE;
2285 static void __devinit
2286 sisfb_sense_crt1(struct sis_video_info *ivideo)
2288 BOOLEAN mustwait = FALSE;
2290 #ifdef CONFIG_FB_SIS_315
2296 inSISIDXREG(SISSR,0x1F,sr1F);
2297 orSISIDXREG(SISSR,0x1F,0x04);
2298 andSISIDXREG(SISSR,0x1F,0x3F);
2299 if(sr1F & 0xc0) mustwait = TRUE;
2301 #ifdef CONFIG_FB_SIS_315
2302 if(ivideo->sisvga_engine == SIS_315_VGA) {
2303 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2305 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2309 inSISIDXREG(SISCR,0x17,cr17);
2312 orSISIDXREG(SISCR,0x17,0x80);
2314 outSISIDXREG(SISSR, 0x00, 0x01);
2315 outSISIDXREG(SISSR, 0x00, 0x03);
2319 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2322 #ifdef CONFIG_FB_SIS_315
2323 if(ivideo->chip >= SIS_330) {
2324 andSISIDXREG(SISCR,0x32,~0x20);
2325 if(ivideo->chip >= SIS_340) {
2326 outSISIDXREG(SISCR, 0x57, 0x4a);
2328 outSISIDXREG(SISCR, 0x57, 0x5f);
2330 orSISIDXREG(SISCR, 0x53, 0x02);
2331 while((inSISREG(SISINPSTAT)) & 0x01) break;
2332 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2333 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2334 andSISIDXREG(SISCR, 0x53, 0xfd);
2335 andSISIDXREG(SISCR, 0x57, 0x00);
2339 if(temp == 0xffff) {
2342 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2343 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2344 } while(((temp == 0) || (temp == 0xffff)) && i--);
2346 if((temp == 0) || (temp == 0xffff)) {
2347 if(sisfb_test_DDC1(ivideo)) temp = 1;
2351 if((temp) && (temp != 0xffff)) {
2352 orSISIDXREG(SISCR,0x32,0x20);
2355 #ifdef CONFIG_FB_SIS_315
2356 if(ivideo->sisvga_engine == SIS_315_VGA) {
2357 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2361 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2363 outSISIDXREG(SISSR,0x1F,sr1F);
2366 /* Determine and detect attached devices on SiS30x */
2367 static void __devinit
2368 SiS_SenseLCD(struct sis_video_info *ivideo)
2370 unsigned char buffer[256];
2371 unsigned short temp, realcrtno, i;
2372 u8 reg, cr37 = 0, paneltype = 0;
2375 ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2377 /* LCD detection only for TMDS bridges */
2378 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2380 if(ivideo->vbflags2 & VB2_30xBDH)
2383 /* If LCD already set up by BIOS, skip it */
2384 inSISIDXREG(SISCR, 0x32, reg);
2389 if(ivideo->SiS_Pr.DDCPortMixup)
2392 /* Check DDC capabilities */
2393 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2394 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2396 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2400 i = 3; /* Number of retrys */
2402 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2403 ivideo->sisvga_engine, realcrtno, 1,
2404 &buffer[0], ivideo->vbflags2);
2405 } while((temp) && i--);
2410 /* No digital device */
2411 if(!(buffer[0x14] & 0x80))
2414 /* First detailed timing preferred timing? */
2415 if(!(buffer[0x18] & 0x02))
2418 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2419 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2431 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2442 if((buffer[0x47] & 0x18) == 0x18)
2443 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2447 outSISIDXREG(SISCR, 0x36, paneltype);
2449 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2450 orSISIDXREG(SISCR, 0x32, 0x08);
2452 ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2455 static int __devinit
2456 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2458 int temp, mytest, result, i, j;
2460 for(j = 0; j < 10; j++) {
2462 for(i = 0; i < 3; i++) {
2464 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2465 temp = (type >> 8) | (mytest & 0x00ff);
2466 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2467 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2470 inSISIDXREG(SISPART4,0x03,temp);
2473 if(temp == mytest) result++;
2475 outSISIDXREG(SISPART4,0x11,0x00);
2476 andSISIDXREG(SISPART4,0x10,0xe0);
2477 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2480 if((result == 0) || (result >= 2)) break;
2485 static void __devinit
2486 SiS_Sense30x(struct sis_video_info *ivideo)
2488 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2489 u16 svhs=0, svhs_c=0;
2490 u16 cvbs=0, cvbs_c=0;
2491 u16 vga2=0, vga2_c=0;
2493 char stdstr[] = "sisfb: Detected";
2494 char tvstr[] = "TV connected to";
2496 if(ivideo->vbflags2 & VB2_301) {
2497 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2498 inSISIDXREG(SISPART4,0x01,myflag);
2500 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2502 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2503 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2504 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2505 svhs = 0x0200; cvbs = 0x0100;
2506 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2507 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2511 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2512 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2513 svhs_c = 0x0408; cvbs_c = 0x0808;
2517 if(ivideo->haveXGIROM) {
2518 biosflag = ivideo->bios_abase[0x58] & 0x03;
2519 } else if(ivideo->newrom) {
2520 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2521 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2522 if(ivideo->bios_abase) {
2523 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2527 if(ivideo->chip == SIS_300) {
2528 inSISIDXREG(SISSR,0x3b,myflag);
2529 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2532 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2536 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2537 orSISIDXREG(SISSR,0x1e,0x20);
2539 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2540 if(ivideo->vbflags2 & VB2_30xC) {
2541 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2543 orSISIDXREG(SISPART4,0x0d,0x04);
2545 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2547 inSISIDXREG(SISPART2,0x00,backupP2_00);
2548 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2550 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2551 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2552 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2555 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2556 SISDoSense(ivideo, 0, 0);
2559 andSISIDXREG(SISCR, 0x32, ~0x14);
2561 if(vga2_c || vga2) {
2562 if(SISDoSense(ivideo, vga2, vga2_c)) {
2563 if(biosflag & 0x01) {
2564 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2565 orSISIDXREG(SISCR, 0x32, 0x04);
2567 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2568 orSISIDXREG(SISCR, 0x32, 0x10);
2573 andSISIDXREG(SISCR, 0x32, 0x3f);
2575 if(ivideo->vbflags2 & VB2_30xCLV) {
2576 orSISIDXREG(SISPART4,0x0d,0x04);
2579 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2580 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2581 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2582 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2583 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2584 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2585 orSISIDXREG(SISCR,0x32,0x80);
2588 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2591 andSISIDXREG(SISCR, 0x32, ~0x03);
2593 if(!(ivideo->vbflags & TV_YPBPR)) {
2594 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2595 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2596 orSISIDXREG(SISCR, 0x32, 0x02);
2598 if((biosflag & 0x02) || (!result)) {
2599 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2600 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2601 orSISIDXREG(SISCR, 0x32, 0x01);
2606 SISDoSense(ivideo, 0, 0);
2608 outSISIDXREG(SISPART2,0x00,backupP2_00);
2609 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2610 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2612 if(ivideo->vbflags2 & VB2_30xCLV) {
2613 inSISIDXREG(SISPART2,0x00,biosflag);
2614 if(biosflag & 0x20) {
2615 for(myflag = 2; myflag > 0; myflag--) {
2617 outSISIDXREG(SISPART2,0x00,biosflag);
2622 outSISIDXREG(SISPART2,0x00,backupP2_00);
2625 /* Determine and detect attached TV's on Chrontel */
2626 static void __devinit
2627 SiS_SenseCh(struct sis_video_info *ivideo)
2629 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2631 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2633 #ifdef CONFIG_FB_SIS_300
2634 unsigned char test[3];
2638 if(ivideo->chip < SIS_315H) {
2640 #ifdef CONFIG_FB_SIS_300
2641 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2642 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2643 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2644 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2645 /* See Chrontel TB31 for explanation */
2646 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2647 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2648 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2649 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2651 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2652 if(temp2 != temp1) temp1 = temp2;
2654 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2655 /* Read power status */
2656 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2657 if((temp1 & 0x03) != 0x03) {
2658 /* Power all outputs */
2659 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2660 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2662 /* Sense connected TV devices */
2663 for(i = 0; i < 3; i++) {
2664 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2665 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2666 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2667 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2668 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2669 if(!(temp1 & 0x08)) test[i] = 0x02;
2670 else if(!(temp1 & 0x02)) test[i] = 0x01;
2672 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2675 if(test[0] == test[1]) temp1 = test[0];
2676 else if(test[0] == test[2]) temp1 = test[0];
2677 else if(test[1] == test[2]) temp1 = test[1];
2680 "sisfb: TV detection unreliable - test results varied\n");
2684 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2685 ivideo->vbflags |= TV_SVIDEO;
2686 orSISIDXREG(SISCR, 0x32, 0x02);
2687 andSISIDXREG(SISCR, 0x32, ~0x05);
2688 } else if (temp1 == 0x01) {
2689 printk(KERN_INFO "%s CVBS output\n", stdstr);
2690 ivideo->vbflags |= TV_AVIDEO;
2691 orSISIDXREG(SISCR, 0x32, 0x01);
2692 andSISIDXREG(SISCR, 0x32, ~0x06);
2694 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2695 andSISIDXREG(SISCR, 0x32, ~0x07);
2697 } else if(temp1 == 0) {
2698 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2699 andSISIDXREG(SISCR, 0x32, ~0x07);
2701 /* Set general purpose IO for Chrontel communication */
2702 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2707 #ifdef CONFIG_FB_SIS_315
2708 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2709 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2710 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2711 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2712 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2714 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2715 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2717 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2718 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2719 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2720 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2722 if(temp2 & 0x02) temp1 |= 0x01;
2723 if(temp2 & 0x10) temp1 |= 0x01;
2724 if(temp2 & 0x04) temp1 |= 0x02;
2725 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2728 printk(KERN_INFO "%s CVBS output\n", stdstr);
2729 ivideo->vbflags |= TV_AVIDEO;
2730 orSISIDXREG(SISCR, 0x32, 0x01);
2731 andSISIDXREG(SISCR, 0x32, ~0x06);
2734 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2735 ivideo->vbflags |= TV_SVIDEO;
2736 orSISIDXREG(SISCR, 0x32, 0x02);
2737 andSISIDXREG(SISCR, 0x32, ~0x05);
2740 printk(KERN_INFO "%s SCART output\n", stdstr);
2741 orSISIDXREG(SISCR, 0x32, 0x04);
2742 andSISIDXREG(SISCR, 0x32, ~0x03);
2745 andSISIDXREG(SISCR, 0x32, ~0x07);
2751 static void __devinit
2752 sisfb_get_VB_type(struct sis_video_info *ivideo)
2754 char stdstr[] = "sisfb: Detected";
2755 char bridgestr[] = "video bridge";
2759 /* No CRT2 on XGI Z7 */
2760 if(ivideo->chip == XGI_20)
2763 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2766 inSISIDXREG(SISPART4, 0x01, reg);
2768 ivideo->vbflags |= VB_301; /* Deprecated */
2769 ivideo->vbflags2 |= VB2_301;
2770 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2771 } else if(reg < 0xc0) {
2772 ivideo->vbflags |= VB_301B; /* Deprecated */
2773 ivideo->vbflags2 |= VB2_301B;
2774 inSISIDXREG(SISPART4,0x23,reg);
2776 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2777 ivideo->vbflags2 |= VB2_30xBDH;
2778 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2780 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2782 } else if(reg < 0xd0) {
2783 ivideo->vbflags |= VB_301C; /* Deprecated */
2784 ivideo->vbflags2 |= VB2_301C;
2785 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2786 } else if(reg < 0xe0) {
2787 ivideo->vbflags |= VB_301LV; /* Deprecated */
2788 ivideo->vbflags2 |= VB2_301LV;
2789 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2790 } else if(reg <= 0xe1) {
2791 inSISIDXREG(SISPART4,0x39,reg);
2793 ivideo->vbflags |= VB_302LV; /* Deprecated */
2794 ivideo->vbflags2 |= VB2_302LV;
2795 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2797 ivideo->vbflags |= VB_301C; /* Deprecated */
2798 ivideo->vbflags2 |= VB2_301C;
2799 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2801 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2802 ivideo->vbflags2 |= VB2_302ELV;
2803 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2809 ivideo->vbflags |= VB_302B; /* Deprecated */
2810 ivideo->vbflags2 |= VB2_302B;
2811 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2815 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2816 inSISIDXREG(SISCR, 0x37, reg);
2817 reg &= SIS_EXTERNAL_CHIP_MASK;
2819 if(ivideo->sisvga_engine == SIS_300_VGA) {
2820 #ifdef CONFIG_FB_SIS_300
2822 case SIS_EXTERNAL_CHIP_LVDS:
2823 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2824 ivideo->vbflags2 |= VB2_LVDS;
2826 case SIS_EXTERNAL_CHIP_TRUMPION:
2827 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2828 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2830 case SIS_EXTERNAL_CHIP_CHRONTEL:
2831 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2832 ivideo->vbflags2 |= VB2_CHRONTEL;
2834 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2835 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2836 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2839 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2841 } else if(ivideo->chip < SIS_661) {
2842 #ifdef CONFIG_FB_SIS_315
2844 case SIS310_EXTERNAL_CHIP_LVDS:
2845 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2846 ivideo->vbflags2 |= VB2_LVDS;
2848 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2849 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2850 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2853 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2855 } else if(ivideo->chip >= SIS_661) {
2856 #ifdef CONFIG_FB_SIS_315
2857 inSISIDXREG(SISCR, 0x38, reg);
2861 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2862 ivideo->vbflags2 |= VB2_LVDS;
2865 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2866 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2869 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2870 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2873 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2876 if(ivideo->vbflags2 & VB2_LVDS) {
2877 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2879 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2880 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2882 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2883 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2885 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2886 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2890 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2891 SiS_SenseLCD(ivideo);
2892 SiS_Sense30x(ivideo);
2893 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2894 SiS_SenseCh(ivideo);
2898 /* ---------- Engine initialization routines ------------ */
2901 sisfb_engine_init(struct sis_video_info *ivideo)
2904 /* Initialize command queue (we use MMIO only) */
2906 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2908 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2909 MMIO_CMD_QUEUE_CAP |
2913 #ifdef CONFIG_FB_SIS_300
2914 if(ivideo->sisvga_engine == SIS_300_VGA) {
2918 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2920 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2923 tq_state |= (u8)(tqueue_pos >> 8);
2924 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2926 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2928 ivideo->caps |= TURBO_QUEUE_CAP;
2932 #ifdef CONFIG_FB_SIS_315
2933 if(ivideo->sisvga_engine == SIS_315_VGA) {
2934 u32 tempq = 0, templ;
2937 if(ivideo->chip == XGI_20) {
2938 switch(ivideo->cmdQueueSize) {
2940 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2944 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2947 switch(ivideo->cmdQueueSize) {
2948 case (4 * 1024 * 1024):
2949 temp = SIS_CMD_QUEUE_SIZE_4M;
2951 case (2 * 1024 * 1024):
2952 temp = SIS_CMD_QUEUE_SIZE_2M;
2954 case (1 * 1024 * 1024):
2955 temp = SIS_CMD_QUEUE_SIZE_1M;
2959 temp = SIS_CMD_QUEUE_SIZE_512k;
2963 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2964 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2966 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2967 /* Must disable dual pipe on XGI_40. Can't do
2968 * this in MMIO mode, because it requires
2969 * setting/clearing a bit in the MMIO fire trigger
2972 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2974 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2976 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2978 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2979 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2981 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2982 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2984 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2985 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2986 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2987 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2989 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2991 sisfb_syncaccel(ivideo);
2993 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2998 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2999 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3001 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3002 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3004 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3005 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3007 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3011 ivideo->engineok = 1;
3014 static void __devinit
3015 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3020 inSISIDXREG(SISCR, 0x36, reg);
3022 if(ivideo->sisvga_engine == SIS_300_VGA) {
3023 ivideo->CRT2LCDType = sis300paneltype[reg];
3024 } else if(ivideo->chip >= SIS_661) {
3025 ivideo->CRT2LCDType = sis661paneltype[reg];
3027 ivideo->CRT2LCDType = sis310paneltype[reg];
3028 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3029 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3030 (ivideo->CRT2LCDType != LCD_320x240_3)) {
3031 ivideo->CRT2LCDType = LCD_320x240;
3036 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3037 /* For broken BIOSes: Assume 1024x768, RGB18 */
3038 ivideo->CRT2LCDType = LCD_1024x768;
3039 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3040 setSISIDXREG(SISCR,0x37,0xee,0x01);
3041 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3044 for(i = 0; i < SIS_LCD_NUMBER; i++) {
3045 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3046 ivideo->lcdxres = sis_lcd_data[i].xres;
3047 ivideo->lcdyres = sis_lcd_data[i].yres;
3048 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3053 #ifdef CONFIG_FB_SIS_300
3054 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3055 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3056 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3057 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3058 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
3059 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3060 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3061 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
3062 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3066 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3067 ivideo->lcdxres, ivideo->lcdyres);
3070 static void __devinit
3071 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3073 #ifdef CONFIG_FB_SIS_300
3074 /* Save the current PanelDelayCompensation if the LCD is currently used */
3075 if(ivideo->sisvga_engine == SIS_300_VGA) {
3076 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3078 inSISIDXREG(SISCR,0x30,tmp);
3080 /* Currently on LCD? If yes, read current pdc */
3081 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3082 ivideo->detectedpdc &= 0x3c;
3083 if(ivideo->SiS_Pr.PDC == -1) {
3084 /* Let option override detection */
3085 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3087 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3088 ivideo->detectedpdc);
3090 if((ivideo->SiS_Pr.PDC != -1) &&
3091 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3092 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3093 ivideo->SiS_Pr.PDC);
3099 #ifdef CONFIG_FB_SIS_315
3100 if(ivideo->sisvga_engine == SIS_315_VGA) {
3102 /* Try to find about LCDA */
3103 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3105 inSISIDXREG(SISPART1,0x13,tmp);
3107 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3108 ivideo->detectedlcda = 0x03;
3113 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3115 inSISIDXREG(SISCR,0x30,tmp);
3116 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3117 /* Currently on LCD? If yes, read current pdc */
3119 inSISIDXREG(SISPART1,0x2D,pdc);
3120 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3121 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3122 inSISIDXREG(SISPART1,0x35,pdc);
3123 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3124 inSISIDXREG(SISPART1,0x20,pdc);
3125 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3126 if(ivideo->newrom) {
3127 /* New ROM invalidates other PDC resp. */
3128 if(ivideo->detectedlcda != 0xff) {
3129 ivideo->detectedpdc = 0xff;
3131 ivideo->detectedpdca = 0xff;
3134 if(ivideo->SiS_Pr.PDC == -1) {
3135 if(ivideo->detectedpdc != 0xff) {
3136 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3139 if(ivideo->SiS_Pr.PDCA == -1) {
3140 if(ivideo->detectedpdca != 0xff) {
3141 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3144 if(ivideo->detectedpdc != 0xff) {
3146 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3147 ivideo->detectedpdc);
3149 if(ivideo->detectedpdca != 0xff) {
3151 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3152 ivideo->detectedpdca);
3157 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3158 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3159 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3160 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3161 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3162 ivideo->SiS_Pr.HaveEMI = TRUE;
3163 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3164 ivideo->SiS_Pr.HaveEMILCD = TRUE;
3169 /* Let user override detected PDCs (all bridges) */
3170 if(ivideo->vbflags2 & VB2_30xBLV) {
3171 if((ivideo->SiS_Pr.PDC != -1) &&
3172 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3173 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3174 ivideo->SiS_Pr.PDC);
3176 if((ivideo->SiS_Pr.PDCA != -1) &&
3177 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3178 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3179 ivideo->SiS_Pr.PDCA);
3187 /* -------------------- Memory manager routines ---------------------- */
3189 static u32 __devinit
3190 sisfb_getheapstart(struct sis_video_info *ivideo)
3192 u32 ret = ivideo->sisfb_parm_mem * 1024;
3193 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3196 /* Calculate heap start = end of memory for console
3198 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3199 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3201 * On 76x in UMA+LFB mode, the layout is as follows:
3202 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3203 * where the heap is the entire UMA area, eventually
3204 * into the LFB area if the given mem parameter is
3205 * higher than the size of the UMA memory.
3207 * Basically given by "mem" parameter
3209 * maximum = videosize - cmd_queue - hwcursor
3210 * (results in a heap of size 0)
3211 * default = SiS 300: depends on videosize
3212 * SiS 315/330/340/XGI: 32k below max
3215 if(ivideo->sisvga_engine == SIS_300_VGA) {
3216 if(ivideo->video_size > 0x1000000) {
3218 } else if(ivideo->video_size > 0x800000) {
3223 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3226 def = maxoffs - 0x8000;
3229 /* Use default for secondary card for now (FIXME) */
3230 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3236 static u32 __devinit
3237 sisfb_getheapsize(struct sis_video_info *ivideo)
3239 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3242 if(ivideo->UMAsize && ivideo->LFBsize) {
3243 if( (!ivideo->sisfb_parm_mem) ||
3244 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3245 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3246 ret = ivideo->UMAsize;
3247 max -= ivideo->UMAsize;
3249 ret = max - (ivideo->sisfb_parm_mem * 1024);
3250 max = ivideo->sisfb_parm_mem * 1024;
3252 ivideo->video_offset = ret;
3253 ivideo->sisfb_mem = max;
3255 ret = max - ivideo->heapstart;
3256 ivideo->sisfb_mem = ivideo->heapstart;
3262 static int __devinit
3263 sisfb_heap_init(struct sis_video_info *ivideo)
3267 ivideo->video_offset = 0;
3268 if(ivideo->sisfb_parm_mem) {
3269 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3270 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3271 ivideo->sisfb_parm_mem = 0;
3275 ivideo->heapstart = sisfb_getheapstart(ivideo);
3276 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3278 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3279 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3281 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3282 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3284 ivideo->sisfb_heap.vinfo = ivideo;
3286 ivideo->sisfb_heap.poha_chain = NULL;
3287 ivideo->sisfb_heap.poh_freelist = NULL;
3289 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3293 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3294 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3295 poh->size = ivideo->sisfb_heap_size;
3296 poh->offset = ivideo->heapstart;
3298 ivideo->sisfb_heap.oh_free.poh_next = poh;
3299 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3300 ivideo->sisfb_heap.oh_free.size = 0;
3301 ivideo->sisfb_heap.max_freesize = poh->size;
3303 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3304 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3305 ivideo->sisfb_heap.oh_used.size = SENTINEL;
3307 if(ivideo->cardnumber == 0) {
3308 /* For the first card, make this heap the "global" one
3309 * for old DRM (which could handle only one card)
3311 sisfb_heap = &ivideo->sisfb_heap;
3317 static struct SIS_OH *
3318 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3320 struct SIS_OHALLOC *poha;
3325 if(memheap->poh_freelist == NULL) {
3326 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3330 poha->poha_next = memheap->poha_chain;
3331 memheap->poha_chain = poha;
3333 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3335 poh = &poha->aoh[0];
3336 for(i = cOhs - 1; i != 0; i--) {
3337 poh->poh_next = poh + 1;
3341 poh->poh_next = NULL;
3342 memheap->poh_freelist = &poha->aoh[0];
3345 poh = memheap->poh_freelist;
3346 memheap->poh_freelist = poh->poh_next;
3351 static struct SIS_OH *
3352 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3354 struct SIS_OH *pohThis;
3355 struct SIS_OH *pohRoot;
3358 if(size > memheap->max_freesize) {
3359 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3360 (unsigned int) size / 1024);
3364 pohThis = memheap->oh_free.poh_next;
3366 while(pohThis != &memheap->oh_free) {
3367 if(size <= pohThis->size) {
3371 pohThis = pohThis->poh_next;
3375 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3376 (unsigned int) size / 1024);
3380 if(size == pohThis->size) {
3382 sisfb_delete_node(pohThis);
3384 pohRoot = sisfb_poh_new_node(memheap);
3388 pohRoot->offset = pohThis->offset;
3389 pohRoot->size = size;
3391 pohThis->offset += size;
3392 pohThis->size -= size;
3395 memheap->max_freesize -= size;
3397 pohThis = &memheap->oh_used;
3398 sisfb_insert_node(pohThis, pohRoot);
3404 sisfb_delete_node(struct SIS_OH *poh)
3406 poh->poh_prev->poh_next = poh->poh_next;
3407 poh->poh_next->poh_prev = poh->poh_prev;
3411 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3413 struct SIS_OH *pohTemp = pohList->poh_next;
3415 pohList->poh_next = poh;
3416 pohTemp->poh_prev = poh;
3418 poh->poh_prev = pohList;
3419 poh->poh_next = pohTemp;
3422 static struct SIS_OH *
3423 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3425 struct SIS_OH *pohThis;
3426 struct SIS_OH *poh_freed;
3427 struct SIS_OH *poh_prev;
3428 struct SIS_OH *poh_next;
3433 poh_freed = memheap->oh_used.poh_next;
3435 while(poh_freed != &memheap->oh_used) {
3436 if(poh_freed->offset == base) {
3441 poh_freed = poh_freed->poh_next;
3447 memheap->max_freesize += poh_freed->size;
3449 poh_prev = poh_next = NULL;
3450 ulUpper = poh_freed->offset + poh_freed->size;
3451 ulLower = poh_freed->offset;
3453 pohThis = memheap->oh_free.poh_next;
3455 while(pohThis != &memheap->oh_free) {
3456 if(pohThis->offset == ulUpper) {
3458 } else if((pohThis->offset + pohThis->size) == ulLower) {
3461 pohThis = pohThis->poh_next;
3464 sisfb_delete_node(poh_freed);
3466 if(poh_prev && poh_next) {
3467 poh_prev->size += (poh_freed->size + poh_next->size);
3468 sisfb_delete_node(poh_next);
3469 sisfb_free_node(memheap, poh_freed);
3470 sisfb_free_node(memheap, poh_next);
3475 poh_prev->size += poh_freed->size;
3476 sisfb_free_node(memheap, poh_freed);
3481 poh_next->size += poh_freed->size;
3482 poh_next->offset = poh_freed->offset;
3483 sisfb_free_node(memheap, poh_freed);
3487 sisfb_insert_node(&memheap->oh_free, poh_freed);
3493 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3498 poh->poh_next = memheap->poh_freelist;
3499 memheap->poh_freelist = poh;
3503 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3505 struct SIS_OH *poh = NULL;
3507 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3508 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3511 req->offset = req->size = 0;
3512 DPRINTK("sisfb: Video RAM allocation failed\n");
3514 req->offset = poh->offset;
3515 req->size = poh->size;
3516 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3517 (poh->offset + ivideo->video_vbase));
3522 sis_malloc(struct sis_memreq *req)
3524 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3526 if(&ivideo->sisfb_heap == sisfb_heap)
3527 sis_int_malloc(ivideo, req);
3529 req->offset = req->size = 0;
3533 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3535 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3537 sis_int_malloc(ivideo, req);
3540 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3543 sis_int_free(struct sis_video_info *ivideo, u32 base)
3547 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3550 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3553 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3554 (unsigned int) base);
3561 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3563 sis_int_free(ivideo, base);
3567 sis_free_new(struct pci_dev *pdev, u32 base)
3569 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3571 sis_int_free(ivideo, base);
3574 /* --------------------- SetMode routines ------------------------- */
3577 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3581 /* Check if MMIO and engines are enabled,
3582 * and sync in case they are. Can't use
3583 * ivideo->accel here, as this might have
3584 * been changed before this is called.
3586 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3587 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3588 /* MMIO and 2D/3D engine enabled? */
3589 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3590 #ifdef CONFIG_FB_SIS_300
3591 if(ivideo->sisvga_engine == SIS_300_VGA) {
3592 /* Don't care about TurboQueue. It's
3593 * enough to know that the engines
3596 sisfb_syncaccel(ivideo);
3599 #ifdef CONFIG_FB_SIS_315
3600 if(ivideo->sisvga_engine == SIS_315_VGA) {
3601 /* Check that any queue mode is
3602 * enabled, and that the queue
3603 * is not in the state of "reset"
3605 inSISIDXREG(SISSR, 0x26, cr30);
3606 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3607 sisfb_syncaccel(ivideo);
3615 sisfb_pre_setmode(struct sis_video_info *ivideo)
3617 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3620 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3622 outSISIDXREG(SISSR, 0x05, 0x86);
3624 inSISIDXREG(SISCR, 0x31, cr31);
3628 cr33 = ivideo->rate_idx & 0x0F;
3630 #ifdef CONFIG_FB_SIS_315
3631 if(ivideo->sisvga_engine == SIS_315_VGA) {
3632 if(ivideo->chip >= SIS_661) {
3633 inSISIDXREG(SISCR, 0x38, cr38);
3634 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3637 inSISIDXREG(SISCR, tvregnum, cr38);
3638 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3642 #ifdef CONFIG_FB_SIS_300
3643 if(ivideo->sisvga_engine == SIS_300_VGA) {
3645 inSISIDXREG(SISCR, tvregnum, cr38);
3649 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3650 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3651 ivideo->curFSTN = ivideo->curDSTN = 0;
3653 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3656 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3657 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3658 #ifdef CONFIG_FB_SIS_315
3659 if(ivideo->chip >= SIS_661) {
3661 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3662 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3663 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3664 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3666 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3667 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3668 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3670 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3671 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3672 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3674 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3677 } else if((ivideo->vbflags & TV_HIVISION) &&
3678 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3679 if(ivideo->chip >= SIS_661) {
3685 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3688 ivideo->currentvbflags |= TV_HIVISION;
3689 } else if(ivideo->vbflags & TV_SCART) {
3690 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3693 ivideo->currentvbflags |= TV_SCART;
3695 if(ivideo->vbflags & TV_SVIDEO) {
3696 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3697 ivideo->currentvbflags |= TV_SVIDEO;
3699 if(ivideo->vbflags & TV_AVIDEO) {
3700 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3701 ivideo->currentvbflags |= TV_AVIDEO;
3704 cr31 |= SIS_DRIVER_MODE;
3706 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3707 if(ivideo->vbflags & TV_PAL) {
3708 cr31 |= 0x01; cr35 |= 0x01;
3709 ivideo->currentvbflags |= TV_PAL;
3710 if(ivideo->vbflags & TV_PALM) {
3711 cr38 |= 0x40; cr35 |= 0x04;
3712 ivideo->currentvbflags |= TV_PALM;
3713 } else if(ivideo->vbflags & TV_PALN) {
3714 cr38 |= 0x80; cr35 |= 0x08;
3715 ivideo->currentvbflags |= TV_PALN;
3718 cr31 &= ~0x01; cr35 &= ~0x01;
3719 ivideo->currentvbflags |= TV_NTSC;
3720 if(ivideo->vbflags & TV_NTSCJ) {
3721 cr38 |= 0x40; cr35 |= 0x02;
3722 ivideo->currentvbflags |= TV_NTSCJ;
3729 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3730 cr31 |= SIS_DRIVER_MODE;
3731 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3732 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3733 ivideo->curFSTN = ivideo->sisfb_fstn;
3734 ivideo->curDSTN = ivideo->sisfb_dstn;
3738 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3739 cr31 |= SIS_DRIVER_MODE;
3740 if(ivideo->sisfb_nocrt2rate) {
3741 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3743 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3747 default: /* disable CRT2 */
3749 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3752 outSISIDXREG(SISCR, 0x30, cr30);
3753 outSISIDXREG(SISCR, 0x33, cr33);
3755 if(ivideo->chip >= SIS_661) {
3756 #ifdef CONFIG_FB_SIS_315
3757 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3758 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3759 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3760 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3762 } else if(ivideo->chip != SIS_300) {
3763 outSISIDXREG(SISCR, tvregnum, cr38);
3765 outSISIDXREG(SISCR, 0x31, cr31);
3767 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3769 sisfb_check_engine_and_sync(ivideo);
3772 /* Fix SR11 for 661 and later */
3773 #ifdef CONFIG_FB_SIS_315
3775 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3779 if(ivideo->chip >= SIS_661) {
3780 inSISIDXREG(SISSR,0x11,tmpreg);
3782 inSISIDXREG(SISSR,0x3e,tmpreg);
3783 tmpreg = (tmpreg + 1) & 0xff;
3784 outSISIDXREG(SISSR,0x3e,tmpreg);
3785 inSISIDXREG(SISSR,0x11,tmpreg);
3788 andSISIDXREG(SISSR,0x11,0x0f);
3795 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3797 if(val > 32) val = 32;
3798 if(val < -32) val = -32;
3799 ivideo->tvxpos = val;
3801 if(ivideo->sisfblocked) return;
3802 if(!ivideo->modechanged) return;
3804 if(ivideo->currentvbflags & CRT2_TV) {
3806 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3808 int x = ivideo->tvx;
3810 switch(ivideo->chronteltype) {
3814 outSISIDXREG(SISSR,0x05,0x86);
3815 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3816 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3819 /* Not supported by hardware */
3823 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3825 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3826 unsigned short temp;
3828 p2_1f = ivideo->p2_1f;
3829 p2_20 = ivideo->p2_20;
3830 p2_2b = ivideo->p2_2b;
3831 p2_42 = ivideo->p2_42;
3832 p2_43 = ivideo->p2_43;
3834 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3836 p2_1f = temp & 0xff;
3837 p2_20 = (temp & 0xf00) >> 4;
3838 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3839 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3841 p2_43 = temp & 0xff;
3842 p2_42 = (temp & 0xf00) >> 4;
3843 outSISIDXREG(SISPART2,0x1f,p2_1f);
3844 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3845 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3846 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3847 outSISIDXREG(SISPART2,0x43,p2_43);
3853 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3855 if(val > 32) val = 32;
3856 if(val < -32) val = -32;
3857 ivideo->tvypos = val;
3859 if(ivideo->sisfblocked) return;
3860 if(!ivideo->modechanged) return;
3862 if(ivideo->currentvbflags & CRT2_TV) {
3864 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3866 int y = ivideo->tvy;
3868 switch(ivideo->chronteltype) {
3872 outSISIDXREG(SISSR,0x05,0x86);
3873 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3874 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3877 /* Not supported by hardware */
3881 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3885 p2_01 = ivideo->p2_01;
3886 p2_02 = ivideo->p2_02;
3890 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3891 while((p2_01 <= 0) || (p2_02 <= 0)) {
3896 outSISIDXREG(SISPART2,0x01,p2_01);
3897 outSISIDXREG(SISPART2,0x02,p2_02);
3903 sisfb_post_setmode(struct sis_video_info *ivideo)
3905 BOOLEAN crt1isoff = FALSE;
3906 BOOLEAN doit = TRUE;
3907 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3910 #ifdef CONFIG_FB_SIS_315
3914 outSISIDXREG(SISSR, 0x05, 0x86);
3916 #ifdef CONFIG_FB_SIS_315
3917 sisfb_fixup_SR11(ivideo);
3920 /* Now we actually HAVE changed the display mode */
3921 ivideo->modechanged = 1;
3923 /* We can't switch off CRT1 if bridge is in slave mode */
3924 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3925 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3927 ivideo->sisfb_crt1off = 0;
3929 #ifdef CONFIG_FB_SIS_300
3930 if(ivideo->sisvga_engine == SIS_300_VGA) {
3931 if((ivideo->sisfb_crt1off) && (doit)) {
3938 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3941 #ifdef CONFIG_FB_SIS_315
3942 if(ivideo->sisvga_engine == SIS_315_VGA) {
3943 if((ivideo->sisfb_crt1off) && (doit)) {
3952 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3953 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3958 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3959 ivideo->currentvbflags |= VB_SINGLE_MODE;
3961 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3962 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3963 ivideo->currentvbflags |= VB_MIRROR_MODE;
3965 ivideo->currentvbflags |= VB_SINGLE_MODE;
3969 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3971 if(ivideo->currentvbflags & CRT2_TV) {
3972 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3973 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3974 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3975 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3976 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3977 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3978 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3979 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3980 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3981 if(ivideo->chronteltype == 1) {
3982 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3983 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3984 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3985 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3990 if(ivideo->tvxpos) {
3991 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3993 if(ivideo->tvypos) {
3994 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3997 /* Eventually sync engines */
3998 sisfb_check_engine_and_sync(ivideo);
4000 /* (Re-)Initialize chip engines */
4002 sisfb_engine_init(ivideo);
4004 ivideo->engineok = 0;
4009 sisfb_reset_mode(struct sis_video_info *ivideo)
4011 if(sisfb_set_mode(ivideo, 0))
4014 sisfb_set_pitch(ivideo);
4015 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4016 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
4022 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4026 switch(sisfb_command->sisfb_cmd) {
4027 case SISFB_CMD_GETVBFLAGS:
4028 if(!ivideo->modechanged) {
4029 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4031 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4032 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4033 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
4036 case SISFB_CMD_SWITCHCRT1:
4037 /* arg[0]: 0 = off, 1 = on, 99 = query */
4038 if(!ivideo->modechanged) {
4039 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4040 } else if(sisfb_command->sisfb_arg[0] == 99) {
4042 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4043 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4044 } else if(ivideo->sisfblocked) {
4045 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4046 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4047 (sisfb_command->sisfb_arg[0] == 0)) {
4048 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4050 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4051 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4052 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4053 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4054 ivideo->sisfb_crt1off = mycrt1off;
4055 if(sisfb_reset_mode(ivideo)) {
4056 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
4059 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4064 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4065 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4066 sisfb_command->sisfb_cmd);
4071 SISINITSTATIC int __init
4072 sisfb_setup(char *options)
4076 sisfb_setdefaultparms();
4078 if(!options || !(*options))
4081 while((this_opt = strsep(&options, ",")) != NULL) {
4083 if(!(*this_opt)) continue;
4085 if(!strnicmp(this_opt, "off", 3)) {
4087 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4088 /* Need to check crt2 type first for fstn/dstn */
4089 sisfb_search_crt2type(this_opt + 14);
4090 } else if(!strnicmp(this_opt, "tvmode:",7)) {
4091 sisfb_search_tvstd(this_opt + 7);
4092 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4093 sisfb_search_tvstd(this_opt + 11);
4094 } else if(!strnicmp(this_opt, "mode:", 5)) {
4095 sisfb_search_mode(this_opt + 5, FALSE);
4096 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4097 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4098 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4099 } else if(!strnicmp(this_opt, "inverse", 7)) {
4101 /* fb_invert_cmaps(); */
4102 } else if(!strnicmp(this_opt, "font:", 5)) {
4103 if(strlen(this_opt + 5) < 40) {
4104 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4105 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4108 } else if(!strnicmp(this_opt, "rate:", 5)) {
4109 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4110 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4111 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4112 } else if(!strnicmp(this_opt, "mem:",4)) {
4113 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4114 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4115 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4116 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4117 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4118 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4120 } else if(!strnicmp(this_opt, "accel", 5)) {
4122 } else if(!strnicmp(this_opt, "noypan", 6)) {
4124 } else if(!strnicmp(this_opt, "ypan", 4)) {
4126 } else if(!strnicmp(this_opt, "nomax", 5)) {
4128 } else if(!strnicmp(this_opt, "max", 3)) {
4130 } else if(!strnicmp(this_opt, "userom:", 7)) {
4131 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4132 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4133 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4134 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4135 sisfb_nocrt2rate = 1;
4136 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4137 unsigned long temp = 2;
4138 temp = simple_strtoul(this_opt + 9, NULL, 0);
4139 if((temp == 0) || (temp == 1)) {
4140 sisfb_scalelcd = temp ^ 1;
4142 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4144 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4145 if((temp >= -32) && (temp <= 32)) {
4146 sisfb_tvxposoffset = temp;
4148 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4150 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4151 if((temp >= -32) && (temp <= 32)) {
4152 sisfb_tvyposoffset = temp;
4154 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4155 sisfb_search_specialtiming(this_opt + 14);
4156 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4158 temp = simple_strtoul(this_opt + 7, NULL, 0);
4159 if((temp >= 0) && (temp <= 3)) {
4160 sisfb_lvdshl = temp;
4162 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4163 sisfb_search_mode(this_opt, TRUE);
4164 #if !defined(__i386__) && !defined(__x86_64__)
4165 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4166 sisfb_resetcard = 1;
4167 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4168 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4171 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4180 static int __devinit
4181 sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4186 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4189 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4190 if(romptr > (0x10000 - 8))
4193 rom = rom_base + romptr;
4195 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4196 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4199 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4202 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4208 static unsigned char * __devinit
4209 sisfb_find_rom(struct pci_dev *pdev)
4211 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4212 SIS_IOTYPE1 *rom_base;
4213 unsigned char *myrombase = NULL;
4215 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4218 /* First, try the official pci ROM functions (except
4219 * on integrated chipsets which have no ROM).
4222 if(!ivideo->nbridge) {
4224 if((rom_base = pci_map_rom(pdev, &romsize))) {
4226 if(sisfb_check_rom(rom_base, ivideo)) {
4228 if((myrombase = vmalloc(65536))) {
4230 /* Work around bug in pci/rom.c: Folks forgot to check
4231 * whether the size retrieved from the BIOS image eventually
4232 * is larger than the mapped size
4234 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4235 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4237 memcpy_fromio(myrombase, rom_base,
4238 (romsize > 65536) ? 65536 : romsize);
4241 pci_unmap_rom(pdev, rom_base);
4245 if(myrombase) return myrombase;
4248 /* Otherwise do it the conventional way. */
4250 #if defined(__i386__) || defined(__x86_64__)
4252 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4254 rom_base = ioremap(temp, 65536);
4258 if(!sisfb_check_rom(rom_base, ivideo)) {
4263 if((myrombase = vmalloc(65536)))
4264 memcpy_fromio(myrombase, rom_base, 65536);
4273 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4274 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4275 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4277 rom_base = ioremap(ivideo->video_base, 65536);
4279 if(sisfb_check_rom(rom_base, ivideo)) {
4280 if((myrombase = vmalloc(65536)))
4281 memcpy_fromio(myrombase, rom_base, 65536);
4286 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4293 static void __devinit
4294 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4297 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4299 if(!ivideo->video_vbase) {
4301 "sisfb: Unable to map maximum video RAM for size detection\n");
4303 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4305 if((*mapsize) < (min << 20))
4308 if(ivideo->video_vbase) {
4310 "sisfb: Video RAM size detection limited to %dMB\n",
4311 (int)((*mapsize) >> 20));
4316 #ifdef CONFIG_FB_SIS_300
4317 static int __devinit
4318 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4320 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4321 unsigned short temp;
4325 andSISIDXREG(SISSR, 0x15, 0xFB);
4326 orSISIDXREG(SISSR, 0x15, 0x04);
4327 outSISIDXREG(SISSR, 0x13, 0x00);
4328 outSISIDXREG(SISSR, 0x14, 0xBF);
4330 for(i = 0; i < 2; i++) {
4332 for(j = 0; j < 4; j++) {
4333 writew(temp, FBAddress);
4334 if(readw(FBAddress) == temp)
4336 orSISIDXREG(SISSR, 0x3c, 0x01);
4337 inSISIDXREG(SISSR, 0x05, reg);
4338 inSISIDXREG(SISSR, 0x05, reg);
4339 andSISIDXREG(SISSR, 0x3c, 0xfe);
4340 inSISIDXREG(SISSR, 0x05, reg);
4341 inSISIDXREG(SISSR, 0x05, reg);
4346 writel(0x01234567L, FBAddress);
4347 writel(0x456789ABL, (FBAddress + 4));
4348 writel(0x89ABCDEFL, (FBAddress + 8));
4349 writel(0xCDEF0123L, (FBAddress + 12));
4351 inSISIDXREG(SISSR, 0x3b, reg);
4353 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4354 return 4; /* Channel A 128bit */
4357 if(readl((FBAddress + 4)) == 0x456789ABL)
4358 return 2; /* Channel B 64bit */
4360 return 1; /* 32bit */
4363 static int __devinit
4364 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4365 int PseudoRankCapacity, int PseudoAdrPinCount,
4366 unsigned int mapsize)
4368 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4369 unsigned short sr14;
4370 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4371 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4372 static const unsigned short SiS_DRAMType[17][5] = {
4373 {0x0C,0x0A,0x02,0x40,0x39},
4374 {0x0D,0x0A,0x01,0x40,0x48},
4375 {0x0C,0x09,0x02,0x20,0x35},
4376 {0x0D,0x09,0x01,0x20,0x44},
4377 {0x0C,0x08,0x02,0x10,0x31},
4378 {0x0D,0x08,0x01,0x10,0x40},
4379 {0x0C,0x0A,0x01,0x20,0x34},
4380 {0x0C,0x09,0x01,0x08,0x32},
4381 {0x0B,0x08,0x02,0x08,0x21},
4382 {0x0C,0x08,0x01,0x08,0x30},
4383 {0x0A,0x08,0x02,0x04,0x11},
4384 {0x0B,0x0A,0x01,0x10,0x28},
4385 {0x09,0x08,0x02,0x02,0x01},
4386 {0x0B,0x09,0x01,0x08,0x24},
4387 {0x0B,0x08,0x01,0x04,0x20},
4388 {0x0A,0x08,0x01,0x02,0x10},
4389 {0x09,0x08,0x01,0x01,0x00}
4392 for(k = 0; k <= 16; k++) {
4394 RankCapacity = buswidth * SiS_DRAMType[k][3];
4396 if(RankCapacity != PseudoRankCapacity)
4399 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4402 BankNumHigh = RankCapacity * 16 * iteration - 1;
4403 if(iteration == 3) { /* Rank No */
4404 BankNumMid = RankCapacity * 16 - 1;
4406 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4409 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4410 PhysicalAdrHigh = BankNumHigh;
4411 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4412 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4414 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4415 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4416 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4417 if(buswidth == 4) sr14 |= 0x80;
4418 else if(buswidth == 2) sr14 |= 0x40;
4419 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4420 outSISIDXREG(SISSR, 0x14, sr14);
4425 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4426 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4427 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4428 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4432 writew(((unsigned short)PhysicalAdrHigh),
4433 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4434 writew(((unsigned short)BankNumMid),
4435 (FBAddr + BankNumMid + PhysicalAdrHigh));
4436 writew(((unsigned short)PhysicalAdrHalfPage),
4437 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4438 writew(((unsigned short)PhysicalAdrOtherPage),
4439 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4442 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4449 static void __devinit
4450 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4452 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4454 int PseudoRankCapacity, PseudoAdrPinCount;
4456 buswidth = sisfb_post_300_buswidth(ivideo);
4458 for(i = 6; i >= 0; i--) {
4459 PseudoRankCapacity = 1 << i;
4460 for(j = 4; j >= 1; j--) {
4461 PseudoAdrPinCount = 15 - j;
4462 if((PseudoRankCapacity * j) <= 64) {
4463 if(sisfb_post_300_rwtest(ivideo,
4475 static void __devinit
4476 sisfb_post_sis300(struct pci_dev *pdev)
4478 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4479 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4480 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4481 u16 index, rindex, memtype = 0;
4482 unsigned int mapsize;
4484 if(!ivideo->SiS_Pr.UseROM)
4487 outSISIDXREG(SISSR, 0x05, 0x86);
4490 if(bios[0x52] & 0x80) {
4491 memtype = bios[0x52];
4493 inSISIDXREG(SISSR, 0x3a, memtype);
4498 v3 = 0x80; v6 = 0x80;
4499 if(ivideo->revision_id <= 0x13) {
4500 v1 = 0x44; v2 = 0x42;
4501 v4 = 0x44; v5 = 0x42;
4503 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4504 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4506 index = memtype * 5;
4507 rindex = index + 0x54;
4508 v1 = bios[rindex++];
4509 v2 = bios[rindex++];
4510 v3 = bios[rindex++];
4511 rindex = index + 0x7c;
4512 v4 = bios[rindex++];
4513 v5 = bios[rindex++];
4514 v6 = bios[rindex++];
4517 outSISIDXREG(SISSR, 0x28, v1);
4518 outSISIDXREG(SISSR, 0x29, v2);
4519 outSISIDXREG(SISSR, 0x2a, v3);
4520 outSISIDXREG(SISSR, 0x2e, v4);
4521 outSISIDXREG(SISSR, 0x2f, v5);
4522 outSISIDXREG(SISSR, 0x30, v6);
4527 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4529 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4531 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4532 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4536 v2 = bios[memtype + 8];
4537 v3 = bios[memtype + 16];
4538 v4 = bios[memtype + 24];
4539 v5 = bios[memtype + 32];
4540 v6 = bios[memtype + 40];
4541 v7 = bios[memtype + 48];
4542 v8 = bios[memtype + 56];
4544 if(ivideo->revision_id >= 0x80)
4546 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4547 outSISIDXREG(SISSR, 0x16, v2);
4548 outSISIDXREG(SISSR, 0x17, v3);
4549 outSISIDXREG(SISSR, 0x18, v4);
4550 outSISIDXREG(SISSR, 0x19, v5);
4551 outSISIDXREG(SISSR, 0x1a, v6);
4552 outSISIDXREG(SISSR, 0x1b, v7);
4553 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4554 andSISIDXREG(SISSR, 0x15 ,0xfb);
4555 orSISIDXREG(SISSR, 0x15, 0x04);
4557 if(bios[0x53] & 0x02) {
4558 orSISIDXREG(SISSR, 0x19, 0x20);
4561 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4562 if(ivideo->revision_id >= 0x80)
4564 outSISIDXREG(SISSR, 0x1f, v1);
4565 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4566 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4572 outSISIDXREG(SISSR, 0x23, v1);
4573 outSISIDXREG(SISSR, 0x24, v2);
4574 outSISIDXREG(SISSR, 0x25, v3);
4575 outSISIDXREG(SISSR, 0x21, 0x84);
4576 outSISIDXREG(SISSR, 0x22, 0x00);
4577 outSISIDXREG(SISCR, 0x37, 0x00);
4578 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4579 outSISIDXREG(SISPART1, 0x00, 0x00);
4580 v1 = 0x40; v2 = 0x11;
4585 outSISIDXREG(SISPART1, 0x02, v1);
4587 if(ivideo->revision_id >= 0x80)
4590 inSISIDXREG(SISPART4, 0x00, reg);
4591 if((reg == 1) || (reg == 2)) {
4592 outSISIDXREG(SISCR, 0x37, 0x02);
4593 outSISIDXREG(SISPART2, 0x00, 0x1c);
4594 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4595 if(ivideo->SiS_Pr.UseROM) {
4600 outSISIDXREG(SISPART4, 0x0d, v4);
4601 outSISIDXREG(SISPART4, 0x0e, v5);
4602 outSISIDXREG(SISPART4, 0x10, v6);
4603 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4604 inSISIDXREG(SISPART4, 0x01, reg);
4606 inSISIDXREG(SISPART4, 0x23, reg);
4609 outSISIDXREG(SISPART4, 0x23, reg);
4614 outSISIDXREG(SISSR, 0x32, v2);
4616 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4618 inSISIDXREG(SISSR, 0x16, reg);
4620 outSISIDXREG(SISCR, 0x35, reg);
4621 outSISIDXREG(SISCR, 0x83, 0x00);
4622 #if !defined(__i386__) && !defined(__x86_64__)
4623 if(sisfb_videoram) {
4624 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4625 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4626 outSISIDXREG(SISSR, 0x14, reg);
4629 /* Need to map max FB size for finding out about RAM size */
4631 sisfb_post_map_vram(ivideo, &mapsize, 4);
4633 if(ivideo->video_vbase) {
4634 sisfb_post_300_ramsize(pdev, mapsize);
4635 iounmap(ivideo->video_vbase);
4638 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4639 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4640 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4642 #if !defined(__i386__) && !defined(__x86_64__)
4649 inSISIDXREG(SISSR, 0x3a, reg);
4650 if((reg & 0x30) == 0x30) {
4651 v1 = 0x04; /* PCI */
4654 v1 = 0x14; /* AGP */
4658 outSISIDXREG(SISSR, 0x21, v1);
4659 outSISIDXREG(SISSR, 0x22, v2);
4662 sisfb_sense_crt1(ivideo);
4664 /* Set default mode, don't clear screen */
4665 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4666 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4667 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4668 ivideo->curFSTN = ivideo->curDSTN = 0;
4669 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4670 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4672 outSISIDXREG(SISSR, 0x05, 0x86);
4675 orSISIDXREG(SISSR, 0x01, 0x20);
4677 /* Save mode number in CR34 */
4678 outSISIDXREG(SISCR, 0x34, 0x2e);
4680 /* Let everyone know what the current mode is */
4681 ivideo->modeprechange = 0x2e;
4685 #ifdef CONFIG_FB_SIS_315
4687 static void __devinit
4688 sisfb_post_sis315330(struct pci_dev *pdev)
4694 static void __devinit
4695 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4700 for(i = 0; i <= (delay * 10 * 36); i++) {
4701 inSISIDXREG(SISSR, 0x05, reg);
4706 static int __devinit
4707 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4708 unsigned short pcivendor)
4710 struct pci_dev *pdev = NULL;
4711 unsigned short temp;
4714 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4715 temp = pdev->vendor;
4716 SIS_PCI_PUT_DEVICE(pdev);
4717 if(temp == pcivendor) {
4726 static int __devinit
4727 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4728 unsigned int enda, unsigned int mapsize)
4733 writel(0, ivideo->video_vbase);
4735 for(i = starta; i <= enda; i++) {
4738 writel(pos, ivideo->video_vbase + pos);
4741 sisfb_post_xgi_delay(ivideo, 150);
4743 if(readl(ivideo->video_vbase) != 0)
4746 for(i = starta; i <= enda; i++) {
4749 if(readl(ivideo->video_vbase + pos) != pos)
4758 static void __devinit
4759 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4761 unsigned int buswidth, ranksize, channelab, mapsize;
4764 static const u8 dramsr13[12 * 5] = {
4765 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4766 0x02, 0x0e, 0x0a, 0x40, 0x59,
4767 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4768 0x02, 0x0e, 0x09, 0x20, 0x55,
4769 0x02, 0x0d, 0x0a, 0x20, 0x49,
4770 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4771 0x02, 0x0e, 0x08, 0x10, 0x51,
4772 0x02, 0x0d, 0x09, 0x10, 0x45,
4773 0x02, 0x0c, 0x0a, 0x10, 0x39,
4774 0x02, 0x0d, 0x08, 0x08, 0x41,
4775 0x02, 0x0c, 0x09, 0x08, 0x35,
4776 0x02, 0x0c, 0x08, 0x04, 0x31
4778 static const u8 dramsr13_4[4 * 5] = {
4779 0x02, 0x0d, 0x09, 0x40, 0x45,
4780 0x02, 0x0c, 0x09, 0x20, 0x35,
4781 0x02, 0x0c, 0x08, 0x10, 0x31,
4782 0x02, 0x0b, 0x08, 0x08, 0x21
4785 /* Enable linear mode, disable 0xa0000 address decoding */
4786 /* We disable a0000 address decoding, because
4787 * - if running on x86, if the card is disabled, it means
4788 * that another card is in the system. We don't want
4789 * to interphere with that primary card's textmode.
4790 * - if running on non-x86, there usually is no VGA window
4793 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4795 /* Need to map max FB size for finding out about RAM size */
4796 mapsize = 256 << 20;
4797 sisfb_post_map_vram(ivideo, &mapsize, 32);
4799 if(!ivideo->video_vbase) {
4800 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4801 outSISIDXREG(SISSR, 0x13, 0x35);
4802 outSISIDXREG(SISSR, 0x14, 0x41);
4807 /* Non-interleaving */
4808 outSISIDXREG(SISSR, 0x15, 0x00);
4810 outSISIDXREG(SISSR, 0x1c, 0x00);
4812 if(ivideo->chip == XGI_20) {
4815 inSISIDXREG(SISCR, 0x97, reg);
4816 if(!(reg & 0x01)) { /* Single 32/16 */
4818 outSISIDXREG(SISSR, 0x13, 0xb1);
4819 outSISIDXREG(SISSR, 0x14, 0x52);
4820 sisfb_post_xgi_delay(ivideo, 1);
4822 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4825 outSISIDXREG(SISSR, 0x13, 0x31);
4826 outSISIDXREG(SISSR, 0x14, 0x42);
4827 sisfb_post_xgi_delay(ivideo, 1);
4828 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4832 outSISIDXREG(SISSR, 0x13, 0xb1);
4833 outSISIDXREG(SISSR, 0x14, 0x41);
4834 sisfb_post_xgi_delay(ivideo, 1);
4836 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4839 outSISIDXREG(SISSR, 0x13, 0x31);
4840 } else { /* Dual 16/8 */
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 outSISIDXREG(SISSR, 0x14, 0x31);
4851 sisfb_post_xgi_delay(ivideo, 1);
4852 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4856 outSISIDXREG(SISSR, 0x13, 0xb1);
4857 outSISIDXREG(SISSR, 0x14, 0x30);
4858 sisfb_post_xgi_delay(ivideo, 1);
4860 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4863 outSISIDXREG(SISSR, 0x13, 0x31);
4866 } else { /* XGI_40 */
4868 inSISIDXREG(SISCR, 0x97, reg);
4870 inSISIDXREG(SISSR, 0x39, reg);
4874 if(reg & 0x01) { /* DDRII */
4876 if(ivideo->revision_id == 2) {
4878 outSISIDXREG(SISSR, 0x13, 0xa1);
4879 outSISIDXREG(SISSR, 0x14, 0x44);
4881 sisfb_post_xgi_delay(ivideo, 1);
4882 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4885 outSISIDXREG(SISSR, 0x13, 0x21);
4886 outSISIDXREG(SISSR, 0x14, 0x34);
4887 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4891 outSISIDXREG(SISSR, 0x13, 0xa1);
4892 outSISIDXREG(SISSR, 0x14, 0x40);
4894 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4897 outSISIDXREG(SISSR, 0x13, 0x21);
4898 outSISIDXREG(SISSR, 0x14, 0x30);
4901 outSISIDXREG(SISSR, 0x13, 0xa1);
4902 outSISIDXREG(SISSR, 0x14, 0x4c);
4904 sisfb_post_xgi_delay(ivideo, 1);
4905 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4909 outSISIDXREG(SISSR, 0x14, 0x48);
4910 sisfb_post_xgi_delay(ivideo, 1);
4912 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4915 outSISIDXREG(SISSR, 0x13, 0x21);
4916 outSISIDXREG(SISSR, 0x14, 0x3c);
4919 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4923 outSISIDXREG(SISSR, 0x14, 0x38);
4927 sisfb_post_xgi_delay(ivideo, 1);
4932 if(ivideo->revision_id == 2) {
4934 outSISIDXREG(SISSR, 0x13, 0xa1);
4935 outSISIDXREG(SISSR, 0x14, 0x52);
4936 sisfb_post_xgi_delay(ivideo, 1);
4938 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4941 outSISIDXREG(SISSR, 0x13, 0x21);
4942 outSISIDXREG(SISSR, 0x14, 0x42);
4945 outSISIDXREG(SISSR, 0x13, 0xa1);
4946 outSISIDXREG(SISSR, 0x14, 0x5a);
4947 sisfb_post_xgi_delay(ivideo, 1);
4949 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4952 outSISIDXREG(SISSR, 0x13, 0x21);
4953 outSISIDXREG(SISSR, 0x14, 0x4a);
4955 sisfb_post_xgi_delay(ivideo, 1);
4961 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4962 sisfb_post_xgi_delay(ivideo, 1);
4964 j = (ivideo->chip == XGI_20) ? 5 : 9;
4965 k = (ivideo->chip == XGI_20) ? 12 : 4;
4967 for(i = 0; i < k; i++) {
4969 reg = (ivideo->chip == XGI_20) ?
4970 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4971 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4972 sisfb_post_xgi_delay(ivideo, 50);
4974 ranksize = (ivideo->chip == XGI_20) ?
4975 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4977 inSISIDXREG(SISSR, 0x13, reg);
4978 if(reg & 0x80) ranksize <<= 1;
4980 if(ivideo->chip == XGI_20) {
4981 if(buswidth == 16) ranksize <<= 1;
4982 else if(buswidth == 32) ranksize <<= 2;
4984 if(buswidth == 64) ranksize <<= 1;
4990 if((ranksize * l) <= 256) {
4991 while((ranksize >>= 1)) reg += 0x10;
4996 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4997 sisfb_post_xgi_delay(ivideo, 1);
4999 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5003 iounmap(ivideo->video_vbase);
5006 static void __devinit
5007 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5011 static const u8 cs90[8 * 3] = {
5021 static const u8 csb8[8 * 3] = {
5035 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5036 if(ivideo->haveXGIROM) {
5037 v1 = ivideo->bios_abase[0x90 + index];
5038 v2 = ivideo->bios_abase[0x90 + index + 1];
5039 v3 = ivideo->bios_abase[0x90 + index + 2];
5041 outSISIDXREG(SISSR, 0x28, v1);
5042 outSISIDXREG(SISSR, 0x29, v2);
5043 outSISIDXREG(SISSR, 0x2a, v3);
5044 sisfb_post_xgi_delay(ivideo, 0x43);
5045 sisfb_post_xgi_delay(ivideo, 0x43);
5046 sisfb_post_xgi_delay(ivideo, 0x43);
5048 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5049 if(ivideo->haveXGIROM) {
5050 v1 = ivideo->bios_abase[0xb8 + index];
5051 v2 = ivideo->bios_abase[0xb8 + index + 1];
5052 v3 = ivideo->bios_abase[0xb8 + index + 2];
5054 outSISIDXREG(SISSR, 0x2e, v1);
5055 outSISIDXREG(SISSR, 0x2f, v2);
5056 outSISIDXREG(SISSR, 0x30, v3);
5057 sisfb_post_xgi_delay(ivideo, 0x43);
5058 sisfb_post_xgi_delay(ivideo, 0x43);
5059 sisfb_post_xgi_delay(ivideo, 0x43);
5062 static int __devinit
5063 sisfb_post_xgi(struct pci_dev *pdev)
5065 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5066 unsigned char *bios = ivideo->bios_abase;
5067 struct pci_dev *mypdev = NULL;
5068 const u8 *ptr, *ptr2;
5069 u8 v1, v2, v3, v4, v5, reg, ramtype;
5070 u32 rega, regb, regd;
5072 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5073 static const u8 cs76[2] = { 0xa3, 0xfb };
5074 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5075 static const u8 cs158[8] = {
5076 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5078 static const u8 cs160[8] = {
5079 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5081 static const u8 cs168[8] = {
5082 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5084 static const u8 cs128[3 * 8] = {
5085 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5086 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5087 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5089 static const u8 cs148[2 * 8] = {
5090 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5093 static const u8 cs31a[8 * 4] = {
5094 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5095 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5096 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5097 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5099 static const u8 cs33a[8 * 4] = {
5100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5105 static const u8 cs45a[8 * 2] = {
5106 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5109 static const u8 cs170[7 * 8] = {
5110 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5111 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5112 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5113 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5114 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5115 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5116 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5118 static const u8 cs1a8[3 * 8] = {
5119 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5120 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5123 static const u8 cs100[2 * 8] = {
5124 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5125 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5129 reg = inSISREG(SISVGAENABLE) | 0x01;
5130 outSISREG(SISVGAENABLE, reg);
5133 reg = inSISREG(SISMISCR) | 0x01;
5134 outSISREG(SISMISCW, reg);
5137 outSISIDXREG(SISSR, 0x05, 0x86);
5138 inSISIDXREG(SISSR, 0x05, reg);
5142 /* Clear some regs */
5143 for(i = 0; i < 0x22; i++) {
5144 if(0x06 + i == 0x20) continue;
5145 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5147 for(i = 0; i < 0x0b; i++) {
5148 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5150 for(i = 0; i < 0x10; i++) {
5151 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5155 if(ivideo->haveXGIROM) {
5156 ptr = (const u8 *)&bios[0x78];
5158 for(i = 0; i < 3; i++) {
5159 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5163 if(ivideo->haveXGIROM) {
5164 ptr = (const u8 *)&bios[0x76];
5166 for(i = 0; i < 2; i++) {
5167 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5170 v1 = 0x18; v2 = 0x00;
5171 if(ivideo->haveXGIROM) {
5175 outSISIDXREG(SISSR, 0x07, v1);
5176 outSISIDXREG(SISSR, 0x11, 0x0f);
5177 outSISIDXREG(SISSR, 0x1f, v2);
5178 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5179 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5180 outSISIDXREG(SISSR, 0x27, 0x74);
5183 if(ivideo->haveXGIROM) {
5184 ptr = (const u8 *)&bios[0x7b];
5186 for(i = 0; i < 3; i++) {
5187 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5190 if(ivideo->chip == XGI_40) {
5191 if(ivideo->revision_id == 2) {
5192 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5194 outSISIDXREG(SISCR, 0x7d, 0xfe);
5195 outSISIDXREG(SISCR, 0x7e, 0x0f);
5197 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5198 andSISIDXREG(SISCR, 0x58, 0xd7);
5199 inSISIDXREG(SISCR, 0xcb, reg);
5201 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5205 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5206 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5208 if(ivideo->chip == XGI_20) {
5209 outSISIDXREG(SISSR, 0x36, 0x70);
5211 outSISIDXREG(SISVID, 0x00, 0x86);
5212 outSISIDXREG(SISVID, 0x32, 0x00);
5213 outSISIDXREG(SISVID, 0x30, 0x00);
5214 outSISIDXREG(SISVID, 0x32, 0x01);
5215 outSISIDXREG(SISVID, 0x30, 0x00);
5216 andSISIDXREG(SISVID, 0x2f, 0xdf);
5217 andSISIDXREG(SISCAP, 0x00, 0x3f);
5219 outSISIDXREG(SISPART1, 0x2f, 0x01);
5220 outSISIDXREG(SISPART1, 0x00, 0x00);
5221 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5222 outSISIDXREG(SISPART1, 0x2e, 0x08);
5223 andSISIDXREG(SISPART1, 0x35, 0x7f);
5224 andSISIDXREG(SISPART1, 0x50, 0xfe);
5226 inSISIDXREG(SISPART4, 0x00, reg);
5227 if(reg == 1 || reg == 2) {
5228 outSISIDXREG(SISPART2, 0x00, 0x1c);
5229 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5230 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5231 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5232 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5234 inSISIDXREG(SISPART4, 0x01, reg);
5235 if((reg & 0xf0) >= 0xb0) {
5236 inSISIDXREG(SISPART4, 0x23, reg);
5237 if(reg & 0x20) reg |= 0x40;
5238 outSISIDXREG(SISPART4, 0x23, reg);
5239 reg = (reg & 0x20) ? 0x02 : 0x00;
5240 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5246 inSISIDXREG(SISSR, 0x3b, reg);
5248 inSISIDXREG(SISSR, 0x3a, reg);
5249 v2 = (reg & 0x30) >> 3;
5250 if(!(v2 & 0x04)) v2 ^= 0x02;
5251 inSISIDXREG(SISSR, 0x39, reg);
5252 if(reg & 0x80) v2 |= 0x80;
5255 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5256 SIS_PCI_PUT_DEVICE(mypdev);
5257 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5262 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5264 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5266 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5268 pci_read_config_dword(mypdev, 0x94, ®d);
5270 pci_write_config_dword(mypdev, 0x94, regd);
5272 SIS_PCI_PUT_DEVICE(mypdev);
5273 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5275 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5276 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5277 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5278 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5279 if((v2 & 0x06) == 4)
5284 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5286 outSISIDXREG(SISSR, 0x22, v1);
5288 if(ivideo->revision_id == 2) {
5289 inSISIDXREG(SISSR, 0x3b, v1);
5290 inSISIDXREG(SISSR, 0x3a, v2);
5291 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5292 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5293 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5295 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5296 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5300 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5301 SIS_PCI_PUT_DEVICE(mypdev);
5306 inSISIDXREG(SISSR, 0x3b, reg);
5307 inSISIDXREG(SISCR, 0x5f, v2);
5308 if((!(reg & 0x02)) && (v2 & 0x0e))
5310 outSISIDXREG(SISSR, 0x27, v1);
5312 if(bios[0x64] & 0x01) {
5313 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5317 pci_read_config_dword(pdev, 0x50, ®d);
5318 regd = (regd >> 20) & 0x0f;
5321 orSISIDXREG(SISCR, 0x5f, 0x08);
5323 outSISIDXREG(SISCR, 0x48, v1);
5325 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5326 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5327 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5328 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5329 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5330 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5331 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5332 outSISIDXREG(SISCR, 0x74, 0xd0);
5333 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5334 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5335 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5337 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5339 SIS_PCI_PUT_DEVICE(mypdev);
5341 outSISIDXREG(SISCR, 0x77, v1);
5349 if(ivideo->haveXGIROM) {
5350 v1 = bios[0x140 + regb];
5352 outSISIDXREG(SISCR, 0x6d, v1);
5355 if(ivideo->haveXGIROM) {
5356 ptr = (const u8 *)&bios[0x128];
5358 for(i = 0, j = 0; i < 3; i++, j += 8) {
5359 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5364 if(ivideo->haveXGIROM) {
5365 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5366 ptr = (const u8 *)&bios[index];
5367 ptr2 = (const u8 *)&bios[index + 0x20];
5369 for(i = 0; i < 2; i++) {
5371 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5374 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5378 for(j = 0; j < 16; j++) {
5380 if(regd & 0x01) reg |= 0x04;
5381 if(regd & 0x02) reg |= 0x08;
5383 outSISIDXREG(SISCR, rega, reg);
5384 inSISIDXREG(SISCR, rega, reg);
5385 inSISIDXREG(SISCR, rega, reg);
5390 andSISIDXREG(SISCR, 0x6e, 0xfc);
5393 if(ivideo->haveXGIROM) {
5394 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5395 ptr = (const u8 *)&bios[index];
5397 for(i = 0; i < 4; i++) {
5398 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5400 for(j = 0; j < 2; j++) {
5403 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5407 for(k = 0; k < 16; k++) {
5409 if(regd & 0x01) reg |= 0x01;
5410 if(regd & 0x02) reg |= 0x02;
5412 outSISIDXREG(SISCR, 0x6f, reg);
5413 inSISIDXREG(SISCR, 0x6f, reg);
5414 inSISIDXREG(SISCR, 0x6f, reg);
5421 if(ivideo->haveXGIROM) {
5422 ptr = (const u8 *)&bios[0x148];
5424 for(i = 0, j = 0; i < 2; i++, j += 8) {
5425 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5428 andSISIDXREG(SISCR, 0x89, 0x8f);
5431 if(ivideo->haveXGIROM) {
5432 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5433 ptr = (const u8 *)&bios[index];
5435 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5437 for(i = 0; i < 5; i++) {
5439 if(regd & 0x01) reg |= 0x01;
5440 if(regd & 0x02) reg |= 0x02;
5442 outSISIDXREG(SISCR, 0x89, reg);
5443 inSISIDXREG(SISCR, 0x89, reg);
5444 inSISIDXREG(SISCR, 0x89, reg);
5448 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5449 if(ivideo->haveXGIROM) {
5450 v1 = bios[0x118 + regb];
5451 v2 = bios[0xf8 + regb];
5452 v3 = bios[0x120 + regb];
5455 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5456 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5457 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5458 outSISIDXREG(SISCR, 0x41, v2);
5461 if(ivideo->haveXGIROM) {
5462 ptr = (const u8 *)&bios[0x170];
5464 for(i = 0, j = 0; i < 7; i++, j += 8) {
5465 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5468 outSISIDXREG(SISCR, 0x59, v3);
5471 if(ivideo->haveXGIROM) {
5472 ptr = (const u8 *)&bios[0x1a8];
5474 for(i = 0, j = 0; i < 3; i++, j += 8) {
5475 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5479 if(ivideo->haveXGIROM) {
5480 ptr = (const u8 *)&bios[0x100];
5482 for(i = 0, j = 0; i < 2; i++, j += 8) {
5483 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5486 outSISIDXREG(SISCR, 0xcf, v4);
5488 outSISIDXREG(SISCR, 0x83, 0x09);
5489 outSISIDXREG(SISCR, 0x87, 0x00);
5491 if(ivideo->chip == XGI_40) {
5492 if( (ivideo->revision_id == 1) ||
5493 (ivideo->revision_id == 2) ) {
5494 outSISIDXREG(SISCR, 0x8c, 0x87);
5498 outSISIDXREG(SISSR, 0x17, 0x00);
5499 outSISIDXREG(SISSR, 0x1a, 0x87);
5501 if(ivideo->chip == XGI_20) {
5502 outSISIDXREG(SISSR, 0x15, 0x00);
5503 outSISIDXREG(SISSR, 0x1c, 0x00);
5506 ramtype = 0x00; v1 = 0x10;
5507 if(ivideo->haveXGIROM) {
5508 ramtype = bios[0x62];
5511 if(!(ramtype & 0x80)) {
5512 if(ivideo->chip == XGI_20) {
5513 outSISIDXREG(SISCR, 0x97, v1);
5514 inSISIDXREG(SISCR, 0x97, reg);
5516 ramtype = (reg & 0x01) << 1;
5519 inSISIDXREG(SISSR, 0x39, reg);
5520 ramtype = reg & 0x02;
5522 inSISIDXREG(SISSR, 0x3a, reg);
5523 ramtype = (reg >> 1) & 0x01;
5533 sisfb_post_xgi_setclocks(ivideo, regb);
5534 if((ivideo->chip == XGI_20) ||
5535 (ivideo->revision_id == 1) ||
5536 (ivideo->revision_id == 2)) {
5537 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5538 if(ivideo->haveXGIROM) {
5539 v1 = bios[regb + 0x158];
5540 v2 = bios[regb + 0x160];
5541 v3 = bios[regb + 0x168];
5543 outSISIDXREG(SISCR, 0x82, v1);
5544 outSISIDXREG(SISCR, 0x85, v2);
5545 outSISIDXREG(SISCR, 0x86, v3);
5547 outSISIDXREG(SISCR, 0x82, 0x88);
5548 outSISIDXREG(SISCR, 0x86, 0x00);
5549 inSISIDXREG(SISCR, 0x86, reg);
5550 outSISIDXREG(SISCR, 0x86, 0x88);
5551 inSISIDXREG(SISCR, 0x86, reg);
5552 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5553 outSISIDXREG(SISCR, 0x82, 0x77);
5554 outSISIDXREG(SISCR, 0x85, 0x00);
5555 inSISIDXREG(SISCR, 0x85, reg);
5556 outSISIDXREG(SISCR, 0x85, 0x88);
5557 inSISIDXREG(SISCR, 0x85, reg);
5558 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5559 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5561 if(ivideo->chip == XGI_40) {
5562 outSISIDXREG(SISCR, 0x97, 0x00);
5564 outSISIDXREG(SISCR, 0x98, 0x01);
5565 outSISIDXREG(SISCR, 0x9a, 0x02);
5567 outSISIDXREG(SISSR, 0x18, 0x01);
5568 if((ivideo->chip == XGI_20) ||
5569 (ivideo->revision_id == 2)) {
5570 outSISIDXREG(SISSR, 0x19, 0x40);
5572 outSISIDXREG(SISSR, 0x19, 0x20);
5574 outSISIDXREG(SISSR, 0x16, 0x00);
5575 outSISIDXREG(SISSR, 0x16, 0x80);
5576 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5577 sisfb_post_xgi_delay(ivideo, 0x43);
5578 sisfb_post_xgi_delay(ivideo, 0x43);
5579 sisfb_post_xgi_delay(ivideo, 0x43);
5580 outSISIDXREG(SISSR, 0x18, 0x00);
5581 if((ivideo->chip == XGI_20) ||
5582 (ivideo->revision_id == 2)) {
5583 outSISIDXREG(SISSR, 0x19, 0x40);
5585 outSISIDXREG(SISSR, 0x19, 0x20);
5587 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5588 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5590 outSISIDXREG(SISSR, 0x16, 0x00);
5591 outSISIDXREG(SISSR, 0x16, 0x80);
5592 sisfb_post_xgi_delay(ivideo, 4);
5593 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5594 if(ivideo->haveXGIROM) {
5596 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5598 v3 = bios[index + 1];
5599 v4 = bios[index + 2];
5600 v5 = bios[index + 3];
5602 outSISIDXREG(SISSR, 0x18, v1);
5603 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5604 outSISIDXREG(SISSR, 0x16, v2);
5605 outSISIDXREG(SISSR, 0x16, v3);
5606 sisfb_post_xgi_delay(ivideo, 0x43);
5607 outSISIDXREG(SISSR, 0x1b, 0x03);
5608 sisfb_post_xgi_delay(ivideo, 0x22);
5609 outSISIDXREG(SISSR, 0x18, v1);
5610 outSISIDXREG(SISSR, 0x19, 0x00);
5611 outSISIDXREG(SISSR, 0x16, v4);
5612 outSISIDXREG(SISSR, 0x16, v5);
5613 outSISIDXREG(SISSR, 0x1b, 0x00);
5616 outSISIDXREG(SISCR, 0x82, 0x77);
5617 outSISIDXREG(SISCR, 0x86, 0x00);
5618 inSISIDXREG(SISCR, 0x86, reg);
5619 outSISIDXREG(SISCR, 0x86, 0x88);
5620 inSISIDXREG(SISCR, 0x86, reg);
5621 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5622 if(ivideo->haveXGIROM) {
5623 v1 = bios[regb + 0x168];
5624 v2 = bios[regb + 0x160];
5625 v3 = bios[regb + 0x158];
5627 outSISIDXREG(SISCR, 0x86, v1);
5628 outSISIDXREG(SISCR, 0x82, 0x77);
5629 outSISIDXREG(SISCR, 0x85, 0x00);
5630 inSISIDXREG(SISCR, 0x85, reg);
5631 outSISIDXREG(SISCR, 0x85, 0x88);
5632 inSISIDXREG(SISCR, 0x85, reg);
5633 outSISIDXREG(SISCR, 0x85, v2);
5634 outSISIDXREG(SISCR, 0x82, v3);
5635 outSISIDXREG(SISCR, 0x98, 0x01);
5636 outSISIDXREG(SISCR, 0x9a, 0x02);
5638 outSISIDXREG(SISSR, 0x28, 0x64);
5639 outSISIDXREG(SISSR, 0x29, 0x63);
5640 sisfb_post_xgi_delay(ivideo, 15);
5641 outSISIDXREG(SISSR, 0x18, 0x00);
5642 outSISIDXREG(SISSR, 0x19, 0x20);
5643 outSISIDXREG(SISSR, 0x16, 0x00);
5644 outSISIDXREG(SISSR, 0x16, 0x80);
5645 outSISIDXREG(SISSR, 0x18, 0xc5);
5646 outSISIDXREG(SISSR, 0x19, 0x23);
5647 outSISIDXREG(SISSR, 0x16, 0x00);
5648 outSISIDXREG(SISSR, 0x16, 0x80);
5649 sisfb_post_xgi_delay(ivideo, 1);
5650 outSISIDXREG(SISCR, 0x97,0x11);
5651 sisfb_post_xgi_setclocks(ivideo, regb);
5652 sisfb_post_xgi_delay(ivideo, 0x46);
5653 outSISIDXREG(SISSR, 0x18, 0xc5);
5654 outSISIDXREG(SISSR, 0x19, 0x23);
5655 outSISIDXREG(SISSR, 0x16, 0x00);
5656 outSISIDXREG(SISSR, 0x16, 0x80);
5657 sisfb_post_xgi_delay(ivideo, 1);
5658 outSISIDXREG(SISSR, 0x1b, 0x04);
5659 sisfb_post_xgi_delay(ivideo, 1);
5660 outSISIDXREG(SISSR, 0x1b, 0x00);
5661 sisfb_post_xgi_delay(ivideo, 1);
5663 if(ivideo->haveXGIROM) {
5666 outSISIDXREG(SISSR, 0x18, v1);
5667 outSISIDXREG(SISSR, 0x19, 0x06);
5668 outSISIDXREG(SISSR, 0x16, 0x04);
5669 outSISIDXREG(SISSR, 0x16, 0x84);
5670 sisfb_post_xgi_delay(ivideo, 1);
5673 sisfb_post_xgi_setclocks(ivideo, regb);
5674 if((ivideo->chip == XGI_40) &&
5675 ((ivideo->revision_id == 1) ||
5676 (ivideo->revision_id == 2))) {
5677 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5678 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5679 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5681 outSISIDXREG(SISCR, 0x82, 0x88);
5682 outSISIDXREG(SISCR, 0x86, 0x00);
5683 inSISIDXREG(SISCR, 0x86, reg);
5684 outSISIDXREG(SISCR, 0x86, 0x88);
5685 outSISIDXREG(SISCR, 0x82, 0x77);
5686 outSISIDXREG(SISCR, 0x85, 0x00);
5687 inSISIDXREG(SISCR, 0x85, reg);
5688 outSISIDXREG(SISCR, 0x85, 0x88);
5689 inSISIDXREG(SISCR, 0x85, reg);
5690 v1 = cs160[regb]; v2 = cs158[regb];
5691 if(ivideo->haveXGIROM) {
5692 v1 = bios[regb + 0x160];
5693 v2 = bios[regb + 0x158];
5695 outSISIDXREG(SISCR, 0x85, v1);
5696 outSISIDXREG(SISCR, 0x82, v2);
5698 if(ivideo->chip == XGI_40) {
5699 outSISIDXREG(SISCR, 0x97, 0x11);
5701 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5702 outSISIDXREG(SISCR, 0x98, 0x01);
5704 outSISIDXREG(SISCR, 0x98, 0x03);
5706 outSISIDXREG(SISCR, 0x9a, 0x02);
5708 if(ivideo->chip == XGI_40) {
5709 outSISIDXREG(SISSR, 0x18, 0x01);
5711 outSISIDXREG(SISSR, 0x18, 0x00);
5713 outSISIDXREG(SISSR, 0x19, 0x40);
5714 outSISIDXREG(SISSR, 0x16, 0x00);
5715 outSISIDXREG(SISSR, 0x16, 0x80);
5716 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5717 sisfb_post_xgi_delay(ivideo, 0x43);
5718 sisfb_post_xgi_delay(ivideo, 0x43);
5719 sisfb_post_xgi_delay(ivideo, 0x43);
5720 outSISIDXREG(SISSR, 0x18, 0x00);
5721 outSISIDXREG(SISSR, 0x19, 0x40);
5722 outSISIDXREG(SISSR, 0x16, 0x00);
5723 outSISIDXREG(SISSR, 0x16, 0x80);
5725 sisfb_post_xgi_delay(ivideo, 4);
5727 if(ivideo->haveXGIROM) {
5730 outSISIDXREG(SISSR, 0x18, v1);
5731 outSISIDXREG(SISSR, 0x19, 0x01);
5732 if(ivideo->chip == XGI_40) {
5733 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5734 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5736 outSISIDXREG(SISSR, 0x16, 0x05);
5737 outSISIDXREG(SISSR, 0x16, 0x85);
5739 sisfb_post_xgi_delay(ivideo, 0x43);
5740 if(ivideo->chip == XGI_40) {
5741 outSISIDXREG(SISSR, 0x1b, 0x01);
5743 outSISIDXREG(SISSR, 0x1b, 0x03);
5745 sisfb_post_xgi_delay(ivideo, 0x22);
5746 outSISIDXREG(SISSR, 0x18, v1);
5747 outSISIDXREG(SISSR, 0x19, 0x00);
5748 if(ivideo->chip == XGI_40) {
5749 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5750 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5752 outSISIDXREG(SISSR, 0x16, 0x05);
5753 outSISIDXREG(SISSR, 0x16, 0x85);
5755 outSISIDXREG(SISSR, 0x1b, 0x00);
5760 if(ivideo->haveXGIROM) {
5761 v1 = bios[0x110 + regb];
5763 outSISIDXREG(SISSR, 0x1b, v1);
5766 v1 = 0x00; v2 = 0x00;
5767 if(ivideo->haveXGIROM) {
5773 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5775 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5776 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5780 /* Set default mode, don't clear screen */
5781 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5782 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5783 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5784 ivideo->curFSTN = ivideo->curDSTN = 0;
5785 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5786 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5788 outSISIDXREG(SISSR, 0x05, 0x86);
5790 /* Disable read-cache */
5791 andSISIDXREG(SISSR, 0x21, 0xdf);
5792 sisfb_post_xgi_ramsize(ivideo);
5793 /* Enable read-cache */
5794 orSISIDXREG(SISSR, 0x21, 0x20);
5799 printk(KERN_DEBUG "-----------------\n");
5800 for(i = 0; i < 0xff; i++) {
5801 inSISIDXREG(SISCR, i, reg);
5802 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5804 for(i = 0; i < 0x40; i++) {
5805 inSISIDXREG(SISSR, i, reg);
5806 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5808 printk(KERN_DEBUG "-----------------\n");
5812 if(ivideo->chip == XGI_20) {
5813 orSISIDXREG(SISCR, 0x32, 0x20);
5815 inSISIDXREG(SISPART4, 0x00, reg);
5816 if((reg == 1) || (reg == 2)) {
5817 sisfb_sense_crt1(ivideo);
5819 orSISIDXREG(SISCR, 0x32, 0x20);
5823 /* Set default mode, don't clear screen */
5824 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5825 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5826 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5827 ivideo->curFSTN = ivideo->curDSTN = 0;
5828 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5830 outSISIDXREG(SISSR, 0x05, 0x86);
5833 orSISIDXREG(SISSR, 0x01, 0x20);
5835 /* Save mode number in CR34 */
5836 outSISIDXREG(SISCR, 0x34, 0x2e);
5838 /* Let everyone know what the current mode is */
5839 ivideo->modeprechange = 0x2e;
5841 if(ivideo->chip == XGI_40) {
5842 inSISIDXREG(SISCR, 0xca, reg);
5843 inSISIDXREG(SISCR, 0xcc, v1);
5844 if((reg & 0x10) && (!(v1 & 0x04))) {
5846 "sisfb: Please connect power to the card.\n");
5855 static int __devinit
5856 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5858 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5859 struct sis_video_info *ivideo = NULL;
5860 struct fb_info *sis_fb_info = NULL;
5868 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5869 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5873 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
5876 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5877 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5880 ivideo = (struct sis_video_info *)sis_fb_info->par;
5881 ivideo->memyselfandi = sis_fb_info;
5883 ivideo->sisfb_id = SISFB_ID;
5885 if(card_list == NULL) {
5886 ivideo->cardnumber = 0;
5888 struct sis_video_info *countvideo = card_list;
5889 ivideo->cardnumber = 1;
5890 while((countvideo = countvideo->next) != 0)
5891 ivideo->cardnumber++;
5894 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5896 ivideo->warncount = 0;
5897 ivideo->chip_id = pdev->device;
5898 ivideo->chip_vendor = pdev->vendor;
5899 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
5900 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5901 pci_read_config_word(pdev, PCI_COMMAND, ®16);
5902 ivideo->sisvga_enabled = reg16 & 0x01;
5903 ivideo->pcibus = pdev->bus->number;
5904 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5905 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5906 ivideo->subsysvendor = pdev->subsystem_vendor;
5907 ivideo->subsysdevice = pdev->subsystem_device;
5908 #ifdef SIS_OLD_CONFIG_COMPAT
5909 ivideo->ioctl32registered = 0;
5913 if(sisfb_mode_idx == -1) {
5914 sisfb_get_vga_mode_from_kernel();
5918 ivideo->chip = chipinfo->chip;
5919 ivideo->sisvga_engine = chipinfo->vgaengine;
5920 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5921 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5922 ivideo->mni = chipinfo->mni;
5924 ivideo->detectedpdc = 0xff;
5925 ivideo->detectedpdca = 0xff;
5926 ivideo->detectedlcda = 0xff;
5928 ivideo->sisfb_thismonitor.datavalid = FALSE;
5930 ivideo->current_base = 0;
5932 ivideo->engineok = 0;
5934 ivideo->sisfb_was_boot_device = 0;
5935 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5936 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5937 if(ivideo->sisvga_enabled)
5938 ivideo->sisfb_was_boot_device = 1;
5940 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5941 "but marked as boot video device ???\n");
5942 printk(KERN_DEBUG "sisfb: I will not accept this "
5943 "as the primary VGA device\n");
5948 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5949 ivideo->sisfb_accel = sisfb_accel;
5950 ivideo->sisfb_ypan = sisfb_ypan;
5951 ivideo->sisfb_max = sisfb_max;
5952 ivideo->sisfb_userom = sisfb_userom;
5953 ivideo->sisfb_useoem = sisfb_useoem;
5954 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5955 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5956 ivideo->sisfb_crt1off = sisfb_crt1off;
5957 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5958 ivideo->sisfb_crt2type = sisfb_crt2type;
5959 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5960 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5961 ivideo->sisfb_dstn = sisfb_dstn;
5962 ivideo->sisfb_fstn = sisfb_fstn;
5963 ivideo->sisfb_tvplug = sisfb_tvplug;
5964 ivideo->sisfb_tvstd = sisfb_tvstd;
5965 ivideo->tvxpos = sisfb_tvxposoffset;
5966 ivideo->tvypos = sisfb_tvyposoffset;
5967 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5968 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5969 ivideo->sisfb_inverse = sisfb_inverse;
5972 ivideo->refresh_rate = 0;
5973 if(ivideo->sisfb_parm_rate != -1) {
5974 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5977 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5978 ivideo->SiS_Pr.CenterScreen = -1;
5979 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5980 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5982 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5983 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5984 ivideo->SiS_Pr.SiS_ChSW = FALSE;
5985 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5986 ivideo->SiS_Pr.HaveEMI = FALSE;
5987 ivideo->SiS_Pr.HaveEMILCD = FALSE;
5988 ivideo->SiS_Pr.OverruleEMI = FALSE;
5989 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
5990 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5991 ivideo->SiS_Pr.PDC = -1;
5992 ivideo->SiS_Pr.PDCA = -1;
5993 ivideo->SiS_Pr.DDCPortMixup = FALSE;
5994 #ifdef CONFIG_FB_SIS_315
5995 if(ivideo->chip >= SIS_330) {
5996 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5997 if(ivideo->chip >= SIS_661) {
5998 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
6003 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6005 pci_set_drvdata(pdev, ivideo);
6007 /* Patch special cases */
6008 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6009 switch(ivideo->nbridge->device) {
6010 #ifdef CONFIG_FB_SIS_300
6011 case PCI_DEVICE_ID_SI_730:
6012 ivideo->chip = SIS_730;
6013 strcpy(ivideo->myid, "SiS 730");
6016 #ifdef CONFIG_FB_SIS_315
6017 case PCI_DEVICE_ID_SI_651:
6018 /* ivideo->chip is ok */
6019 strcpy(ivideo->myid, "SiS 651");
6021 case PCI_DEVICE_ID_SI_740:
6022 ivideo->chip = SIS_740;
6023 strcpy(ivideo->myid, "SiS 740");
6025 case PCI_DEVICE_ID_SI_661:
6026 ivideo->chip = SIS_661;
6027 strcpy(ivideo->myid, "SiS 661");
6029 case PCI_DEVICE_ID_SI_741:
6030 ivideo->chip = SIS_741;
6031 strcpy(ivideo->myid, "SiS 741");
6033 case PCI_DEVICE_ID_SI_760:
6034 ivideo->chip = SIS_760;
6035 strcpy(ivideo->myid, "SiS 760");
6037 case PCI_DEVICE_ID_SI_761:
6038 ivideo->chip = SIS_761;
6039 strcpy(ivideo->myid, "SiS 761");
6047 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6048 strcpy(sis_fb_info->modename, ivideo->myid);
6051 ivideo->SiS_Pr.ChipType = ivideo->chip;
6053 ivideo->SiS_Pr.ivideo = (void *)ivideo;
6055 #ifdef CONFIG_FB_SIS_315
6056 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6057 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6058 ivideo->SiS_Pr.ChipType = SIS_315H;
6062 if(!ivideo->sisvga_enabled) {
6063 if(pci_enable_device(pdev)) {
6064 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6065 pci_set_drvdata(pdev, NULL);
6071 ivideo->video_base = pci_resource_start(pdev, 0);
6072 ivideo->mmio_base = pci_resource_start(pdev, 1);
6073 ivideo->mmio_size = pci_resource_len(pdev, 1);
6074 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
6075 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
6077 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
6079 #ifdef CONFIG_FB_SIS_300
6080 /* Find PCI systems for Chrontel/GPIO communication setup */
6081 if(ivideo->chip == SIS_630) {
6084 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6085 mychswtable[i].subsysCard == ivideo->subsysdevice) {
6086 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6087 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6088 "requiring Chrontel/GPIO setup\n",
6089 mychswtable[i].vendorName,
6090 mychswtable[i].cardName);
6091 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6095 } while(mychswtable[i].subsysVendor != 0);
6099 #ifdef CONFIG_FB_SIS_315
6100 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6101 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
6105 outSISIDXREG(SISSR, 0x05, 0x86);
6107 if( (!ivideo->sisvga_enabled)
6108 #if !defined(__i386__) && !defined(__x86_64__)
6109 || (sisfb_resetcard)
6112 for(i = 0x30; i <= 0x3f; i++) {
6113 outSISIDXREG(SISCR, i, 0x00);
6117 /* Find out about current video mode */
6118 ivideo->modeprechange = 0x03;
6119 inSISIDXREG(SISCR, 0x34, reg);
6121 ivideo->modeprechange = reg & 0x7f;
6122 } else if(ivideo->sisvga_enabled) {
6123 #if defined(__i386__) || defined(__x86_64__)
6124 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
6126 ivideo->modeprechange = readb(tt + 0x49);
6132 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6134 if((reg & 0x80) && (reg != 0xff)) {
6135 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6137 printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6138 "X server is active\n");
6146 /* Search and copy ROM image */
6147 ivideo->bios_abase = NULL;
6148 ivideo->SiS_Pr.VirtualRomBase = NULL;
6149 ivideo->SiS_Pr.UseROM = FALSE;
6150 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
6151 if(ivideo->sisfb_userom) {
6152 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6153 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6154 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6155 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6156 ivideo->SiS_Pr.UseROM ? "" : "not ");
6157 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6158 ivideo->SiS_Pr.UseROM = FALSE;
6159 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6160 if( (ivideo->revision_id == 2) &&
6161 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6162 ivideo->SiS_Pr.DDCPortMixup = TRUE;
6166 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6169 /* Find systems for special custom timing */
6170 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6171 sisfb_detect_custom_timing(ivideo);
6174 /* POST card in case this has not been done by the BIOS */
6175 if( (!ivideo->sisvga_enabled)
6176 #if !defined(__i386__) && !defined(__x86_64__)
6177 || (sisfb_resetcard)
6180 #ifdef CONFIG_FB_SIS_300
6181 if(ivideo->sisvga_engine == SIS_300_VGA) {
6182 if(ivideo->chip == SIS_300) {
6183 sisfb_post_sis300(pdev);
6184 ivideo->sisfb_can_post = 1;
6189 #ifdef CONFIG_FB_SIS_315
6190 if(ivideo->sisvga_engine == SIS_315_VGA) {
6192 /* if((ivideo->chip == SIS_315H) ||
6193 (ivideo->chip == SIS_315) ||
6194 (ivideo->chip == SIS_315PRO) ||
6195 (ivideo->chip == SIS_330)) {
6196 sisfb_post_sis315330(pdev);
6197 } else */ if(ivideo->chip == XGI_20) {
6198 result = sisfb_post_xgi(pdev);
6199 ivideo->sisfb_can_post = 1;
6200 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6201 result = sisfb_post_xgi(pdev);
6202 ivideo->sisfb_can_post = 1;
6204 printk(KERN_INFO "sisfb: Card is not "
6205 "POSTed and sisfb can't do this either.\n");
6208 printk(KERN_ERR "sisfb: Failed to POST card\n");
6216 ivideo->sisfb_card_posted = 1;
6218 /* Find out about RAM size */
6219 if(sisfb_get_dram_size(ivideo)) {
6220 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6226 /* Enable PCI addressing and MMIO */
6227 if((ivideo->sisfb_mode_idx < 0) ||
6228 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6229 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6230 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6231 /* Enable 2D accelerator engine */
6232 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6235 if(sisfb_pdc != 0xff) {
6236 if(ivideo->sisvga_engine == SIS_300_VGA)
6240 ivideo->SiS_Pr.PDC = sisfb_pdc;
6242 #ifdef CONFIG_FB_SIS_315
6243 if(ivideo->sisvga_engine == SIS_315_VGA) {
6244 if(sisfb_pdca != 0xff)
6245 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6249 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6250 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6251 (int)(ivideo->video_size >> 20));
6252 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6257 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6258 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6263 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6264 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6265 if(!ivideo->video_vbase) {
6266 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6271 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6272 if(!ivideo->mmio_vbase) {
6273 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6275 error_0: iounmap(ivideo->video_vbase);
6276 error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6277 error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6278 error_3: vfree(ivideo->bios_abase);
6279 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6283 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6285 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6286 pci_set_drvdata(pdev, NULL);
6287 if(!ivideo->sisvga_enabled)
6288 pci_disable_device(pdev);
6293 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6294 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6296 if(ivideo->video_offset) {
6297 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6298 ivideo->video_offset / 1024);
6301 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6302 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6305 /* Determine the size of the command queue */
6306 if(ivideo->sisvga_engine == SIS_300_VGA) {
6307 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6309 if(ivideo->chip == XGI_20) {
6310 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6312 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6316 /* Engines are no longer initialized here; this is
6317 * now done after the first mode-switch (if the
6318 * submitted var has its acceleration flags set).
6321 /* Calculate the base of the (unused) hw cursor */
6322 ivideo->hwcursor_vbase = ivideo->video_vbase
6323 + ivideo->video_size
6324 - ivideo->cmdQueueSize
6325 - ivideo->hwcursor_size;
6326 ivideo->caps |= HW_CURSOR_CAP;
6328 /* Initialize offscreen memory manager */
6329 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6330 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6333 /* Used for clearing the screen only, therefore respect our mem limit */
6334 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6335 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6339 ivideo->vbflags = 0;
6340 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6341 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6342 ivideo->defmodeidx = DEFAULT_MODE;
6345 if(ivideo->chip < XGI_20) {
6346 if(ivideo->bios_abase) {
6347 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6351 if((ivideo->sisfb_mode_idx < 0) ||
6352 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6354 sisfb_sense_crt1(ivideo);
6356 sisfb_get_VB_type(ivideo);
6358 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6359 sisfb_detect_VB_connect(ivideo);
6362 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6364 /* Decide on which CRT2 device to use */
6365 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6366 if(ivideo->sisfb_crt2type != -1) {
6367 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6368 (ivideo->vbflags & CRT2_LCD)) {
6369 ivideo->currentvbflags |= CRT2_LCD;
6370 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6371 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6374 /* Chrontel 700x TV detection often unreliable, therefore
6375 * use a different default order on such machines
6377 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6378 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6379 if(ivideo->vbflags & CRT2_LCD)
6380 ivideo->currentvbflags |= CRT2_LCD;
6381 else if(ivideo->vbflags & CRT2_TV)
6382 ivideo->currentvbflags |= CRT2_TV;
6383 else if(ivideo->vbflags & CRT2_VGA)
6384 ivideo->currentvbflags |= CRT2_VGA;
6386 if(ivideo->vbflags & CRT2_TV)
6387 ivideo->currentvbflags |= CRT2_TV;
6388 else if(ivideo->vbflags & CRT2_LCD)
6389 ivideo->currentvbflags |= CRT2_LCD;
6390 else if(ivideo->vbflags & CRT2_VGA)
6391 ivideo->currentvbflags |= CRT2_VGA;
6396 if(ivideo->vbflags & CRT2_LCD) {
6397 sisfb_detect_lcd_type(ivideo);
6400 sisfb_save_pdc_emi(ivideo);
6402 if(!ivideo->sisfb_crt1off) {
6403 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6405 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6406 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6407 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6411 if(ivideo->sisfb_mode_idx >= 0) {
6412 int bu = ivideo->sisfb_mode_idx;
6413 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6414 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6415 if(bu != ivideo->sisfb_mode_idx) {
6416 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6417 sisbios_mode[bu].xres,
6418 sisbios_mode[bu].yres,
6419 sisbios_mode[bu].bpp);
6423 if(ivideo->sisfb_mode_idx < 0) {
6424 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6426 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6429 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6432 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6437 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6439 if(ivideo->refresh_rate != 0) {
6440 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6441 ivideo->sisfb_mode_idx);
6444 if(ivideo->rate_idx == 0) {
6445 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6446 ivideo->refresh_rate = 60;
6449 if(ivideo->sisfb_thismonitor.datavalid) {
6450 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6451 ivideo->sisfb_mode_idx,
6453 ivideo->refresh_rate)) {
6454 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6455 "exceeds monitor specs!\n");
6459 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6460 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6461 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6463 sisfb_set_vparms(ivideo);
6465 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6467 /* ---------------- For 2.4: Now switch the mode ------------------ */
6469 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6470 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6471 ivideo->refresh_rate);
6473 /* Determine whether or not acceleration is to be
6474 * used. Need to know before pre/post_set_mode()
6477 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6478 if(ivideo->sisfb_accel) {
6480 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6483 /* Now switch the mode */
6484 sisfb_pre_setmode(ivideo);
6486 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
6487 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6490 iounmap(ivideo->mmio_vbase);
6494 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6496 sisfb_post_setmode(ivideo);
6498 /* Maximize regardless of sisfb_max at startup */
6499 ivideo->default_var.yres_virtual = 32767;
6501 /* Force reset of x virtual in crtc_to_var */
6502 ivideo->default_var.xres_virtual = 0;
6504 /* Copy mode timing to var */
6505 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6507 /* Find out about screen pitch */
6508 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6509 sisfb_set_pitch(ivideo);
6511 /* Init the accelerator (does nothing currently) */
6512 sisfb_initaccel(ivideo);
6514 /* Init some fbinfo entries */
6515 sis_fb_info->node = -1;
6516 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6517 sis_fb_info->fbops = &sisfb_ops;
6518 sis_fb_info->disp = &ivideo->sis_disp;
6519 sis_fb_info->blank = &sisfb_blank;
6520 sis_fb_info->switch_con = &sisfb_switch;
6521 sis_fb_info->updatevar = &sisfb_update_var;
6522 sis_fb_info->changevar = NULL;
6523 strcpy(sis_fb_info->fontname, sisfb_fontname);
6525 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6527 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6529 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6530 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6531 ivideo->refresh_rate);
6533 /* Set up the default var according to chosen default display mode */
6534 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6535 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6536 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6538 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6540 ivideo->default_var.pixclock = (u32) (1000000000 /
6541 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6543 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6544 ivideo->rate_idx, &ivideo->default_var)) {
6545 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6546 ivideo->default_var.pixclock <<= 1;
6550 if(ivideo->sisfb_ypan) {
6551 /* Maximize regardless of sisfb_max at startup */
6552 ivideo->default_var.yres_virtual =
6553 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6554 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6555 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6559 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6562 if(ivideo->sisfb_accel) {
6564 #ifdef STUPID_ACCELF_TEXT_SHIT
6565 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6568 sisfb_initaccel(ivideo);
6570 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6571 sis_fb_info->flags = FBINFO_DEFAULT |
6572 FBINFO_HWACCEL_YPAN |
6573 FBINFO_HWACCEL_XPAN |
6574 FBINFO_HWACCEL_COPYAREA |
6575 FBINFO_HWACCEL_FILLRECT |
6576 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6578 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6580 sis_fb_info->var = ivideo->default_var;
6581 sis_fb_info->fix = ivideo->sisfb_fix;
6582 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6583 sis_fb_info->fbops = &sisfb_ops;
6585 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6586 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6588 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6591 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6594 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6595 MTRR_TYPE_WRCOMB, 1);
6596 if(ivideo->mtrr < 0) {
6597 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6601 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6602 vc_resize_con(1, 1, 0);
6605 if(register_framebuffer(sis_fb_info) < 0) {
6606 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6608 iounmap(ivideo->mmio_vbase);
6612 ivideo->registered = 1;
6615 ivideo->next = card_list;
6618 #ifdef SIS_OLD_CONFIG_COMPAT
6621 /* Our ioctls are all "32/64bit compatible" */
6622 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6623 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6624 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6625 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6626 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6627 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6628 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6629 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6630 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6631 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6632 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6633 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6636 "sisfb: Error registering ioctl32 translations\n");
6638 ivideo->ioctl32registered = 1;
6642 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6643 ivideo->sisfb_accel ? "enabled" : "disabled",
6644 ivideo->sisfb_ypan ?
6645 (ivideo->sisfb_max ? "enabled (auto-max)" :
6646 "enabled (no auto-max)") :
6650 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6651 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6652 GET_FB_IDX(sis_fb_info->node),
6656 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6658 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6660 } /* if mode = "none" */
6665 /*****************************************************/
6666 /* PCI DEVICE HANDLING */
6667 /*****************************************************/
6669 static void __devexit sisfb_remove(struct pci_dev *pdev)
6671 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6672 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6673 int registered = ivideo->registered;
6674 int modechanged = ivideo->modechanged;
6676 #ifdef SIS_OLD_CONFIG_COMPAT
6677 if(ivideo->ioctl32registered) {
6679 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6680 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6681 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6682 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6683 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6684 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6685 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6686 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6687 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6688 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6689 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6690 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6693 "sisfb: Error unregistering ioctl32 translations\n");
6698 iounmap(ivideo->mmio_vbase);
6699 iounmap(ivideo->video_vbase);
6701 /* Release mem regions */
6702 release_mem_region(ivideo->video_base, ivideo->video_size);
6703 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6705 vfree(ivideo->bios_abase);
6708 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6711 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6714 /* Release MTRR region */
6715 if(ivideo->mtrr >= 0)
6716 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6719 pci_set_drvdata(pdev, NULL);
6721 /* If device was disabled when starting, disable
6724 if(!ivideo->sisvga_enabled)
6725 pci_disable_device(pdev);
6727 /* Unregister the framebuffer */
6728 if(ivideo->registered) {
6729 unregister_framebuffer(sis_fb_info);
6730 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6731 framebuffer_release(sis_fb_info);
6737 /* OK, our ivideo is gone for good from here. */
6739 /* TODO: Restore the initial mode
6740 * This sounds easy but is as good as impossible
6741 * on many machines with SiS chip and video bridge
6742 * since text modes are always set up differently
6743 * from machine to machine. Depends on the type
6744 * of integration between chipset and bridge.
6746 if(registered && modechanged)
6748 "sisfb: Restoring of text mode not supported yet\n");
6751 static struct pci_driver sisfb_driver = {
6753 .id_table = sisfb_pci_table,
6754 .probe = sisfb_probe,
6755 .remove = __devexit_p(sisfb_remove)
6758 SISINITSTATIC int __init sisfb_init(void)
6760 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6762 char *options = NULL;
6764 if(fb_get_options("sisfb", &options))
6767 sisfb_setup(options);
6770 return pci_register_driver(&sisfb_driver);
6773 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6775 module_init(sisfb_init);
6779 /*****************************************************/
6781 /*****************************************************/
6785 static char *mode = NULL;
6786 static int vesa = -1;
6787 static unsigned int rate = 0;
6788 static unsigned int crt1off = 1;
6789 static unsigned int mem = 0;
6790 static char *forcecrt2type = NULL;
6791 static int forcecrt1 = -1;
6792 static int pdc = -1;
6793 static int pdc1 = -1;
6794 static int noaccel = -1;
6795 static int noypan = -1;
6796 static int nomax = -1;
6797 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6798 static int inverse = 0;
6800 static int userom = -1;
6801 static int useoem = -1;
6802 static char *tvstandard = NULL;
6803 static int nocrt2rate = 0;
6804 static int scalelcd = -1;
6805 static char *specialtiming = NULL;
6806 static int lvdshl = -1;
6807 static int tvxposoffset = 0, tvyposoffset = 0;
6808 #if !defined(__i386__) && !defined(__x86_64__)
6809 static int resetcard = 0;
6810 static int videoram = 0;
6813 static int __init sisfb_init_module(void)
6815 sisfb_setdefaultparms();
6818 sisfb_parm_rate = rate;
6820 if((scalelcd == 0) || (scalelcd == 1))
6821 sisfb_scalelcd = scalelcd ^ 1;
6823 /* Need to check crt2 type first for fstn/dstn */
6826 sisfb_search_crt2type(forcecrt2type);
6829 sisfb_search_tvstd(tvstandard);
6832 sisfb_search_mode(mode, FALSE);
6834 sisfb_search_vesamode(vesa, FALSE);
6836 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6838 sisfb_forcecrt1 = forcecrt1;
6841 else if(forcecrt1 == 0)
6846 else if(noaccel == 0)
6851 else if(noypan == 0)
6859 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6860 if(inverse) sisfb_inverse = 1;
6864 sisfb_parm_mem = mem;
6867 sisfb_userom = userom;
6870 sisfb_useoem = useoem;
6873 sisfb_pdc = (pdc & 0x7f);
6876 sisfb_pdca = (pdc1 & 0x1f);
6878 sisfb_nocrt2rate = nocrt2rate;
6881 sisfb_search_specialtiming(specialtiming);
6883 if((lvdshl >= 0) && (lvdshl <= 3))
6884 sisfb_lvdshl = lvdshl;
6886 sisfb_tvxposoffset = tvxposoffset;
6887 sisfb_tvyposoffset = tvyposoffset;
6889 #if !defined(__i386__) && !defined(__x86_64__)
6890 sisfb_resetcard = (resetcard) ? 1 : 0;
6892 sisfb_videoram = videoram;
6895 return sisfb_init();
6898 static void __exit sisfb_remove_module(void)
6900 pci_unregister_driver(&sisfb_driver);
6901 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6904 module_init(sisfb_init_module);
6905 module_exit(sisfb_remove_module);
6907 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6908 MODULE_LICENSE("GPL");
6909 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6911 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6912 MODULE_PARM(mem, "i");
6913 MODULE_PARM(noaccel, "i");
6914 MODULE_PARM(noypan, "i");
6915 MODULE_PARM(nomax, "i");
6916 MODULE_PARM(userom, "i");
6917 MODULE_PARM(useoem, "i");
6918 MODULE_PARM(mode, "s");
6919 MODULE_PARM(vesa, "i");
6920 MODULE_PARM(rate, "i");
6921 MODULE_PARM(forcecrt1, "i");
6922 MODULE_PARM(forcecrt2type, "s");
6923 MODULE_PARM(scalelcd, "i");
6924 MODULE_PARM(pdc, "i");
6925 MODULE_PARM(pdc1, "i");
6926 MODULE_PARM(specialtiming, "s");
6927 MODULE_PARM(lvdshl, "i");
6928 MODULE_PARM(tvstandard, "s");
6929 MODULE_PARM(tvxposoffset, "i");
6930 MODULE_PARM(tvyposoffset, "i");
6931 MODULE_PARM(nocrt2rate, "i");
6932 MODULE_PARM(inverse, "i");
6933 #if !defined(__i386__) && !defined(__x86_64__)
6934 MODULE_PARM(resetcard, "i");
6935 MODULE_PARM(videoram, "i");
6939 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6940 module_param(mem, int, 0);
6941 module_param(noaccel, int, 0);
6942 module_param(noypan, int, 0);
6943 module_param(nomax, int, 0);
6944 module_param(userom, int, 0);
6945 module_param(useoem, int, 0);
6946 module_param(mode, charp, 0);
6947 module_param(vesa, int, 0);
6948 module_param(rate, int, 0);
6949 module_param(forcecrt1, int, 0);
6950 module_param(forcecrt2type, charp, 0);
6951 module_param(scalelcd, int, 0);
6952 module_param(pdc, int, 0);
6953 module_param(pdc1, int, 0);
6954 module_param(specialtiming, charp, 0);
6955 module_param(lvdshl, int, 0);
6956 module_param(tvstandard, charp, 0);
6957 module_param(tvxposoffset, int, 0);
6958 module_param(tvyposoffset, int, 0);
6959 module_param(nocrt2rate, int, 0);
6960 #if !defined(__i386__) && !defined(__x86_64__)
6961 module_param(resetcard, int, 0);
6962 module_param(videoram, int, 0);
6966 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6967 MODULE_PARM_DESC(mem,
6968 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6969 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6970 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6971 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6972 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6973 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6974 "for XFree86 4.x/X.org 6.7 and later.\n");
6976 MODULE_PARM_DESC(mem,
6977 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6978 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6979 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6980 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6981 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6982 "The value is to be specified without 'KB'.\n");
6985 MODULE_PARM_DESC(noaccel,
6986 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6989 MODULE_PARM_DESC(noypan,
6990 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6991 "will be performed by redrawing the screen. (default: 0)\n");
6993 MODULE_PARM_DESC(nomax,
6994 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
6995 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6996 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6997 "enable the user to positively specify a virtual Y size of the screen using\n"
6998 "fbset. (default: 0)\n");
7000 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7001 MODULE_PARM_DESC(mode,
7002 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7003 "1024x768x16. Other formats supported include XxY-Depth and\n"
7004 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7005 "number, it will be interpreted as a VESA mode number. (default: none if\n"
7006 "sisfb is a module; this leaves the console untouched and the driver will\n"
7007 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7008 "is in the kernel)\n");
7009 MODULE_PARM_DESC(vesa,
7010 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7011 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
7012 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7013 "0x0103 if sisfb is in the kernel)\n");
7016 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7017 MODULE_PARM_DESC(mode,
7018 "\nSelects the desired default display mode in the format XxYxDepth,\n"
7019 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
7020 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7021 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7023 MODULE_PARM_DESC(vesa,
7024 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7025 "0x117 (default: 0x0103)\n");
7028 MODULE_PARM_DESC(rate,
7029 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7030 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7031 "will be ignored (default: 60)\n");
7033 MODULE_PARM_DESC(forcecrt1,
7034 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7035 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7036 "0=CRT1 OFF) (default: [autodetected])\n");
7038 MODULE_PARM_DESC(forcecrt2type,
7039 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7040 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7041 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7042 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7043 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7044 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7045 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7046 "depends on the very hardware in use. (default: [autodetected])\n");
7048 MODULE_PARM_DESC(scalelcd,
7049 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7050 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7051 "show black bars around the image, TMDS panels will probably do the scaling\n"
7052 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7054 MODULE_PARM_DESC(pdc,
7055 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
7056 "should detect this correctly in most cases; however, sometimes this is not\n"
7057 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
7058 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7059 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7060 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
7062 #ifdef CONFIG_FB_SIS_315
7063 MODULE_PARM_DESC(pdc1,
7064 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
7065 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7066 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7067 "implemented yet.\n");
7070 MODULE_PARM_DESC(specialtiming,
7071 "\nPlease refer to documentation for more information on this option.\n");
7073 MODULE_PARM_DESC(lvdshl,
7074 "\nPlease refer to documentation for more information on this option.\n");
7076 MODULE_PARM_DESC(tvstandard,
7077 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7078 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7080 MODULE_PARM_DESC(tvxposoffset,
7081 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7084 MODULE_PARM_DESC(tvyposoffset,
7085 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7088 MODULE_PARM_DESC(nocrt2rate,
7089 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7090 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7092 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7093 MODULE_PARM_DESC(inverse,
7094 "\nSetting this to anything but 0 should invert the display colors, but this\n"
7095 "does not seem to work. (default: 0)\n");
7098 #if !defined(__i386__) && !defined(__x86_64__)
7099 #ifdef CONFIG_FB_SIS_300
7100 MODULE_PARM_DESC(resetcard,
7101 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
7102 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7103 "currently). Default: 0\n");
7105 MODULE_PARM_DESC(videoram,
7106 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7107 "some non-x86 architectures where the memory auto detection fails. Only\n"
7108 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
7112 #endif /* /MODULE */
7114 /* _GPL only for new symbols. */
7115 EXPORT_SYMBOL(sis_malloc);
7116 EXPORT_SYMBOL(sis_free);
7117 EXPORT_SYMBOL_GPL(sis_malloc_new);
7118 EXPORT_SYMBOL_GPL(sis_free_new);