2 * SiS 300/540/630[S]/730[S],
3 * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
5 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
7 * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the named License,
12 * or any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
23 * Author: Thomas Winischhofer <thomas@winischhofer.net>
25 * Author of (practically wiped) code base:
27 * Copyright (C) 1999 Silicon Integrated Systems, Inc.
29 * See http://www.winischhofer.net/ for more information and updates
31 * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
32 * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
36 #include <linux/config.h>
37 #include <linux/version.h>
38 #include <linux/module.h>
39 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
40 #include <linux/moduleparam.h>
42 #include <linux/kernel.h>
43 #include <linux/smp_lock.h>
44 #include <linux/spinlock.h>
45 #include <linux/errno.h>
46 #include <linux/string.h>
48 #include <linux/tty.h>
49 #include <linux/slab.h>
51 #include <linux/selection.h>
52 #include <linux/ioport.h>
53 #include <linux/init.h>
54 #include <linux/pci.h>
55 #include <linux/vmalloc.h>
56 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
57 #include <linux/vt_kern.h>
59 #include <linux/capability.h>
61 #include <linux/types.h>
62 #include <asm/uaccess.h>
68 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
69 #include <video/fbcon.h>
70 #include <video/fbcon-cfb8.h>
71 #include <video/fbcon-cfb16.h>
72 #include <video/fbcon-cfb24.h>
73 #include <video/fbcon-cfb32.h>
79 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
80 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
81 #error "This version of sisfb requires at least 2.6.3"
85 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
87 extern struct display_switch fbcon_sis8;
89 #ifdef FBCON_HAS_CFB16
90 extern struct display_switch fbcon_sis16;
92 #ifdef FBCON_HAS_CFB32
93 extern struct display_switch fbcon_sis32;
97 static void sisfb_handle_command(struct sis_video_info *ivideo,
98 struct sisfb_cmd *sisfb_command);
100 /* ------------------ Internal helper routines ----------------- */
103 sisfb_setdefaultparms(void)
113 /* Module: "None" for 2.4, default mode for 2.5+ */
114 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
117 sisfb_mode_idx = MODE_INDEX_NONE;
120 /* Static: Default mode */
123 sisfb_parm_rate = -1;
125 sisfb_forcecrt1 = -1;
131 sisfb_specialtiming = CUT_NONE;
137 sisfb_tvxposoffset = 0;
138 sisfb_tvyposoffset = 0;
139 sisfb_nocrt2rate = 0;
140 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
142 sisfb_fontname[0] = 0;
144 #if !defined(__i386__) && !defined(__x86_64__)
150 /* ------------- Parameter parsing -------------- */
152 static void __devinit
153 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
157 /* We don't know the hardware specs yet and there is no ivideo */
160 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
161 sisfb_mode_idx = MODE_INDEX_NONE;
164 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
166 sisfb_mode_idx = DEFAULT_MODE;
171 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
173 while(sisbios_mode[i++].mode_no[0] != 0) {
174 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
175 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
177 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
178 sisbios_mode[i-1].mode_no[1] == 0x56 ||
179 sisbios_mode[i-1].mode_no[1] == 0x53)
182 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
183 sisbios_mode[i-1].mode_no[1] == 0x5b)
186 sisfb_mode_idx = i - 1;
192 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
195 static void __devinit
196 sisfb_search_mode(char *name, BOOLEAN quiet)
198 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
200 char strbuf[16], strbuf1[20];
201 char *nameptr = name;
203 /* We don't know the hardware specs yet and there is no ivideo */
207 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
209 sisfb_mode_idx = DEFAULT_MODE;
213 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
214 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
216 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
218 sisfb_mode_idx = DEFAULT_MODE;
222 if(strlen(name) <= 19) {
223 strcpy(strbuf1, name);
224 for(i = 0; i < strlen(strbuf1); i++) {
225 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
228 /* This does some fuzzy mode naming detection */
229 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
230 if((rate <= 32) || (depth > 32)) {
231 j = rate; rate = depth; depth = j;
233 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
235 sisfb_parm_rate = rate;
236 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
237 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
241 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
242 sprintf(strbuf, "%ux%ux8", xres, yres);
245 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
252 while(sisbios_mode[i].mode_no[0] != 0) {
253 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
255 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
256 sisbios_mode[i-1].mode_no[1] == 0x56 ||
257 sisbios_mode[i-1].mode_no[1] == 0x53)
260 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
261 sisbios_mode[i-1].mode_no[1] == 0x5b)
264 sisfb_mode_idx = i - 1;
271 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
275 static void __devinit
276 sisfb_get_vga_mode_from_kernel(void)
278 #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
280 int mydepth = screen_info.lfb_depth;
282 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
284 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
285 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
286 (mydepth >= 8) && (mydepth <= 32) ) {
288 if(mydepth == 24) mydepth = 32;
290 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
291 screen_info.lfb_height,
295 "sisfb: Using vga mode %s pre-set by kernel as default\n",
298 sisfb_search_mode(mymode, TRUE);
306 sisfb_search_crt2type(const char *name)
310 /* We don't know the hardware specs yet and there is no ivideo */
312 if(name == NULL) return;
314 while(sis_crt2type[i].type_no != -1) {
315 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
316 sisfb_crt2type = sis_crt2type[i].type_no;
317 sisfb_tvplug = sis_crt2type[i].tvplug_no;
318 sisfb_crt2flags = sis_crt2type[i].flags;
324 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
325 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
327 if(sisfb_crt2type < 0)
328 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
332 sisfb_search_tvstd(const char *name)
336 /* We don't know the hardware specs yet and there is no ivideo */
341 while(sis_tvtype[i].type_no != -1) {
342 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
343 sisfb_tvstd = sis_tvtype[i].type_no;
351 sisfb_search_specialtiming(const char *name)
354 BOOLEAN found = FALSE;
356 /* We don't know the hardware specs yet and there is no ivideo */
361 if(!strnicmp(name, "none", 4)) {
362 sisfb_specialtiming = CUT_FORCENONE;
363 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
365 while(mycustomttable[i].chipID != 0) {
366 if(!strnicmp(name,mycustomttable[i].optionName,
367 strlen(mycustomttable[i].optionName))) {
368 sisfb_specialtiming = mycustomttable[i].SpecialID;
370 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
371 mycustomttable[i].vendorName,
372 mycustomttable[i].cardName,
373 mycustomttable[i].optionName);
379 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
380 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
382 while(mycustomttable[i].chipID != 0) {
383 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
384 mycustomttable[i].optionName,
385 mycustomttable[i].vendorName,
386 mycustomttable[i].cardName);
393 /* ----------- Various detection routines ----------- */
395 static void __devinit
396 sisfb_detect_custom_timing(struct sis_video_info *ivideo)
398 unsigned char *biosver = NULL;
399 unsigned char *biosdate = NULL;
404 if(ivideo->SiS_Pr.UseROM) {
405 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
406 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
407 for(i = 0; i < 32768; i++)
408 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
413 if( (mycustomttable[i].chipID == ivideo->chip) &&
414 ((!strlen(mycustomttable[i].biosversion)) ||
415 (ivideo->SiS_Pr.UseROM &&
416 (!strncmp(mycustomttable[i].biosversion, biosver,
417 strlen(mycustomttable[i].biosversion))))) &&
418 ((!strlen(mycustomttable[i].biosdate)) ||
419 (ivideo->SiS_Pr.UseROM &&
420 (!strncmp(mycustomttable[i].biosdate, biosdate,
421 strlen(mycustomttable[i].biosdate))))) &&
422 ((!mycustomttable[i].bioschksum) ||
423 (ivideo->SiS_Pr.UseROM &&
424 (mycustomttable[i].bioschksum == chksum))) &&
425 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
426 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
428 for(j = 0; j < 5; j++) {
429 if(mycustomttable[i].biosFootprintAddr[j]) {
430 if(ivideo->SiS_Pr.UseROM) {
431 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
432 mycustomttable[i].biosFootprintData[j]) {
440 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
441 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
442 mycustomttable[i].vendorName,
443 mycustomttable[i].cardName);
444 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
445 mycustomttable[i].optionName);
450 } while(mycustomttable[i].chipID);
453 static BOOLEAN __devinit
454 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
456 int i, j, xres, yres, refresh, index;
459 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
460 buffer[2] != 0xff || buffer[3] != 0xff ||
461 buffer[4] != 0xff || buffer[5] != 0xff ||
462 buffer[6] != 0xff || buffer[7] != 0x00) {
463 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
467 if(buffer[0x12] != 0x01) {
468 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
473 monitor->feature = buffer[0x18];
475 if(!buffer[0x14] & 0x80) {
476 if(!(buffer[0x14] & 0x08)) {
478 "sisfb: WARNING: Monitor does not support separate syncs\n");
482 if(buffer[0x13] >= 0x01) {
483 /* EDID V1 rev 1 and 2: Search for monitor descriptor
488 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
489 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
490 buffer[j + 4] == 0x00) {
491 monitor->hmin = buffer[j + 7];
492 monitor->hmax = buffer[j + 8];
493 monitor->vmin = buffer[j + 5];
494 monitor->vmax = buffer[j + 6];
495 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
496 monitor->datavalid = TRUE;
503 if(!monitor->datavalid) {
504 /* Otherwise: Get a range from the list of supported
505 * Estabished Timings. This is not entirely accurate,
506 * because fixed frequency monitors are not supported
509 monitor->hmin = 65535; monitor->hmax = 0;
510 monitor->vmin = 65535; monitor->vmax = 0;
511 monitor->dclockmax = 0;
512 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
513 for(i = 0; i < 13; i++) {
514 if(emodes & sisfb_ddcsmodes[i].mask) {
515 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
516 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
517 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
518 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
519 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
523 for(i = 0; i < 8; i++) {
524 xres = (buffer[index] + 31) * 8;
525 switch(buffer[index + 1] & 0xc0) {
526 case 0xc0: yres = (xres * 9) / 16; break;
527 case 0x80: yres = (xres * 4) / 5; break;
528 case 0x40: yres = (xres * 3) / 4; break;
529 default: yres = xres; break;
531 refresh = (buffer[index + 1] & 0x3f) + 60;
532 if((xres >= 640) && (yres >= 480)) {
533 for(j = 0; j < 8; j++) {
534 if((xres == sisfb_ddcfmodes[j].x) &&
535 (yres == sisfb_ddcfmodes[j].y) &&
536 (refresh == sisfb_ddcfmodes[j].v)) {
537 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
538 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
539 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
540 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
541 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
547 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
548 monitor->datavalid = TRUE;
552 return monitor->datavalid;
555 static void __devinit
556 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
558 unsigned short temp, i, realcrtno = crtno;
559 unsigned char buffer[256];
561 monitor->datavalid = FALSE;
564 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
565 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
569 if((ivideo->sisfb_crt1off) && (!crtno))
572 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
573 realcrtno, 0, &buffer[0], ivideo->vbflags2);
574 if((!temp) || (temp == 0xffff)) {
575 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
578 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
579 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
581 (temp & 0x1a) ? "" : "[none of the supported]",
582 (temp & 0x02) ? "2 " : "",
583 (temp & 0x08) ? "D&P" : "",
584 (temp & 0x10) ? "FPDI-2" : "");
586 i = 3; /* Number of retrys */
588 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
589 realcrtno, 1, &buffer[0], ivideo->vbflags2);
590 } while((temp) && i--);
592 if(sisfb_interpret_edid(monitor, &buffer[0])) {
593 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
594 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
595 monitor->dclockmax / 1000);
597 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
600 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
603 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
608 /* -------------- Mode validation --------------- */
611 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
612 int mode_idx, int rate_idx, int rate)
615 unsigned int dclock, hsync;
617 if(!monitor->datavalid)
623 /* Skip for 320x200, 320x240, 640x400 */
624 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
635 #ifdef CONFIG_FB_SIS_315
638 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
642 if(rate < (monitor->vmin - 1))
644 if(rate > (monitor->vmax + 1))
647 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
648 sisbios_mode[mode_idx].mode_no[ivideo->mni],
649 &htotal, &vtotal, rate_idx)) {
650 dclock = (htotal * vtotal * rate) / 1000;
651 if(dclock > (monitor->dclockmax + 1000))
653 hsync = dclock / htotal;
654 if(hsync < (monitor->hmin - 1))
656 if(hsync > (monitor->hmax + 1))
665 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
667 u16 xres=0, yres, myres;
669 #ifdef CONFIG_FB_SIS_300
670 if(ivideo->sisvga_engine == SIS_300_VGA) {
671 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
675 #ifdef CONFIG_FB_SIS_315
676 if(ivideo->sisvga_engine == SIS_315_VGA) {
677 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
682 myres = sisbios_mode[myindex].yres;
684 switch(vbflags & VB_DISPTYPE_DISP2) {
687 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
689 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
690 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
691 if(sisbios_mode[myindex].xres > xres)
697 if(ivideo->sisfb_fstn) {
698 if(sisbios_mode[myindex].xres == 320) {
700 switch(sisbios_mode[myindex].mode_no[1]) {
701 case 0x50: myindex = MODE_FSTN_8; break;
702 case 0x56: myindex = MODE_FSTN_16; break;
703 case 0x53: return -1;
709 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
710 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
711 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
717 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
718 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
724 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
725 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
735 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
738 u16 xres = sisbios_mode[mode_idx].xres;
739 u16 yres = sisbios_mode[mode_idx].yres;
741 ivideo->rate_idx = 0;
742 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
743 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
744 if(sisfb_vrate[i].refresh == rate) {
745 ivideo->rate_idx = sisfb_vrate[i].idx;
747 } else if(sisfb_vrate[i].refresh > rate) {
748 if((sisfb_vrate[i].refresh - rate) <= 3) {
749 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
750 rate, sisfb_vrate[i].refresh);
751 ivideo->rate_idx = sisfb_vrate[i].idx;
752 ivideo->refresh_rate = sisfb_vrate[i].refresh;
753 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
754 && (sisfb_vrate[i].idx != 1)) {
755 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
756 rate, sisfb_vrate[i-1].refresh);
757 ivideo->rate_idx = sisfb_vrate[i-1].idx;
758 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
761 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
762 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
763 rate, sisfb_vrate[i].refresh);
764 ivideo->rate_idx = sisfb_vrate[i].idx;
770 if(ivideo->rate_idx > 0) {
771 return ivideo->rate_idx;
773 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
780 sisfb_bridgeisslave(struct sis_video_info *ivideo)
784 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
787 inSISIDXREG(SISPART1,0x00,P1_00);
788 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
789 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
797 sisfballowretracecrt1(struct sis_video_info *ivideo)
801 inSISIDXREG(SISCR,0x17,temp);
805 inSISIDXREG(SISSR,0x1f,temp);
813 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
815 if(!sisfballowretracecrt1(ivideo))
818 if(inSISREG(SISINPSTAT) & 0x08)
825 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
829 if(!sisfballowretracecrt1(ivideo))
833 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
835 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
839 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
841 unsigned char temp, reg;
843 switch(ivideo->sisvga_engine) {
844 case SIS_300_VGA: reg = 0x25; break;
845 case SIS_315_VGA: reg = 0x30; break;
846 default: return FALSE;
849 inSISIDXREG(SISPART1, reg, temp);
857 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
859 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
860 if(!sisfb_bridgeisslave(ivideo)) {
861 return sisfbcheckvretracecrt2(ivideo);
864 return sisfbcheckvretracecrt1(ivideo);
868 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
870 u8 idx, reg1, reg2, reg3, reg4;
873 (*vcount) = (*hcount) = 0;
875 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
877 ret |= (FB_VBLANK_HAVE_VSYNC |
878 FB_VBLANK_HAVE_HBLANK |
879 FB_VBLANK_HAVE_VBLANK |
880 FB_VBLANK_HAVE_VCOUNT |
881 FB_VBLANK_HAVE_HCOUNT);
882 switch(ivideo->sisvga_engine) {
883 case SIS_300_VGA: idx = 0x25; break;
885 case SIS_315_VGA: idx = 0x30; break;
887 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
888 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
889 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
890 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
891 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
892 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
893 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
894 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
895 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
897 } else if(sisfballowretracecrt1(ivideo)) {
899 ret |= (FB_VBLANK_HAVE_VSYNC |
900 FB_VBLANK_HAVE_VBLANK |
901 FB_VBLANK_HAVE_VCOUNT |
902 FB_VBLANK_HAVE_HCOUNT);
903 reg1 = inSISREG(SISINPSTAT);
904 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
905 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
906 inSISIDXREG(SISCR,0x20,reg1);
907 inSISIDXREG(SISCR,0x1b,reg1);
908 inSISIDXREG(SISCR,0x1c,reg2);
909 inSISIDXREG(SISCR,0x1d,reg3);
910 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
911 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
918 sisfb_myblank(struct sis_video_info *ivideo, int blank)
920 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
921 BOOLEAN backlight = TRUE;
924 case FB_BLANK_UNBLANK: /* on */
933 case FB_BLANK_NORMAL: /* blank */
942 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
951 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
960 case FB_BLANK_POWERDOWN: /* off */
973 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
975 if( (!ivideo->sisfb_thismonitor.datavalid) ||
976 ((ivideo->sisfb_thismonitor.datavalid) &&
977 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
979 if(ivideo->sisvga_engine == SIS_315_VGA) {
980 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
983 if(!(sisfb_bridgeisslave(ivideo))) {
984 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
985 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
991 if(ivideo->currentvbflags & CRT2_LCD) {
993 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
995 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
997 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
999 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1000 #ifdef CONFIG_FB_SIS_315
1001 if(ivideo->vbflags2 & VB2_CHRONTEL) {
1003 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
1005 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
1011 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
1012 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
1013 ((ivideo->sisvga_engine == SIS_315_VGA) &&
1014 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
1015 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
1018 if(ivideo->sisvga_engine == SIS_300_VGA) {
1019 if((ivideo->vbflags2 & VB2_30xB) &&
1020 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1021 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
1023 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1024 if((ivideo->vbflags2 & VB2_30xB) &&
1025 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1026 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1030 } else if(ivideo->currentvbflags & CRT2_VGA) {
1032 if(ivideo->vbflags2 & VB2_30xB) {
1033 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1041 /* ------------- Callbacks from init.c/init301.c -------------- */
1043 #ifdef CONFIG_FB_SIS_300
1045 sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1047 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1050 pci_read_config_dword(ivideo->nbridge, reg, &val);
1051 return (unsigned int)val;
1055 sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1057 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1059 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1063 sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1065 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1068 if(!ivideo->lpcdev) return 0;
1070 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1071 return (unsigned int)val;
1075 #ifdef CONFIG_FB_SIS_315
1077 sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1079 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1081 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1085 sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1087 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1090 if(!ivideo->lpcdev) return 0;
1092 pci_read_config_word(ivideo->lpcdev, reg, &val);
1093 return (unsigned int)val;
1097 /* ----------- FBDev related routines for all series ----------- */
1100 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1102 return (var->bits_per_pixel == 8) ? 256 : 16;
1106 sisfb_set_vparms(struct sis_video_info *ivideo)
1108 switch(ivideo->video_bpp) {
1110 ivideo->DstColor = 0x0000;
1111 ivideo->SiS310_AccelDepth = 0x00000000;
1112 ivideo->video_cmap_len = 256;
1115 ivideo->DstColor = 0x8000;
1116 ivideo->SiS310_AccelDepth = 0x00010000;
1117 ivideo->video_cmap_len = 16;
1120 ivideo->DstColor = 0xC000;
1121 ivideo->SiS310_AccelDepth = 0x00020000;
1122 ivideo->video_cmap_len = 16;
1125 ivideo->video_cmap_len = 16;
1126 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1132 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1134 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1136 if(maxyres > 32767) maxyres = 32767;
1142 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1144 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1145 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1146 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1147 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1148 ivideo->scrnpitchCRT1 <<= 1;
1154 sisfb_set_pitch(struct sis_video_info *ivideo)
1156 BOOLEAN isslavemode = FALSE;
1157 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1158 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1160 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
1162 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1163 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1164 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1165 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1168 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1169 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1170 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1171 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1172 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1177 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1179 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1181 switch(var->bits_per_pixel) {
1183 var->red.offset = var->green.offset = var->blue.offset = 0;
1184 var->red.length = var->green.length = var->blue.length = 6;
1187 var->red.offset = 11;
1188 var->red.length = 5;
1189 var->green.offset = 5;
1190 var->green.length = 6;
1191 var->blue.offset = 0;
1192 var->blue.length = 5;
1193 var->transp.offset = 0;
1194 var->transp.length = 0;
1197 var->red.offset = 16;
1198 var->red.length = 8;
1199 var->green.offset = 8;
1200 var->green.length = 8;
1201 var->blue.offset = 0;
1202 var->blue.length = 8;
1203 var->transp.offset = 24;
1204 var->transp.length = 8;
1210 sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1212 unsigned short modeno = ivideo->mode_no;
1214 /* >=2.6.12's fbcon clears the screen anyway */
1215 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
1216 if(!clrscrn) modeno |= 0x80;
1221 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1223 sisfb_pre_setmode(ivideo);
1225 if(SiSSetMode(&ivideo->SiS_Pr, modeno) == 0) {
1226 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1230 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1232 sisfb_post_setmode(ivideo);
1239 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1241 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1242 unsigned int htotal = 0, vtotal = 0;
1243 unsigned int drate = 0, hrate = 0;
1244 int found_mode = 0, ret;
1248 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1250 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1252 pixclock = var->pixclock;
1254 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1255 vtotal += var->yres;
1257 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1258 vtotal += var->yres;
1260 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1261 vtotal += var->yres;
1263 } else vtotal += var->yres;
1265 if(!(htotal) || !(vtotal)) {
1266 DPRINTK("sisfb: Invalid 'var' information\n");
1270 if(pixclock && htotal && vtotal) {
1271 drate = 1000000000 / pixclock;
1272 hrate = (drate * 1000) / htotal;
1273 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1275 ivideo->refresh_rate = 60;
1278 old_mode = ivideo->sisfb_mode_idx;
1279 ivideo->sisfb_mode_idx = 0;
1281 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1282 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1283 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1284 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1285 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1286 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1290 ivideo->sisfb_mode_idx++;
1294 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1295 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1296 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1298 ivideo->sisfb_mode_idx = -1;
1301 if(ivideo->sisfb_mode_idx < 0) {
1302 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1303 var->yres, var->bits_per_pixel);
1304 ivideo->sisfb_mode_idx = old_mode;
1308 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1309 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1310 ivideo->refresh_rate = 60;
1313 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1314 if(ivideo->sisfb_thismonitor.datavalid) {
1315 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
1316 ivideo->rate_idx, ivideo->refresh_rate)) {
1317 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1322 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1323 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1327 /* If acceleration to be used? Need to know
1328 * before pre/post_set_mode()
1331 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1332 #ifdef STUPID_ACCELF_TEXT_SHIT
1333 if(var->accel_flags & FB_ACCELF_TEXT) {
1334 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1336 info->flags |= FBINFO_HWACCEL_DISABLED;
1339 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1341 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1344 if((ret = sisfb_set_mode(ivideo, 1))) {
1348 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1349 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1350 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1352 sisfb_calc_pitch(ivideo, var);
1353 sisfb_set_pitch(ivideo);
1355 sisfb_set_vparms(ivideo);
1357 ivideo->current_width = ivideo->video_width;
1358 ivideo->current_height = ivideo->video_height;
1359 ivideo->current_bpp = ivideo->video_bpp;
1360 ivideo->current_htotal = htotal;
1361 ivideo->current_vtotal = vtotal;
1362 ivideo->current_linelength = ivideo->video_linelength;
1363 ivideo->current_pixclock = var->pixclock;
1364 ivideo->current_refresh_rate = ivideo->refresh_rate;
1365 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1366 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1374 sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1376 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1378 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1379 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1380 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1381 if(ivideo->sisvga_engine == SIS_315_VGA) {
1382 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1387 sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1389 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1390 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1391 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1392 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1393 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1394 if(ivideo->sisvga_engine == SIS_315_VGA) {
1395 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1401 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1403 if(var->xoffset > (var->xres_virtual - var->xres)) {
1406 if(var->yoffset > (var->yres_virtual - var->yres)) {
1410 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
1412 /* calculate base bpp dep. */
1413 switch(var->bits_per_pixel) {
1417 ivideo->current_base >>= 1;
1421 ivideo->current_base >>= 2;
1425 ivideo->current_base += (ivideo->video_offset >> 2);
1427 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1428 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1433 /* ------------ FBDev related routines for 2.4 series ----------- */
1435 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1437 #include "sisfb_fbdev_2_4.h"
1441 /* ------------ FBDev related routines for 2.6 series ----------- */
1443 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1446 sisfb_open(struct fb_info *info, int user)
1452 sisfb_release(struct fb_info *info, int user)
1458 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1459 unsigned transp, struct fb_info *info)
1461 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1463 if(regno >= sisfb_get_cmap_len(&info->var))
1466 switch(info->var.bits_per_pixel) {
1468 outSISREG(SISDACA, regno);
1469 outSISREG(SISDACD, (red >> 10));
1470 outSISREG(SISDACD, (green >> 10));
1471 outSISREG(SISDACD, (blue >> 10));
1472 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1473 outSISREG(SISDAC2A, regno);
1474 outSISREG(SISDAC2D, (red >> 8));
1475 outSISREG(SISDAC2D, (green >> 8));
1476 outSISREG(SISDAC2D, (blue >> 8));
1480 ((u32 *)(info->pseudo_palette))[regno] =
1482 ((green & 0xfc00) >> 5) |
1483 ((blue & 0xf800) >> 11);
1489 ((u32 *)(info->pseudo_palette))[regno] =
1490 (red << 16) | (green << 8) | (blue);
1497 sisfb_set_par(struct fb_info *info)
1501 if((err = sisfb_do_set_var(&info->var, 1, info)))
1504 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1505 sisfb_get_fix(&info->fix, info->currcon, info);
1507 sisfb_get_fix(&info->fix, -1, info);
1513 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1515 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1516 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1517 unsigned int drate = 0, hrate = 0, maxyres;
1519 int refresh_rate, search_idx, tidx;
1520 BOOLEAN recalc_clock = FALSE;
1523 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1525 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1527 pixclock = var->pixclock;
1529 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1530 vtotal += var->yres;
1532 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1533 vtotal += var->yres;
1535 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1536 vtotal += var->yres;
1539 vtotal += var->yres;
1541 if(!(htotal) || !(vtotal)) {
1542 SISFAIL("sisfb: no valid timing data");
1546 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1547 (sisbios_mode[search_idx].xres <= var->xres) ) {
1548 if( (sisbios_mode[search_idx].xres == var->xres) &&
1549 (sisbios_mode[search_idx].yres == var->yres) &&
1550 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1551 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1552 ivideo->currentvbflags)) > 0) {
1563 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1564 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1565 (var->yres <= sisbios_mode[search_idx].yres) &&
1566 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1567 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1568 ivideo->currentvbflags)) > 0) {
1578 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1579 var->xres, var->yres, var->bits_per_pixel,
1580 sisbios_mode[search_idx].xres,
1581 sisbios_mode[search_idx].yres,
1582 var->bits_per_pixel);
1583 var->xres = sisbios_mode[search_idx].xres;
1584 var->yres = sisbios_mode[search_idx].yres;
1587 "sisfb: Failed to find supported mode near %dx%dx%d\n",
1588 var->xres, var->yres, var->bits_per_pixel);
1593 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1594 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1595 (var->bits_per_pixel == 8) ) {
1596 /* Slave modes on LVDS and 301B-DH */
1598 recalc_clock = TRUE;
1599 } else if( (ivideo->current_htotal == htotal) &&
1600 (ivideo->current_vtotal == vtotal) &&
1601 (ivideo->current_pixclock == pixclock) ) {
1602 /* x=x & y=y & c=c -> assume depth change */
1603 drate = 1000000000 / pixclock;
1604 hrate = (drate * 1000) / htotal;
1605 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1606 } else if( ( (ivideo->current_htotal != htotal) ||
1607 (ivideo->current_vtotal != vtotal) ) &&
1608 (ivideo->current_pixclock == var->pixclock) ) {
1609 /* x!=x | y!=y & c=c -> invalid pixclock */
1610 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1612 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1613 } else if(ivideo->sisfb_parm_rate != -1) {
1614 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1615 refresh_rate = ivideo->sisfb_parm_rate;
1619 recalc_clock = TRUE;
1620 } else if((pixclock) && (htotal) && (vtotal)) {
1621 drate = 1000000000 / pixclock;
1622 hrate = (drate * 1000) / htotal;
1623 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1624 } else if(ivideo->current_refresh_rate) {
1625 refresh_rate = ivideo->current_refresh_rate;
1626 recalc_clock = TRUE;
1629 recalc_clock = TRUE;
1632 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1634 /* Eventually recalculate timing and clock */
1636 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1637 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1638 sisbios_mode[search_idx].mode_no[ivideo->mni],
1640 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1641 sisbios_mode[search_idx].mode_no[ivideo->mni],
1643 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1644 var->pixclock <<= 1;
1648 if(ivideo->sisfb_thismonitor.datavalid) {
1649 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1650 myrateindex, refresh_rate)) {
1652 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1656 /* Adapt RGB settings */
1657 sisfb_bpp_to_var(ivideo, var);
1659 /* Sanity check for offsets */
1660 if(var->xoffset < 0) var->xoffset = 0;
1661 if(var->yoffset < 0) var->yoffset = 0;
1663 if(var->xres > var->xres_virtual)
1664 var->xres_virtual = var->xres;
1666 if(ivideo->sisfb_ypan) {
1667 maxyres = sisfb_calc_maxyres(ivideo, var);
1668 if(ivideo->sisfb_max) {
1669 var->yres_virtual = maxyres;
1671 if(var->yres_virtual > maxyres) {
1672 var->yres_virtual = maxyres;
1675 if(var->yres_virtual <= var->yres) {
1676 var->yres_virtual = var->yres;
1679 if(var->yres != var->yres_virtual) {
1680 var->yres_virtual = var->yres;
1686 /* Truncate offsets to maximum if too high */
1687 if(var->xoffset > var->xres_virtual - var->xres) {
1688 var->xoffset = var->xres_virtual - var->xres - 1;
1691 if(var->yoffset > var->yres_virtual - var->yres) {
1692 var->yoffset = var->yres_virtual - var->yres - 1;
1695 /* Set everything else to 0 */
1696 var->red.msb_right =
1697 var->green.msb_right =
1698 var->blue.msb_right =
1699 var->transp.offset =
1700 var->transp.length =
1701 var->transp.msb_right = 0;
1707 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1709 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1712 if(var->xoffset > (var->xres_virtual - var->xres))
1715 if(var->yoffset > (var->yres_virtual - var->yres))
1718 if(var->vmode & FB_VMODE_YWRAP)
1721 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
1722 var->yoffset + info->var.yres > info->var.yres_virtual)
1725 if((err = sisfb_pan_var(ivideo, var)) < 0)
1728 info->var.xoffset = var->xoffset;
1729 info->var.yoffset = var->yoffset;
1735 sisfb_blank(int blank, struct fb_info *info)
1737 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1739 return sisfb_myblank(ivideo, blank);
1744 /* ----------- FBDev related routines for all series ---------- */
1747 sisfb_ioctl(struct inode *inode, struct file *file,
1748 unsigned int cmd, unsigned long arg,
1749 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1752 struct fb_info *info)
1754 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1755 struct sis_memreq sismemreq;
1756 struct fb_vblank sisvbblank;
1761 u32 __user *argp = (u32 __user *)arg;
1765 if(!capable(CAP_SYS_RAWIO))
1768 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1771 sis_malloc(&sismemreq);
1773 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1774 sis_free((u32)sismemreq.offset);
1780 if(!capable(CAP_SYS_RAWIO))
1783 if(get_user(gpu32, argp))
1789 case FBIOGET_VBLANK:
1790 sisvbblank.count = 0;
1791 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1793 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1798 case SISFB_GET_INFO_SIZE:
1799 return put_user(sizeof(struct sisfb_info), argp);
1801 case SISFB_GET_INFO_OLD:
1802 if(ivideo->warncount++ < 10)
1804 "sisfb: Deprecated ioctl call received - update your application!\n");
1805 case SISFB_GET_INFO: /* For communication with X driver */
1806 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1807 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1808 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1809 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1810 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1811 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1812 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1813 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1814 if(ivideo->modechanged) {
1815 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1817 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1819 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1820 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1821 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1822 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1823 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1824 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1825 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1826 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1827 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1828 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1829 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1830 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1831 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1832 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1833 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1834 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1835 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1836 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1837 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1838 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1839 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1840 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1841 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1842 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1843 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1844 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1845 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1846 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1848 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1849 sizeof(ivideo->sisfb_infoblock)))
1854 case SISFB_GET_VBRSTATUS_OLD:
1855 if(ivideo->warncount++ < 10)
1857 "sisfb: Deprecated ioctl call received - update your application!\n");
1858 case SISFB_GET_VBRSTATUS:
1859 if(sisfb_CheckVBRetrace(ivideo))
1860 return put_user((u32)1, argp);
1862 return put_user((u32)0, argp);
1864 case SISFB_GET_AUTOMAXIMIZE_OLD:
1865 if(ivideo->warncount++ < 10)
1867 "sisfb: Deprecated ioctl call received - update your application!\n");
1868 case SISFB_GET_AUTOMAXIMIZE:
1869 if(ivideo->sisfb_max)
1870 return put_user((u32)1, argp);
1872 return put_user((u32)0, argp);
1874 case SISFB_SET_AUTOMAXIMIZE_OLD:
1875 if(ivideo->warncount++ < 10)
1877 "sisfb: Deprecated ioctl call received - update your application!\n");
1878 case SISFB_SET_AUTOMAXIMIZE:
1879 if(get_user(gpu32, argp))
1882 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1885 case SISFB_SET_TVPOSOFFSET:
1886 if(get_user(gpu32, argp))
1889 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1890 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1893 case SISFB_GET_TVPOSOFFSET:
1894 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1898 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1899 sizeof(struct sisfb_cmd)))
1902 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1904 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1905 sizeof(struct sisfb_cmd)))
1910 case SISFB_SET_LOCK:
1911 if(get_user(gpu32, argp))
1914 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1918 #ifdef SIS_NEW_CONFIG_COMPAT
1919 return -ENOIOCTLCMD;
1927 #ifdef SIS_NEW_CONFIG_COMPAT
1929 sisfb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg, struct fb_info *info)
1934 ret = sisfb_ioctl(NULL, f, cmd, arg, info);
1941 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1943 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1945 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1947 strcpy(fix->id, ivideo->myid);
1949 fix->smem_start = ivideo->video_base + ivideo->video_offset;
1950 fix->smem_len = ivideo->sisfb_mem;
1951 fix->type = FB_TYPE_PACKED_PIXELS;
1953 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1955 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1957 fix->line_length = ivideo->video_linelength;
1958 fix->mmio_start = ivideo->mmio_base;
1959 fix->mmio_len = ivideo->mmio_size;
1960 if(ivideo->sisvga_engine == SIS_300_VGA) {
1961 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1962 } else if((ivideo->chip == SIS_330) ||
1963 (ivideo->chip == SIS_760) ||
1964 (ivideo->chip == SIS_761)) {
1965 fix->accel = FB_ACCEL_SIS_XABRE;
1966 } else if(ivideo->chip == XGI_20) {
1967 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1968 } else if(ivideo->chip >= XGI_40) {
1969 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1971 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1977 /* ---------------- fb_ops structures ----------------- */
1979 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1980 static struct fb_ops sisfb_ops = {
1981 .owner = THIS_MODULE,
1982 .fb_get_fix = sisfb_get_fix,
1983 .fb_get_var = sisfb_get_var,
1984 .fb_set_var = sisfb_set_var,
1985 .fb_get_cmap = sisfb_get_cmap,
1986 .fb_set_cmap = sisfb_set_cmap,
1987 .fb_pan_display = sisfb_pan_display,
1988 .fb_ioctl = sisfb_ioctl
1992 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1993 static struct fb_ops sisfb_ops = {
1994 .owner = THIS_MODULE,
1995 .fb_open = sisfb_open,
1996 .fb_release = sisfb_release,
1997 .fb_check_var = sisfb_check_var,
1998 .fb_set_par = sisfb_set_par,
1999 .fb_setcolreg = sisfb_setcolreg,
2000 .fb_pan_display = sisfb_pan_display,
2001 .fb_blank = sisfb_blank,
2002 .fb_fillrect = fbcon_sis_fillrect,
2003 .fb_copyarea = fbcon_sis_copyarea,
2004 .fb_imageblit = cfb_imageblit,
2005 #ifdef CONFIG_FB_SOFT_CURSOR
2006 .fb_cursor = soft_cursor,
2008 .fb_sync = fbcon_sis_sync,
2009 #ifdef SIS_NEW_CONFIG_COMPAT
2010 .fb_compat_ioctl= sisfb_compat_ioctl,
2012 .fb_ioctl = sisfb_ioctl
2016 /* ---------------- Chip generation dependent routines ---------------- */
2018 static struct pci_dev * __devinit
2019 sisfb_get_northbridge(int basechipid)
2021 struct pci_dev *pdev = NULL;
2022 int nbridgenum, nbridgeidx, i;
2023 static const unsigned short nbridgeids[] = {
2024 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2025 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2026 PCI_DEVICE_ID_SI_730,
2027 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2028 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2029 PCI_DEVICE_ID_SI_651,
2030 PCI_DEVICE_ID_SI_740,
2031 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
2032 PCI_DEVICE_ID_SI_741,
2033 PCI_DEVICE_ID_SI_660,
2034 PCI_DEVICE_ID_SI_760,
2035 PCI_DEVICE_ID_SI_761
2038 switch(basechipid) {
2039 #ifdef CONFIG_FB_SIS_300
2040 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2041 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2043 #ifdef CONFIG_FB_SIS_315
2044 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2045 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
2046 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
2048 default: return NULL;
2050 for(i = 0; i < nbridgenum; i++) {
2051 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2052 nbridgeids[nbridgeidx+i], NULL)))
2058 static int __devinit
2059 sisfb_get_dram_size(struct sis_video_info *ivideo)
2061 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2065 ivideo->video_size = 0;
2066 ivideo->UMAsize = ivideo->LFBsize = 0;
2068 switch(ivideo->chip) {
2069 #ifdef CONFIG_FB_SIS_300
2071 inSISIDXREG(SISSR, 0x14, reg);
2072 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2077 if(!ivideo->nbridge)
2079 pci_read_config_byte(ivideo->nbridge, 0x63, ®);
2080 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2083 #ifdef CONFIG_FB_SIS_315
2087 inSISIDXREG(SISSR, 0x14, reg);
2088 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2089 switch((reg >> 2) & 0x03) {
2092 ivideo->video_size <<= 1;
2095 ivideo->video_size += (ivideo->video_size/2);
2099 inSISIDXREG(SISSR, 0x14, reg);
2100 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2101 if(reg & 0x0c) ivideo->video_size <<= 1;
2106 inSISIDXREG(SISSR, 0x14, reg);
2107 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2111 inSISIDXREG(SISCR, 0x79, reg);
2112 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2117 inSISIDXREG(SISCR, 0x79, reg);
2118 reg = (reg & 0xf0) >> 4;
2120 ivideo->video_size = (1 << reg) << 20;
2121 ivideo->UMAsize = ivideo->video_size;
2123 inSISIDXREG(SISCR, 0x78, reg);
2127 ivideo->LFBsize = (32 << 20);
2129 ivideo->LFBsize = (64 << 20);
2131 ivideo->video_size += ivideo->LFBsize;
2137 inSISIDXREG(SISSR, 0x14, reg);
2138 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2139 if(ivideo->chip != XGI_20) {
2140 reg = (reg & 0x0c) >> 2;
2141 if(ivideo->revision_id == 2) {
2142 if(reg & 0x01) reg = 0x02;
2145 if(reg == 0x02) ivideo->video_size <<= 1;
2146 else if(reg == 0x03) ivideo->video_size <<= 2;
2156 /* -------------- video bridge device detection --------------- */
2158 static void __devinit
2159 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2163 /* No CRT2 on XGI Z7 */
2164 if(ivideo->chip == XGI_20) {
2165 ivideo->sisfb_crt1off = 0;
2169 #ifdef CONFIG_FB_SIS_300
2170 if(ivideo->sisvga_engine == SIS_300_VGA) {
2171 inSISIDXREG(SISSR, 0x17, temp);
2172 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2173 /* PAL/NTSC is stored on SR16 on such machines */
2174 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2175 inSISIDXREG(SISSR, 0x16, temp);
2177 ivideo->vbflags |= TV_PAL;
2179 ivideo->vbflags |= TV_NTSC;
2185 inSISIDXREG(SISCR, 0x32, cr32);
2187 if(cr32 & SIS_CRT1) {
2188 ivideo->sisfb_crt1off = 0;
2190 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2193 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2195 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2196 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2197 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2199 /* Check given parms for hardware compatibility.
2200 * (Cannot do this in the search_xx routines since we don't
2201 * know what hardware we are running on then)
2204 if(ivideo->chip != SIS_550) {
2205 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2208 if(ivideo->sisfb_tvplug != -1) {
2209 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2210 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2211 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2212 ivideo->sisfb_tvplug = -1;
2213 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2217 if(ivideo->sisfb_tvplug != -1) {
2218 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2219 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2220 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2221 ivideo->sisfb_tvplug = -1;
2222 printk(KERN_ERR "sisfb: HiVision not supported\n");
2226 if(ivideo->sisfb_tvstd != -1) {
2227 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2228 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2229 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2230 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2231 ivideo->sisfb_tvstd = -1;
2232 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2237 /* Detect/set TV plug & type */
2238 if(ivideo->sisfb_tvplug != -1) {
2239 ivideo->vbflags |= ivideo->sisfb_tvplug;
2241 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2242 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2243 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2245 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2246 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2250 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2251 if(ivideo->sisfb_tvstd != -1) {
2252 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2253 ivideo->vbflags |= ivideo->sisfb_tvstd;
2255 if(ivideo->vbflags & TV_SCART) {
2256 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2257 ivideo->vbflags |= TV_PAL;
2259 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2260 if(ivideo->sisvga_engine == SIS_300_VGA) {
2261 inSISIDXREG(SISSR, 0x38, temp);
2262 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2263 else ivideo->vbflags |= TV_NTSC;
2264 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2265 inSISIDXREG(SISSR, 0x38, temp);
2266 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2267 else ivideo->vbflags |= TV_NTSC;
2269 inSISIDXREG(SISCR, 0x79, temp);
2270 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2271 else ivideo->vbflags |= TV_NTSC;
2276 /* Copy forceCRT1 option to CRT1off if option is given */
2277 if(ivideo->sisfb_forcecrt1 != -1) {
2278 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2282 /* ------------------ Sensing routines ------------------ */
2284 static BOOLEAN __devinit
2285 sisfb_test_DDC1(struct sis_video_info *ivideo)
2290 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2292 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2294 return (count == -1) ? FALSE : TRUE;
2297 static void __devinit
2298 sisfb_sense_crt1(struct sis_video_info *ivideo)
2300 BOOLEAN mustwait = FALSE;
2302 #ifdef CONFIG_FB_SIS_315
2308 inSISIDXREG(SISSR,0x1F,sr1F);
2309 orSISIDXREG(SISSR,0x1F,0x04);
2310 andSISIDXREG(SISSR,0x1F,0x3F);
2311 if(sr1F & 0xc0) mustwait = TRUE;
2313 #ifdef CONFIG_FB_SIS_315
2314 if(ivideo->sisvga_engine == SIS_315_VGA) {
2315 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2317 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2321 inSISIDXREG(SISCR,0x17,cr17);
2324 orSISIDXREG(SISCR,0x17,0x80);
2326 outSISIDXREG(SISSR, 0x00, 0x01);
2327 outSISIDXREG(SISSR, 0x00, 0x03);
2331 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2334 #ifdef CONFIG_FB_SIS_315
2335 if(ivideo->chip >= SIS_330) {
2336 andSISIDXREG(SISCR,0x32,~0x20);
2337 if(ivideo->chip >= SIS_340) {
2338 outSISIDXREG(SISCR, 0x57, 0x4a);
2340 outSISIDXREG(SISCR, 0x57, 0x5f);
2342 orSISIDXREG(SISCR, 0x53, 0x02);
2343 while((inSISREG(SISINPSTAT)) & 0x01) break;
2344 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2345 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2346 andSISIDXREG(SISCR, 0x53, 0xfd);
2347 andSISIDXREG(SISCR, 0x57, 0x00);
2351 if(temp == 0xffff) {
2354 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2355 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2356 } while(((temp == 0) || (temp == 0xffff)) && i--);
2358 if((temp == 0) || (temp == 0xffff)) {
2359 if(sisfb_test_DDC1(ivideo)) temp = 1;
2363 if((temp) && (temp != 0xffff)) {
2364 orSISIDXREG(SISCR,0x32,0x20);
2367 #ifdef CONFIG_FB_SIS_315
2368 if(ivideo->sisvga_engine == SIS_315_VGA) {
2369 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2373 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2375 outSISIDXREG(SISSR,0x1F,sr1F);
2378 /* Determine and detect attached devices on SiS30x */
2379 static void __devinit
2380 SiS_SenseLCD(struct sis_video_info *ivideo)
2382 unsigned char buffer[256];
2383 unsigned short temp, realcrtno, i;
2384 u8 reg, cr37 = 0, paneltype = 0;
2387 ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2389 /* LCD detection only for TMDS bridges */
2390 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2392 if(ivideo->vbflags2 & VB2_30xBDH)
2395 /* If LCD already set up by BIOS, skip it */
2396 inSISIDXREG(SISCR, 0x32, reg);
2401 if(ivideo->SiS_Pr.DDCPortMixup)
2404 /* Check DDC capabilities */
2405 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2406 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2408 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2412 i = 3; /* Number of retrys */
2414 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2415 ivideo->sisvga_engine, realcrtno, 1,
2416 &buffer[0], ivideo->vbflags2);
2417 } while((temp) && i--);
2422 /* No digital device */
2423 if(!(buffer[0x14] & 0x80))
2426 /* First detailed timing preferred timing? */
2427 if(!(buffer[0x18] & 0x02))
2430 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2431 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2443 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2454 if((buffer[0x47] & 0x18) == 0x18)
2455 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2459 outSISIDXREG(SISCR, 0x36, paneltype);
2461 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2462 orSISIDXREG(SISCR, 0x32, 0x08);
2464 ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2467 static int __devinit
2468 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2470 int temp, mytest, result, i, j;
2472 for(j = 0; j < 10; j++) {
2474 for(i = 0; i < 3; i++) {
2476 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2477 temp = (type >> 8) | (mytest & 0x00ff);
2478 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2479 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2482 inSISIDXREG(SISPART4,0x03,temp);
2485 if(temp == mytest) result++;
2487 outSISIDXREG(SISPART4,0x11,0x00);
2488 andSISIDXREG(SISPART4,0x10,0xe0);
2489 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2492 if((result == 0) || (result >= 2)) break;
2497 static void __devinit
2498 SiS_Sense30x(struct sis_video_info *ivideo)
2500 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2501 u16 svhs=0, svhs_c=0;
2502 u16 cvbs=0, cvbs_c=0;
2503 u16 vga2=0, vga2_c=0;
2505 char stdstr[] = "sisfb: Detected";
2506 char tvstr[] = "TV connected to";
2508 if(ivideo->vbflags2 & VB2_301) {
2509 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2510 inSISIDXREG(SISPART4,0x01,myflag);
2512 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2514 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2515 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2516 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2517 svhs = 0x0200; cvbs = 0x0100;
2518 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2519 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2523 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2524 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2525 svhs_c = 0x0408; cvbs_c = 0x0808;
2529 if(ivideo->haveXGIROM) {
2530 biosflag = ivideo->bios_abase[0x58] & 0x03;
2531 } else if(ivideo->newrom) {
2532 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2533 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2534 if(ivideo->bios_abase) {
2535 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2539 if(ivideo->chip == SIS_300) {
2540 inSISIDXREG(SISSR,0x3b,myflag);
2541 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2544 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2548 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2549 orSISIDXREG(SISSR,0x1e,0x20);
2551 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2552 if(ivideo->vbflags2 & VB2_30xC) {
2553 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2555 orSISIDXREG(SISPART4,0x0d,0x04);
2557 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2559 inSISIDXREG(SISPART2,0x00,backupP2_00);
2560 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2562 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2563 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2564 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2567 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2568 SISDoSense(ivideo, 0, 0);
2571 andSISIDXREG(SISCR, 0x32, ~0x14);
2573 if(vga2_c || vga2) {
2574 if(SISDoSense(ivideo, vga2, vga2_c)) {
2575 if(biosflag & 0x01) {
2576 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2577 orSISIDXREG(SISCR, 0x32, 0x04);
2579 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2580 orSISIDXREG(SISCR, 0x32, 0x10);
2585 andSISIDXREG(SISCR, 0x32, 0x3f);
2587 if(ivideo->vbflags2 & VB2_30xCLV) {
2588 orSISIDXREG(SISPART4,0x0d,0x04);
2591 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2592 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2593 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2594 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2595 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2596 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2597 orSISIDXREG(SISCR,0x32,0x80);
2600 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2603 andSISIDXREG(SISCR, 0x32, ~0x03);
2605 if(!(ivideo->vbflags & TV_YPBPR)) {
2606 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2607 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2608 orSISIDXREG(SISCR, 0x32, 0x02);
2610 if((biosflag & 0x02) || (!result)) {
2611 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2612 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2613 orSISIDXREG(SISCR, 0x32, 0x01);
2618 SISDoSense(ivideo, 0, 0);
2620 outSISIDXREG(SISPART2,0x00,backupP2_00);
2621 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2622 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2624 if(ivideo->vbflags2 & VB2_30xCLV) {
2625 inSISIDXREG(SISPART2,0x00,biosflag);
2626 if(biosflag & 0x20) {
2627 for(myflag = 2; myflag > 0; myflag--) {
2629 outSISIDXREG(SISPART2,0x00,biosflag);
2634 outSISIDXREG(SISPART2,0x00,backupP2_00);
2637 /* Determine and detect attached TV's on Chrontel */
2638 static void __devinit
2639 SiS_SenseCh(struct sis_video_info *ivideo)
2641 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2643 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2645 #ifdef CONFIG_FB_SIS_300
2646 unsigned char test[3];
2650 if(ivideo->chip < SIS_315H) {
2652 #ifdef CONFIG_FB_SIS_300
2653 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2654 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2655 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2656 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2657 /* See Chrontel TB31 for explanation */
2658 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2659 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2660 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2661 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2663 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2664 if(temp2 != temp1) temp1 = temp2;
2666 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2667 /* Read power status */
2668 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2669 if((temp1 & 0x03) != 0x03) {
2670 /* Power all outputs */
2671 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2672 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2674 /* Sense connected TV devices */
2675 for(i = 0; i < 3; i++) {
2676 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2677 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2678 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2679 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2680 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2681 if(!(temp1 & 0x08)) test[i] = 0x02;
2682 else if(!(temp1 & 0x02)) test[i] = 0x01;
2684 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2687 if(test[0] == test[1]) temp1 = test[0];
2688 else if(test[0] == test[2]) temp1 = test[0];
2689 else if(test[1] == test[2]) temp1 = test[1];
2692 "sisfb: TV detection unreliable - test results varied\n");
2696 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2697 ivideo->vbflags |= TV_SVIDEO;
2698 orSISIDXREG(SISCR, 0x32, 0x02);
2699 andSISIDXREG(SISCR, 0x32, ~0x05);
2700 } else if (temp1 == 0x01) {
2701 printk(KERN_INFO "%s CVBS output\n", stdstr);
2702 ivideo->vbflags |= TV_AVIDEO;
2703 orSISIDXREG(SISCR, 0x32, 0x01);
2704 andSISIDXREG(SISCR, 0x32, ~0x06);
2706 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2707 andSISIDXREG(SISCR, 0x32, ~0x07);
2709 } else if(temp1 == 0) {
2710 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2711 andSISIDXREG(SISCR, 0x32, ~0x07);
2713 /* Set general purpose IO for Chrontel communication */
2714 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2719 #ifdef CONFIG_FB_SIS_315
2720 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2721 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2722 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2723 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2724 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2726 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2727 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2729 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2730 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2731 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2732 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2734 if(temp2 & 0x02) temp1 |= 0x01;
2735 if(temp2 & 0x10) temp1 |= 0x01;
2736 if(temp2 & 0x04) temp1 |= 0x02;
2737 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2740 printk(KERN_INFO "%s CVBS output\n", stdstr);
2741 ivideo->vbflags |= TV_AVIDEO;
2742 orSISIDXREG(SISCR, 0x32, 0x01);
2743 andSISIDXREG(SISCR, 0x32, ~0x06);
2746 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2747 ivideo->vbflags |= TV_SVIDEO;
2748 orSISIDXREG(SISCR, 0x32, 0x02);
2749 andSISIDXREG(SISCR, 0x32, ~0x05);
2752 printk(KERN_INFO "%s SCART output\n", stdstr);
2753 orSISIDXREG(SISCR, 0x32, 0x04);
2754 andSISIDXREG(SISCR, 0x32, ~0x03);
2757 andSISIDXREG(SISCR, 0x32, ~0x07);
2763 static void __devinit
2764 sisfb_get_VB_type(struct sis_video_info *ivideo)
2766 char stdstr[] = "sisfb: Detected";
2767 char bridgestr[] = "video bridge";
2771 /* No CRT2 on XGI Z7 */
2772 if(ivideo->chip == XGI_20)
2775 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2778 inSISIDXREG(SISPART4, 0x01, reg);
2780 ivideo->vbflags |= VB_301; /* Deprecated */
2781 ivideo->vbflags2 |= VB2_301;
2782 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2783 } else if(reg < 0xc0) {
2784 ivideo->vbflags |= VB_301B; /* Deprecated */
2785 ivideo->vbflags2 |= VB2_301B;
2786 inSISIDXREG(SISPART4,0x23,reg);
2788 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2789 ivideo->vbflags2 |= VB2_30xBDH;
2790 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2792 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2794 } else if(reg < 0xd0) {
2795 ivideo->vbflags |= VB_301C; /* Deprecated */
2796 ivideo->vbflags2 |= VB2_301C;
2797 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2798 } else if(reg < 0xe0) {
2799 ivideo->vbflags |= VB_301LV; /* Deprecated */
2800 ivideo->vbflags2 |= VB2_301LV;
2801 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2802 } else if(reg <= 0xe1) {
2803 inSISIDXREG(SISPART4,0x39,reg);
2805 ivideo->vbflags |= VB_302LV; /* Deprecated */
2806 ivideo->vbflags2 |= VB2_302LV;
2807 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2809 ivideo->vbflags |= VB_301C; /* Deprecated */
2810 ivideo->vbflags2 |= VB2_301C;
2811 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2813 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2814 ivideo->vbflags2 |= VB2_302ELV;
2815 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2821 ivideo->vbflags |= VB_302B; /* Deprecated */
2822 ivideo->vbflags2 |= VB2_302B;
2823 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2827 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2828 inSISIDXREG(SISCR, 0x37, reg);
2829 reg &= SIS_EXTERNAL_CHIP_MASK;
2831 if(ivideo->sisvga_engine == SIS_300_VGA) {
2832 #ifdef CONFIG_FB_SIS_300
2834 case SIS_EXTERNAL_CHIP_LVDS:
2835 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2836 ivideo->vbflags2 |= VB2_LVDS;
2838 case SIS_EXTERNAL_CHIP_TRUMPION:
2839 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2840 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2842 case SIS_EXTERNAL_CHIP_CHRONTEL:
2843 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2844 ivideo->vbflags2 |= VB2_CHRONTEL;
2846 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2847 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2848 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2851 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2853 } else if(ivideo->chip < SIS_661) {
2854 #ifdef CONFIG_FB_SIS_315
2856 case SIS310_EXTERNAL_CHIP_LVDS:
2857 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2858 ivideo->vbflags2 |= VB2_LVDS;
2860 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2861 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2862 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2865 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2867 } else if(ivideo->chip >= SIS_661) {
2868 #ifdef CONFIG_FB_SIS_315
2869 inSISIDXREG(SISCR, 0x38, reg);
2873 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2874 ivideo->vbflags2 |= VB2_LVDS;
2877 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2878 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2881 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2882 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2885 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2888 if(ivideo->vbflags2 & VB2_LVDS) {
2889 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2891 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2892 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2894 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2895 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2897 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2898 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2902 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2903 SiS_SenseLCD(ivideo);
2904 SiS_Sense30x(ivideo);
2905 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2906 SiS_SenseCh(ivideo);
2910 /* ---------- Engine initialization routines ------------ */
2913 sisfb_engine_init(struct sis_video_info *ivideo)
2916 /* Initialize command queue (we use MMIO only) */
2918 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2920 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2921 MMIO_CMD_QUEUE_CAP |
2925 #ifdef CONFIG_FB_SIS_300
2926 if(ivideo->sisvga_engine == SIS_300_VGA) {
2930 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2932 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2935 tq_state |= (u8)(tqueue_pos >> 8);
2936 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2938 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2940 ivideo->caps |= TURBO_QUEUE_CAP;
2944 #ifdef CONFIG_FB_SIS_315
2945 if(ivideo->sisvga_engine == SIS_315_VGA) {
2946 u32 tempq = 0, templ;
2949 if(ivideo->chip == XGI_20) {
2950 switch(ivideo->cmdQueueSize) {
2952 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2956 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2959 switch(ivideo->cmdQueueSize) {
2960 case (4 * 1024 * 1024):
2961 temp = SIS_CMD_QUEUE_SIZE_4M;
2963 case (2 * 1024 * 1024):
2964 temp = SIS_CMD_QUEUE_SIZE_2M;
2966 case (1 * 1024 * 1024):
2967 temp = SIS_CMD_QUEUE_SIZE_1M;
2971 temp = SIS_CMD_QUEUE_SIZE_512k;
2975 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2976 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2978 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2979 /* Must disable dual pipe on XGI_40. Can't do
2980 * this in MMIO mode, because it requires
2981 * setting/clearing a bit in the MMIO fire trigger
2984 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2986 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2988 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2990 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2991 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2993 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2994 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2996 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2997 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2998 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2999 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
3001 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
3003 sisfb_syncaccel(ivideo);
3005 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3010 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3011 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3013 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3014 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3016 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3017 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3019 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3023 ivideo->engineok = 1;
3026 static void __devinit
3027 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3032 inSISIDXREG(SISCR, 0x36, reg);
3034 if(ivideo->sisvga_engine == SIS_300_VGA) {
3035 ivideo->CRT2LCDType = sis300paneltype[reg];
3036 } else if(ivideo->chip >= SIS_661) {
3037 ivideo->CRT2LCDType = sis661paneltype[reg];
3039 ivideo->CRT2LCDType = sis310paneltype[reg];
3040 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3041 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3042 (ivideo->CRT2LCDType != LCD_320x240_3)) {
3043 ivideo->CRT2LCDType = LCD_320x240;
3048 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3049 /* For broken BIOSes: Assume 1024x768, RGB18 */
3050 ivideo->CRT2LCDType = LCD_1024x768;
3051 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3052 setSISIDXREG(SISCR,0x37,0xee,0x01);
3053 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3056 for(i = 0; i < SIS_LCD_NUMBER; i++) {
3057 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3058 ivideo->lcdxres = sis_lcd_data[i].xres;
3059 ivideo->lcdyres = sis_lcd_data[i].yres;
3060 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3065 #ifdef CONFIG_FB_SIS_300
3066 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3067 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3068 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3069 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3070 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
3071 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3072 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3073 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
3074 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3078 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3079 ivideo->lcdxres, ivideo->lcdyres);
3082 static void __devinit
3083 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3085 #ifdef CONFIG_FB_SIS_300
3086 /* Save the current PanelDelayCompensation if the LCD is currently used */
3087 if(ivideo->sisvga_engine == SIS_300_VGA) {
3088 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3090 inSISIDXREG(SISCR,0x30,tmp);
3092 /* Currently on LCD? If yes, read current pdc */
3093 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3094 ivideo->detectedpdc &= 0x3c;
3095 if(ivideo->SiS_Pr.PDC == -1) {
3096 /* Let option override detection */
3097 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3099 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3100 ivideo->detectedpdc);
3102 if((ivideo->SiS_Pr.PDC != -1) &&
3103 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3104 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3105 ivideo->SiS_Pr.PDC);
3111 #ifdef CONFIG_FB_SIS_315
3112 if(ivideo->sisvga_engine == SIS_315_VGA) {
3114 /* Try to find about LCDA */
3115 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3117 inSISIDXREG(SISPART1,0x13,tmp);
3119 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3120 ivideo->detectedlcda = 0x03;
3125 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3127 inSISIDXREG(SISCR,0x30,tmp);
3128 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3129 /* Currently on LCD? If yes, read current pdc */
3131 inSISIDXREG(SISPART1,0x2D,pdc);
3132 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3133 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3134 inSISIDXREG(SISPART1,0x35,pdc);
3135 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3136 inSISIDXREG(SISPART1,0x20,pdc);
3137 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3138 if(ivideo->newrom) {
3139 /* New ROM invalidates other PDC resp. */
3140 if(ivideo->detectedlcda != 0xff) {
3141 ivideo->detectedpdc = 0xff;
3143 ivideo->detectedpdca = 0xff;
3146 if(ivideo->SiS_Pr.PDC == -1) {
3147 if(ivideo->detectedpdc != 0xff) {
3148 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3151 if(ivideo->SiS_Pr.PDCA == -1) {
3152 if(ivideo->detectedpdca != 0xff) {
3153 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3156 if(ivideo->detectedpdc != 0xff) {
3158 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3159 ivideo->detectedpdc);
3161 if(ivideo->detectedpdca != 0xff) {
3163 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3164 ivideo->detectedpdca);
3169 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3170 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3171 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3172 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3173 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3174 ivideo->SiS_Pr.HaveEMI = TRUE;
3175 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3176 ivideo->SiS_Pr.HaveEMILCD = TRUE;
3181 /* Let user override detected PDCs (all bridges) */
3182 if(ivideo->vbflags2 & VB2_30xBLV) {
3183 if((ivideo->SiS_Pr.PDC != -1) &&
3184 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3185 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3186 ivideo->SiS_Pr.PDC);
3188 if((ivideo->SiS_Pr.PDCA != -1) &&
3189 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3190 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3191 ivideo->SiS_Pr.PDCA);
3199 /* -------------------- Memory manager routines ---------------------- */
3201 static u32 __devinit
3202 sisfb_getheapstart(struct sis_video_info *ivideo)
3204 u32 ret = ivideo->sisfb_parm_mem * 1024;
3205 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3208 /* Calculate heap start = end of memory for console
3210 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3211 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3213 * On 76x in UMA+LFB mode, the layout is as follows:
3214 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3215 * where the heap is the entire UMA area, eventually
3216 * into the LFB area if the given mem parameter is
3217 * higher than the size of the UMA memory.
3219 * Basically given by "mem" parameter
3221 * maximum = videosize - cmd_queue - hwcursor
3222 * (results in a heap of size 0)
3223 * default = SiS 300: depends on videosize
3224 * SiS 315/330/340/XGI: 32k below max
3227 if(ivideo->sisvga_engine == SIS_300_VGA) {
3228 if(ivideo->video_size > 0x1000000) {
3230 } else if(ivideo->video_size > 0x800000) {
3235 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3238 def = maxoffs - 0x8000;
3241 /* Use default for secondary card for now (FIXME) */
3242 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3248 static u32 __devinit
3249 sisfb_getheapsize(struct sis_video_info *ivideo)
3251 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3254 if(ivideo->UMAsize && ivideo->LFBsize) {
3255 if( (!ivideo->sisfb_parm_mem) ||
3256 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3257 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3258 ret = ivideo->UMAsize;
3259 max -= ivideo->UMAsize;
3261 ret = max - (ivideo->sisfb_parm_mem * 1024);
3262 max = ivideo->sisfb_parm_mem * 1024;
3264 ivideo->video_offset = ret;
3265 ivideo->sisfb_mem = max;
3267 ret = max - ivideo->heapstart;
3268 ivideo->sisfb_mem = ivideo->heapstart;
3274 static int __devinit
3275 sisfb_heap_init(struct sis_video_info *ivideo)
3279 ivideo->video_offset = 0;
3280 if(ivideo->sisfb_parm_mem) {
3281 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3282 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3283 ivideo->sisfb_parm_mem = 0;
3287 ivideo->heapstart = sisfb_getheapstart(ivideo);
3288 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3290 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3291 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3293 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3294 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3296 ivideo->sisfb_heap.vinfo = ivideo;
3298 ivideo->sisfb_heap.poha_chain = NULL;
3299 ivideo->sisfb_heap.poh_freelist = NULL;
3301 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3305 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3306 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3307 poh->size = ivideo->sisfb_heap_size;
3308 poh->offset = ivideo->heapstart;
3310 ivideo->sisfb_heap.oh_free.poh_next = poh;
3311 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3312 ivideo->sisfb_heap.oh_free.size = 0;
3313 ivideo->sisfb_heap.max_freesize = poh->size;
3315 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3316 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3317 ivideo->sisfb_heap.oh_used.size = SENTINEL;
3319 if(ivideo->cardnumber == 0) {
3320 /* For the first card, make this heap the "global" one
3321 * for old DRM (which could handle only one card)
3323 sisfb_heap = &ivideo->sisfb_heap;
3329 static struct SIS_OH *
3330 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3332 struct SIS_OHALLOC *poha;
3337 if(memheap->poh_freelist == NULL) {
3338 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3342 poha->poha_next = memheap->poha_chain;
3343 memheap->poha_chain = poha;
3345 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3347 poh = &poha->aoh[0];
3348 for(i = cOhs - 1; i != 0; i--) {
3349 poh->poh_next = poh + 1;
3353 poh->poh_next = NULL;
3354 memheap->poh_freelist = &poha->aoh[0];
3357 poh = memheap->poh_freelist;
3358 memheap->poh_freelist = poh->poh_next;
3363 static struct SIS_OH *
3364 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3366 struct SIS_OH *pohThis;
3367 struct SIS_OH *pohRoot;
3370 if(size > memheap->max_freesize) {
3371 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3372 (unsigned int) size / 1024);
3376 pohThis = memheap->oh_free.poh_next;
3378 while(pohThis != &memheap->oh_free) {
3379 if(size <= pohThis->size) {
3383 pohThis = pohThis->poh_next;
3387 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3388 (unsigned int) size / 1024);
3392 if(size == pohThis->size) {
3394 sisfb_delete_node(pohThis);
3396 pohRoot = sisfb_poh_new_node(memheap);
3400 pohRoot->offset = pohThis->offset;
3401 pohRoot->size = size;
3403 pohThis->offset += size;
3404 pohThis->size -= size;
3407 memheap->max_freesize -= size;
3409 pohThis = &memheap->oh_used;
3410 sisfb_insert_node(pohThis, pohRoot);
3416 sisfb_delete_node(struct SIS_OH *poh)
3418 poh->poh_prev->poh_next = poh->poh_next;
3419 poh->poh_next->poh_prev = poh->poh_prev;
3423 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3425 struct SIS_OH *pohTemp = pohList->poh_next;
3427 pohList->poh_next = poh;
3428 pohTemp->poh_prev = poh;
3430 poh->poh_prev = pohList;
3431 poh->poh_next = pohTemp;
3434 static struct SIS_OH *
3435 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3437 struct SIS_OH *pohThis;
3438 struct SIS_OH *poh_freed;
3439 struct SIS_OH *poh_prev;
3440 struct SIS_OH *poh_next;
3445 poh_freed = memheap->oh_used.poh_next;
3447 while(poh_freed != &memheap->oh_used) {
3448 if(poh_freed->offset == base) {
3453 poh_freed = poh_freed->poh_next;
3459 memheap->max_freesize += poh_freed->size;
3461 poh_prev = poh_next = NULL;
3462 ulUpper = poh_freed->offset + poh_freed->size;
3463 ulLower = poh_freed->offset;
3465 pohThis = memheap->oh_free.poh_next;
3467 while(pohThis != &memheap->oh_free) {
3468 if(pohThis->offset == ulUpper) {
3470 } else if((pohThis->offset + pohThis->size) == ulLower) {
3473 pohThis = pohThis->poh_next;
3476 sisfb_delete_node(poh_freed);
3478 if(poh_prev && poh_next) {
3479 poh_prev->size += (poh_freed->size + poh_next->size);
3480 sisfb_delete_node(poh_next);
3481 sisfb_free_node(memheap, poh_freed);
3482 sisfb_free_node(memheap, poh_next);
3487 poh_prev->size += poh_freed->size;
3488 sisfb_free_node(memheap, poh_freed);
3493 poh_next->size += poh_freed->size;
3494 poh_next->offset = poh_freed->offset;
3495 sisfb_free_node(memheap, poh_freed);
3499 sisfb_insert_node(&memheap->oh_free, poh_freed);
3505 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3510 poh->poh_next = memheap->poh_freelist;
3511 memheap->poh_freelist = poh;
3515 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3517 struct SIS_OH *poh = NULL;
3519 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3520 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3523 req->offset = req->size = 0;
3524 DPRINTK("sisfb: Video RAM allocation failed\n");
3526 req->offset = poh->offset;
3527 req->size = poh->size;
3528 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3529 (poh->offset + ivideo->video_vbase));
3534 sis_malloc(struct sis_memreq *req)
3536 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3538 if(&ivideo->sisfb_heap == sisfb_heap)
3539 sis_int_malloc(ivideo, req);
3541 req->offset = req->size = 0;
3545 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3547 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3549 sis_int_malloc(ivideo, req);
3552 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3555 sis_int_free(struct sis_video_info *ivideo, u32 base)
3559 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3562 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3565 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3566 (unsigned int) base);
3573 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3575 sis_int_free(ivideo, base);
3579 sis_free_new(struct pci_dev *pdev, u32 base)
3581 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3583 sis_int_free(ivideo, base);
3586 /* --------------------- SetMode routines ------------------------- */
3589 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3593 /* Check if MMIO and engines are enabled,
3594 * and sync in case they are. Can't use
3595 * ivideo->accel here, as this might have
3596 * been changed before this is called.
3598 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3599 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3600 /* MMIO and 2D/3D engine enabled? */
3601 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3602 #ifdef CONFIG_FB_SIS_300
3603 if(ivideo->sisvga_engine == SIS_300_VGA) {
3604 /* Don't care about TurboQueue. It's
3605 * enough to know that the engines
3608 sisfb_syncaccel(ivideo);
3611 #ifdef CONFIG_FB_SIS_315
3612 if(ivideo->sisvga_engine == SIS_315_VGA) {
3613 /* Check that any queue mode is
3614 * enabled, and that the queue
3615 * is not in the state of "reset"
3617 inSISIDXREG(SISSR, 0x26, cr30);
3618 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3619 sisfb_syncaccel(ivideo);
3627 sisfb_pre_setmode(struct sis_video_info *ivideo)
3629 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3632 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3634 outSISIDXREG(SISSR, 0x05, 0x86);
3636 inSISIDXREG(SISCR, 0x31, cr31);
3640 cr33 = ivideo->rate_idx & 0x0F;
3642 #ifdef CONFIG_FB_SIS_315
3643 if(ivideo->sisvga_engine == SIS_315_VGA) {
3644 if(ivideo->chip >= SIS_661) {
3645 inSISIDXREG(SISCR, 0x38, cr38);
3646 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3649 inSISIDXREG(SISCR, tvregnum, cr38);
3650 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3654 #ifdef CONFIG_FB_SIS_300
3655 if(ivideo->sisvga_engine == SIS_300_VGA) {
3657 inSISIDXREG(SISCR, tvregnum, cr38);
3661 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3662 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3663 ivideo->curFSTN = ivideo->curDSTN = 0;
3665 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3668 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3669 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3670 #ifdef CONFIG_FB_SIS_315
3671 if(ivideo->chip >= SIS_661) {
3673 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3674 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3675 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3676 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3678 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3679 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3680 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3682 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3683 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3684 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3686 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3689 } else if((ivideo->vbflags & TV_HIVISION) &&
3690 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3691 if(ivideo->chip >= SIS_661) {
3697 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3700 ivideo->currentvbflags |= TV_HIVISION;
3701 } else if(ivideo->vbflags & TV_SCART) {
3702 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3705 ivideo->currentvbflags |= TV_SCART;
3707 if(ivideo->vbflags & TV_SVIDEO) {
3708 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3709 ivideo->currentvbflags |= TV_SVIDEO;
3711 if(ivideo->vbflags & TV_AVIDEO) {
3712 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3713 ivideo->currentvbflags |= TV_AVIDEO;
3716 cr31 |= SIS_DRIVER_MODE;
3718 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3719 if(ivideo->vbflags & TV_PAL) {
3720 cr31 |= 0x01; cr35 |= 0x01;
3721 ivideo->currentvbflags |= TV_PAL;
3722 if(ivideo->vbflags & TV_PALM) {
3723 cr38 |= 0x40; cr35 |= 0x04;
3724 ivideo->currentvbflags |= TV_PALM;
3725 } else if(ivideo->vbflags & TV_PALN) {
3726 cr38 |= 0x80; cr35 |= 0x08;
3727 ivideo->currentvbflags |= TV_PALN;
3730 cr31 &= ~0x01; cr35 &= ~0x01;
3731 ivideo->currentvbflags |= TV_NTSC;
3732 if(ivideo->vbflags & TV_NTSCJ) {
3733 cr38 |= 0x40; cr35 |= 0x02;
3734 ivideo->currentvbflags |= TV_NTSCJ;
3741 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3742 cr31 |= SIS_DRIVER_MODE;
3743 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3744 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3745 ivideo->curFSTN = ivideo->sisfb_fstn;
3746 ivideo->curDSTN = ivideo->sisfb_dstn;
3750 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3751 cr31 |= SIS_DRIVER_MODE;
3752 if(ivideo->sisfb_nocrt2rate) {
3753 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3755 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3759 default: /* disable CRT2 */
3761 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3764 outSISIDXREG(SISCR, 0x30, cr30);
3765 outSISIDXREG(SISCR, 0x33, cr33);
3767 if(ivideo->chip >= SIS_661) {
3768 #ifdef CONFIG_FB_SIS_315
3769 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3770 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3771 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3772 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3774 } else if(ivideo->chip != SIS_300) {
3775 outSISIDXREG(SISCR, tvregnum, cr38);
3777 outSISIDXREG(SISCR, 0x31, cr31);
3779 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3781 sisfb_check_engine_and_sync(ivideo);
3784 /* Fix SR11 for 661 and later */
3785 #ifdef CONFIG_FB_SIS_315
3787 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3791 if(ivideo->chip >= SIS_661) {
3792 inSISIDXREG(SISSR,0x11,tmpreg);
3794 inSISIDXREG(SISSR,0x3e,tmpreg);
3795 tmpreg = (tmpreg + 1) & 0xff;
3796 outSISIDXREG(SISSR,0x3e,tmpreg);
3797 inSISIDXREG(SISSR,0x11,tmpreg);
3800 andSISIDXREG(SISSR,0x11,0x0f);
3807 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3809 if(val > 32) val = 32;
3810 if(val < -32) val = -32;
3811 ivideo->tvxpos = val;
3813 if(ivideo->sisfblocked) return;
3814 if(!ivideo->modechanged) return;
3816 if(ivideo->currentvbflags & CRT2_TV) {
3818 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3820 int x = ivideo->tvx;
3822 switch(ivideo->chronteltype) {
3826 outSISIDXREG(SISSR,0x05,0x86);
3827 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3828 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3831 /* Not supported by hardware */
3835 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3837 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3838 unsigned short temp;
3840 p2_1f = ivideo->p2_1f;
3841 p2_20 = ivideo->p2_20;
3842 p2_2b = ivideo->p2_2b;
3843 p2_42 = ivideo->p2_42;
3844 p2_43 = ivideo->p2_43;
3846 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3848 p2_1f = temp & 0xff;
3849 p2_20 = (temp & 0xf00) >> 4;
3850 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3851 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3853 p2_43 = temp & 0xff;
3854 p2_42 = (temp & 0xf00) >> 4;
3855 outSISIDXREG(SISPART2,0x1f,p2_1f);
3856 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3857 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3858 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3859 outSISIDXREG(SISPART2,0x43,p2_43);
3865 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3867 if(val > 32) val = 32;
3868 if(val < -32) val = -32;
3869 ivideo->tvypos = val;
3871 if(ivideo->sisfblocked) return;
3872 if(!ivideo->modechanged) return;
3874 if(ivideo->currentvbflags & CRT2_TV) {
3876 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3878 int y = ivideo->tvy;
3880 switch(ivideo->chronteltype) {
3884 outSISIDXREG(SISSR,0x05,0x86);
3885 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3886 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3889 /* Not supported by hardware */
3893 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3897 p2_01 = ivideo->p2_01;
3898 p2_02 = ivideo->p2_02;
3902 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3903 while((p2_01 <= 0) || (p2_02 <= 0)) {
3908 outSISIDXREG(SISPART2,0x01,p2_01);
3909 outSISIDXREG(SISPART2,0x02,p2_02);
3915 sisfb_post_setmode(struct sis_video_info *ivideo)
3917 BOOLEAN crt1isoff = FALSE;
3918 BOOLEAN doit = TRUE;
3919 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3922 #ifdef CONFIG_FB_SIS_315
3926 outSISIDXREG(SISSR, 0x05, 0x86);
3928 #ifdef CONFIG_FB_SIS_315
3929 sisfb_fixup_SR11(ivideo);
3932 /* Now we actually HAVE changed the display mode */
3933 ivideo->modechanged = 1;
3935 /* We can't switch off CRT1 if bridge is in slave mode */
3936 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3937 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3939 ivideo->sisfb_crt1off = 0;
3941 #ifdef CONFIG_FB_SIS_300
3942 if(ivideo->sisvga_engine == SIS_300_VGA) {
3943 if((ivideo->sisfb_crt1off) && (doit)) {
3950 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3953 #ifdef CONFIG_FB_SIS_315
3954 if(ivideo->sisvga_engine == SIS_315_VGA) {
3955 if((ivideo->sisfb_crt1off) && (doit)) {
3964 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3965 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3970 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3971 ivideo->currentvbflags |= VB_SINGLE_MODE;
3973 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3974 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3975 ivideo->currentvbflags |= VB_MIRROR_MODE;
3977 ivideo->currentvbflags |= VB_SINGLE_MODE;
3981 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3983 if(ivideo->currentvbflags & CRT2_TV) {
3984 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3985 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3986 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3987 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3988 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3989 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3990 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3991 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3992 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3993 if(ivideo->chronteltype == 1) {
3994 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3995 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3996 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3997 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
4002 if(ivideo->tvxpos) {
4003 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
4005 if(ivideo->tvypos) {
4006 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
4009 /* Eventually sync engines */
4010 sisfb_check_engine_and_sync(ivideo);
4012 /* (Re-)Initialize chip engines */
4014 sisfb_engine_init(ivideo);
4016 ivideo->engineok = 0;
4021 sisfb_reset_mode(struct sis_video_info *ivideo)
4023 if(sisfb_set_mode(ivideo, 0))
4026 sisfb_set_pitch(ivideo);
4027 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4028 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
4034 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4038 switch(sisfb_command->sisfb_cmd) {
4039 case SISFB_CMD_GETVBFLAGS:
4040 if(!ivideo->modechanged) {
4041 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4043 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4044 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4045 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
4048 case SISFB_CMD_SWITCHCRT1:
4049 /* arg[0]: 0 = off, 1 = on, 99 = query */
4050 if(!ivideo->modechanged) {
4051 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4052 } else if(sisfb_command->sisfb_arg[0] == 99) {
4054 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4055 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4056 } else if(ivideo->sisfblocked) {
4057 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4058 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4059 (sisfb_command->sisfb_arg[0] == 0)) {
4060 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4062 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4063 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4064 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4065 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4066 ivideo->sisfb_crt1off = mycrt1off;
4067 if(sisfb_reset_mode(ivideo)) {
4068 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
4071 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4076 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4077 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4078 sisfb_command->sisfb_cmd);
4083 SISINITSTATIC int __init
4084 sisfb_setup(char *options)
4088 sisfb_setdefaultparms();
4090 if(!options || !(*options))
4093 while((this_opt = strsep(&options, ",")) != NULL) {
4095 if(!(*this_opt)) continue;
4097 if(!strnicmp(this_opt, "off", 3)) {
4099 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4100 /* Need to check crt2 type first for fstn/dstn */
4101 sisfb_search_crt2type(this_opt + 14);
4102 } else if(!strnicmp(this_opt, "tvmode:",7)) {
4103 sisfb_search_tvstd(this_opt + 7);
4104 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4105 sisfb_search_tvstd(this_opt + 11);
4106 } else if(!strnicmp(this_opt, "mode:", 5)) {
4107 sisfb_search_mode(this_opt + 5, FALSE);
4108 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4109 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4110 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4111 } else if(!strnicmp(this_opt, "inverse", 7)) {
4113 /* fb_invert_cmaps(); */
4114 } else if(!strnicmp(this_opt, "font:", 5)) {
4115 if(strlen(this_opt + 5) < 40) {
4116 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4117 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4120 } else if(!strnicmp(this_opt, "rate:", 5)) {
4121 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4122 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4123 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4124 } else if(!strnicmp(this_opt, "mem:",4)) {
4125 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4126 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4127 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4128 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4129 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4130 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4132 } else if(!strnicmp(this_opt, "accel", 5)) {
4134 } else if(!strnicmp(this_opt, "noypan", 6)) {
4136 } else if(!strnicmp(this_opt, "ypan", 4)) {
4138 } else if(!strnicmp(this_opt, "nomax", 5)) {
4140 } else if(!strnicmp(this_opt, "max", 3)) {
4142 } else if(!strnicmp(this_opt, "userom:", 7)) {
4143 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4144 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4145 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4146 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4147 sisfb_nocrt2rate = 1;
4148 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4149 unsigned long temp = 2;
4150 temp = simple_strtoul(this_opt + 9, NULL, 0);
4151 if((temp == 0) || (temp == 1)) {
4152 sisfb_scalelcd = temp ^ 1;
4154 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4156 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4157 if((temp >= -32) && (temp <= 32)) {
4158 sisfb_tvxposoffset = temp;
4160 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4162 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4163 if((temp >= -32) && (temp <= 32)) {
4164 sisfb_tvyposoffset = temp;
4166 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4167 sisfb_search_specialtiming(this_opt + 14);
4168 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4170 temp = simple_strtoul(this_opt + 7, NULL, 0);
4171 if((temp >= 0) && (temp <= 3)) {
4172 sisfb_lvdshl = temp;
4174 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4175 sisfb_search_mode(this_opt, TRUE);
4176 #if !defined(__i386__) && !defined(__x86_64__)
4177 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4178 sisfb_resetcard = 1;
4179 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4180 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4183 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4192 static int __devinit
4193 sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4198 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4201 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4202 if(romptr > (0x10000 - 8))
4205 rom = rom_base + romptr;
4207 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4208 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4211 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4214 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4220 static unsigned char * __devinit
4221 sisfb_find_rom(struct pci_dev *pdev)
4223 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4224 SIS_IOTYPE1 *rom_base;
4225 unsigned char *myrombase = NULL;
4227 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4230 /* First, try the official pci ROM functions (except
4231 * on integrated chipsets which have no ROM).
4234 if(!ivideo->nbridge) {
4236 if((rom_base = pci_map_rom(pdev, &romsize))) {
4238 if(sisfb_check_rom(rom_base, ivideo)) {
4240 if((myrombase = vmalloc(65536))) {
4242 /* Work around bug in pci/rom.c: Folks forgot to check
4243 * whether the size retrieved from the BIOS image eventually
4244 * is larger than the mapped size
4246 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4247 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4249 memcpy_fromio(myrombase, rom_base,
4250 (romsize > 65536) ? 65536 : romsize);
4253 pci_unmap_rom(pdev, rom_base);
4257 if(myrombase) return myrombase;
4260 /* Otherwise do it the conventional way. */
4262 #if defined(__i386__) || defined(__x86_64__)
4264 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4266 rom_base = ioremap(temp, 65536);
4270 if(!sisfb_check_rom(rom_base, ivideo)) {
4275 if((myrombase = vmalloc(65536)))
4276 memcpy_fromio(myrombase, rom_base, 65536);
4285 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4286 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4287 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4289 rom_base = ioremap(ivideo->video_base, 65536);
4291 if(sisfb_check_rom(rom_base, ivideo)) {
4292 if((myrombase = vmalloc(65536)))
4293 memcpy_fromio(myrombase, rom_base, 65536);
4298 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4305 static void __devinit
4306 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4309 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4311 if(!ivideo->video_vbase) {
4313 "sisfb: Unable to map maximum video RAM for size detection\n");
4315 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4317 if((*mapsize) < (min << 20))
4320 if(ivideo->video_vbase) {
4322 "sisfb: Video RAM size detection limited to %dMB\n",
4323 (int)((*mapsize) >> 20));
4328 #ifdef CONFIG_FB_SIS_300
4329 static int __devinit
4330 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4332 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4333 unsigned short temp;
4337 andSISIDXREG(SISSR, 0x15, 0xFB);
4338 orSISIDXREG(SISSR, 0x15, 0x04);
4339 outSISIDXREG(SISSR, 0x13, 0x00);
4340 outSISIDXREG(SISSR, 0x14, 0xBF);
4342 for(i = 0; i < 2; i++) {
4344 for(j = 0; j < 4; j++) {
4345 writew(temp, FBAddress);
4346 if(readw(FBAddress) == temp)
4348 orSISIDXREG(SISSR, 0x3c, 0x01);
4349 inSISIDXREG(SISSR, 0x05, reg);
4350 inSISIDXREG(SISSR, 0x05, reg);
4351 andSISIDXREG(SISSR, 0x3c, 0xfe);
4352 inSISIDXREG(SISSR, 0x05, reg);
4353 inSISIDXREG(SISSR, 0x05, reg);
4358 writel(0x01234567L, FBAddress);
4359 writel(0x456789ABL, (FBAddress + 4));
4360 writel(0x89ABCDEFL, (FBAddress + 8));
4361 writel(0xCDEF0123L, (FBAddress + 12));
4363 inSISIDXREG(SISSR, 0x3b, reg);
4365 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4366 return 4; /* Channel A 128bit */
4369 if(readl((FBAddress + 4)) == 0x456789ABL)
4370 return 2; /* Channel B 64bit */
4372 return 1; /* 32bit */
4375 static int __devinit
4376 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4377 int PseudoRankCapacity, int PseudoAdrPinCount,
4378 unsigned int mapsize)
4380 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4381 unsigned short sr14;
4382 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4383 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4384 static const unsigned short SiS_DRAMType[17][5] = {
4385 {0x0C,0x0A,0x02,0x40,0x39},
4386 {0x0D,0x0A,0x01,0x40,0x48},
4387 {0x0C,0x09,0x02,0x20,0x35},
4388 {0x0D,0x09,0x01,0x20,0x44},
4389 {0x0C,0x08,0x02,0x10,0x31},
4390 {0x0D,0x08,0x01,0x10,0x40},
4391 {0x0C,0x0A,0x01,0x20,0x34},
4392 {0x0C,0x09,0x01,0x08,0x32},
4393 {0x0B,0x08,0x02,0x08,0x21},
4394 {0x0C,0x08,0x01,0x08,0x30},
4395 {0x0A,0x08,0x02,0x04,0x11},
4396 {0x0B,0x0A,0x01,0x10,0x28},
4397 {0x09,0x08,0x02,0x02,0x01},
4398 {0x0B,0x09,0x01,0x08,0x24},
4399 {0x0B,0x08,0x01,0x04,0x20},
4400 {0x0A,0x08,0x01,0x02,0x10},
4401 {0x09,0x08,0x01,0x01,0x00}
4404 for(k = 0; k <= 16; k++) {
4406 RankCapacity = buswidth * SiS_DRAMType[k][3];
4408 if(RankCapacity != PseudoRankCapacity)
4411 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4414 BankNumHigh = RankCapacity * 16 * iteration - 1;
4415 if(iteration == 3) { /* Rank No */
4416 BankNumMid = RankCapacity * 16 - 1;
4418 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4421 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4422 PhysicalAdrHigh = BankNumHigh;
4423 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4424 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4426 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4427 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4428 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4429 if(buswidth == 4) sr14 |= 0x80;
4430 else if(buswidth == 2) sr14 |= 0x40;
4431 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4432 outSISIDXREG(SISSR, 0x14, sr14);
4437 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4438 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4439 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4440 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4444 writew(((unsigned short)PhysicalAdrHigh),
4445 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4446 writew(((unsigned short)BankNumMid),
4447 (FBAddr + BankNumMid + PhysicalAdrHigh));
4448 writew(((unsigned short)PhysicalAdrHalfPage),
4449 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4450 writew(((unsigned short)PhysicalAdrOtherPage),
4451 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4454 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4461 static void __devinit
4462 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4464 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4466 int PseudoRankCapacity, PseudoAdrPinCount;
4468 buswidth = sisfb_post_300_buswidth(ivideo);
4470 for(i = 6; i >= 0; i--) {
4471 PseudoRankCapacity = 1 << i;
4472 for(j = 4; j >= 1; j--) {
4473 PseudoAdrPinCount = 15 - j;
4474 if((PseudoRankCapacity * j) <= 64) {
4475 if(sisfb_post_300_rwtest(ivideo,
4487 static void __devinit
4488 sisfb_post_sis300(struct pci_dev *pdev)
4490 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4491 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4492 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4493 u16 index, rindex, memtype = 0;
4494 unsigned int mapsize;
4496 if(!ivideo->SiS_Pr.UseROM)
4499 outSISIDXREG(SISSR, 0x05, 0x86);
4502 if(bios[0x52] & 0x80) {
4503 memtype = bios[0x52];
4505 inSISIDXREG(SISSR, 0x3a, memtype);
4510 v3 = 0x80; v6 = 0x80;
4511 if(ivideo->revision_id <= 0x13) {
4512 v1 = 0x44; v2 = 0x42;
4513 v4 = 0x44; v5 = 0x42;
4515 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4516 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4518 index = memtype * 5;
4519 rindex = index + 0x54;
4520 v1 = bios[rindex++];
4521 v2 = bios[rindex++];
4522 v3 = bios[rindex++];
4523 rindex = index + 0x7c;
4524 v4 = bios[rindex++];
4525 v5 = bios[rindex++];
4526 v6 = bios[rindex++];
4529 outSISIDXREG(SISSR, 0x28, v1);
4530 outSISIDXREG(SISSR, 0x29, v2);
4531 outSISIDXREG(SISSR, 0x2a, v3);
4532 outSISIDXREG(SISSR, 0x2e, v4);
4533 outSISIDXREG(SISSR, 0x2f, v5);
4534 outSISIDXREG(SISSR, 0x30, v6);
4539 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4541 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4543 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4544 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4548 v2 = bios[memtype + 8];
4549 v3 = bios[memtype + 16];
4550 v4 = bios[memtype + 24];
4551 v5 = bios[memtype + 32];
4552 v6 = bios[memtype + 40];
4553 v7 = bios[memtype + 48];
4554 v8 = bios[memtype + 56];
4556 if(ivideo->revision_id >= 0x80)
4558 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4559 outSISIDXREG(SISSR, 0x16, v2);
4560 outSISIDXREG(SISSR, 0x17, v3);
4561 outSISIDXREG(SISSR, 0x18, v4);
4562 outSISIDXREG(SISSR, 0x19, v5);
4563 outSISIDXREG(SISSR, 0x1a, v6);
4564 outSISIDXREG(SISSR, 0x1b, v7);
4565 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4566 andSISIDXREG(SISSR, 0x15 ,0xfb);
4567 orSISIDXREG(SISSR, 0x15, 0x04);
4569 if(bios[0x53] & 0x02) {
4570 orSISIDXREG(SISSR, 0x19, 0x20);
4573 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4574 if(ivideo->revision_id >= 0x80)
4576 outSISIDXREG(SISSR, 0x1f, v1);
4577 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4578 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4584 outSISIDXREG(SISSR, 0x23, v1);
4585 outSISIDXREG(SISSR, 0x24, v2);
4586 outSISIDXREG(SISSR, 0x25, v3);
4587 outSISIDXREG(SISSR, 0x21, 0x84);
4588 outSISIDXREG(SISSR, 0x22, 0x00);
4589 outSISIDXREG(SISCR, 0x37, 0x00);
4590 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4591 outSISIDXREG(SISPART1, 0x00, 0x00);
4592 v1 = 0x40; v2 = 0x11;
4597 outSISIDXREG(SISPART1, 0x02, v1);
4599 if(ivideo->revision_id >= 0x80)
4602 inSISIDXREG(SISPART4, 0x00, reg);
4603 if((reg == 1) || (reg == 2)) {
4604 outSISIDXREG(SISCR, 0x37, 0x02);
4605 outSISIDXREG(SISPART2, 0x00, 0x1c);
4606 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4607 if(ivideo->SiS_Pr.UseROM) {
4612 outSISIDXREG(SISPART4, 0x0d, v4);
4613 outSISIDXREG(SISPART4, 0x0e, v5);
4614 outSISIDXREG(SISPART4, 0x10, v6);
4615 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4616 inSISIDXREG(SISPART4, 0x01, reg);
4618 inSISIDXREG(SISPART4, 0x23, reg);
4621 outSISIDXREG(SISPART4, 0x23, reg);
4626 outSISIDXREG(SISSR, 0x32, v2);
4628 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4630 inSISIDXREG(SISSR, 0x16, reg);
4632 outSISIDXREG(SISCR, 0x35, reg);
4633 outSISIDXREG(SISCR, 0x83, 0x00);
4634 #if !defined(__i386__) && !defined(__x86_64__)
4635 if(sisfb_videoram) {
4636 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4637 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4638 outSISIDXREG(SISSR, 0x14, reg);
4641 /* Need to map max FB size for finding out about RAM size */
4643 sisfb_post_map_vram(ivideo, &mapsize, 4);
4645 if(ivideo->video_vbase) {
4646 sisfb_post_300_ramsize(pdev, mapsize);
4647 iounmap(ivideo->video_vbase);
4650 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4651 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4652 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4654 #if !defined(__i386__) && !defined(__x86_64__)
4661 inSISIDXREG(SISSR, 0x3a, reg);
4662 if((reg & 0x30) == 0x30) {
4663 v1 = 0x04; /* PCI */
4666 v1 = 0x14; /* AGP */
4670 outSISIDXREG(SISSR, 0x21, v1);
4671 outSISIDXREG(SISSR, 0x22, v2);
4674 sisfb_sense_crt1(ivideo);
4676 /* Set default mode, don't clear screen */
4677 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4678 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4679 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4680 ivideo->curFSTN = ivideo->curDSTN = 0;
4681 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4682 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4684 outSISIDXREG(SISSR, 0x05, 0x86);
4687 orSISIDXREG(SISSR, 0x01, 0x20);
4689 /* Save mode number in CR34 */
4690 outSISIDXREG(SISCR, 0x34, 0x2e);
4692 /* Let everyone know what the current mode is */
4693 ivideo->modeprechange = 0x2e;
4697 #ifdef CONFIG_FB_SIS_315
4699 static void __devinit
4700 sisfb_post_sis315330(struct pci_dev *pdev)
4706 static void __devinit
4707 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4712 for(i = 0; i <= (delay * 10 * 36); i++) {
4713 inSISIDXREG(SISSR, 0x05, reg);
4718 static int __devinit
4719 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4720 unsigned short pcivendor)
4722 struct pci_dev *pdev = NULL;
4723 unsigned short temp;
4726 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4727 temp = pdev->vendor;
4728 SIS_PCI_PUT_DEVICE(pdev);
4729 if(temp == pcivendor) {
4738 static int __devinit
4739 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4740 unsigned int enda, unsigned int mapsize)
4745 writel(0, ivideo->video_vbase);
4747 for(i = starta; i <= enda; i++) {
4750 writel(pos, ivideo->video_vbase + pos);
4753 sisfb_post_xgi_delay(ivideo, 150);
4755 if(readl(ivideo->video_vbase) != 0)
4758 for(i = starta; i <= enda; i++) {
4761 if(readl(ivideo->video_vbase + pos) != pos)
4770 static void __devinit
4771 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4773 unsigned int buswidth, ranksize, channelab, mapsize;
4776 static const u8 dramsr13[12 * 5] = {
4777 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4778 0x02, 0x0e, 0x0a, 0x40, 0x59,
4779 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4780 0x02, 0x0e, 0x09, 0x20, 0x55,
4781 0x02, 0x0d, 0x0a, 0x20, 0x49,
4782 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4783 0x02, 0x0e, 0x08, 0x10, 0x51,
4784 0x02, 0x0d, 0x09, 0x10, 0x45,
4785 0x02, 0x0c, 0x0a, 0x10, 0x39,
4786 0x02, 0x0d, 0x08, 0x08, 0x41,
4787 0x02, 0x0c, 0x09, 0x08, 0x35,
4788 0x02, 0x0c, 0x08, 0x04, 0x31
4790 static const u8 dramsr13_4[4 * 5] = {
4791 0x02, 0x0d, 0x09, 0x40, 0x45,
4792 0x02, 0x0c, 0x09, 0x20, 0x35,
4793 0x02, 0x0c, 0x08, 0x10, 0x31,
4794 0x02, 0x0b, 0x08, 0x08, 0x21
4797 /* Enable linear mode, disable 0xa0000 address decoding */
4798 /* We disable a0000 address decoding, because
4799 * - if running on x86, if the card is disabled, it means
4800 * that another card is in the system. We don't want
4801 * to interphere with that primary card's textmode.
4802 * - if running on non-x86, there usually is no VGA window
4805 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4807 /* Need to map max FB size for finding out about RAM size */
4808 mapsize = 256 << 20;
4809 sisfb_post_map_vram(ivideo, &mapsize, 32);
4811 if(!ivideo->video_vbase) {
4812 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4813 outSISIDXREG(SISSR, 0x13, 0x35);
4814 outSISIDXREG(SISSR, 0x14, 0x41);
4819 /* Non-interleaving */
4820 outSISIDXREG(SISSR, 0x15, 0x00);
4822 outSISIDXREG(SISSR, 0x1c, 0x00);
4824 if(ivideo->chip == XGI_20) {
4827 inSISIDXREG(SISCR, 0x97, reg);
4828 if(!(reg & 0x01)) { /* Single 32/16 */
4830 outSISIDXREG(SISSR, 0x13, 0xb1);
4831 outSISIDXREG(SISSR, 0x14, 0x52);
4832 sisfb_post_xgi_delay(ivideo, 1);
4834 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4837 outSISIDXREG(SISSR, 0x13, 0x31);
4838 outSISIDXREG(SISSR, 0x14, 0x42);
4839 sisfb_post_xgi_delay(ivideo, 1);
4840 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4844 outSISIDXREG(SISSR, 0x13, 0xb1);
4845 outSISIDXREG(SISSR, 0x14, 0x41);
4846 sisfb_post_xgi_delay(ivideo, 1);
4848 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4851 outSISIDXREG(SISSR, 0x13, 0x31);
4852 } else { /* Dual 16/8 */
4854 outSISIDXREG(SISSR, 0x13, 0xb1);
4855 outSISIDXREG(SISSR, 0x14, 0x41);
4856 sisfb_post_xgi_delay(ivideo, 1);
4858 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4861 outSISIDXREG(SISSR, 0x13, 0x31);
4862 outSISIDXREG(SISSR, 0x14, 0x31);
4863 sisfb_post_xgi_delay(ivideo, 1);
4864 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4868 outSISIDXREG(SISSR, 0x13, 0xb1);
4869 outSISIDXREG(SISSR, 0x14, 0x30);
4870 sisfb_post_xgi_delay(ivideo, 1);
4872 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4875 outSISIDXREG(SISSR, 0x13, 0x31);
4878 } else { /* XGI_40 */
4880 inSISIDXREG(SISCR, 0x97, reg);
4882 inSISIDXREG(SISSR, 0x39, reg);
4886 if(reg & 0x01) { /* DDRII */
4888 if(ivideo->revision_id == 2) {
4890 outSISIDXREG(SISSR, 0x13, 0xa1);
4891 outSISIDXREG(SISSR, 0x14, 0x44);
4893 sisfb_post_xgi_delay(ivideo, 1);
4894 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4897 outSISIDXREG(SISSR, 0x13, 0x21);
4898 outSISIDXREG(SISSR, 0x14, 0x34);
4899 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4903 outSISIDXREG(SISSR, 0x13, 0xa1);
4904 outSISIDXREG(SISSR, 0x14, 0x40);
4906 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4909 outSISIDXREG(SISSR, 0x13, 0x21);
4910 outSISIDXREG(SISSR, 0x14, 0x30);
4913 outSISIDXREG(SISSR, 0x13, 0xa1);
4914 outSISIDXREG(SISSR, 0x14, 0x4c);
4916 sisfb_post_xgi_delay(ivideo, 1);
4917 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4921 outSISIDXREG(SISSR, 0x14, 0x48);
4922 sisfb_post_xgi_delay(ivideo, 1);
4924 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4927 outSISIDXREG(SISSR, 0x13, 0x21);
4928 outSISIDXREG(SISSR, 0x14, 0x3c);
4931 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4935 outSISIDXREG(SISSR, 0x14, 0x38);
4939 sisfb_post_xgi_delay(ivideo, 1);
4944 if(ivideo->revision_id == 2) {
4946 outSISIDXREG(SISSR, 0x13, 0xa1);
4947 outSISIDXREG(SISSR, 0x14, 0x52);
4948 sisfb_post_xgi_delay(ivideo, 1);
4950 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4953 outSISIDXREG(SISSR, 0x13, 0x21);
4954 outSISIDXREG(SISSR, 0x14, 0x42);
4957 outSISIDXREG(SISSR, 0x13, 0xa1);
4958 outSISIDXREG(SISSR, 0x14, 0x5a);
4959 sisfb_post_xgi_delay(ivideo, 1);
4961 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4964 outSISIDXREG(SISSR, 0x13, 0x21);
4965 outSISIDXREG(SISSR, 0x14, 0x4a);
4967 sisfb_post_xgi_delay(ivideo, 1);
4973 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4974 sisfb_post_xgi_delay(ivideo, 1);
4976 j = (ivideo->chip == XGI_20) ? 5 : 9;
4977 k = (ivideo->chip == XGI_20) ? 12 : 4;
4979 for(i = 0; i < k; i++) {
4981 reg = (ivideo->chip == XGI_20) ?
4982 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4983 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4984 sisfb_post_xgi_delay(ivideo, 50);
4986 ranksize = (ivideo->chip == XGI_20) ?
4987 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4989 inSISIDXREG(SISSR, 0x13, reg);
4990 if(reg & 0x80) ranksize <<= 1;
4992 if(ivideo->chip == XGI_20) {
4993 if(buswidth == 16) ranksize <<= 1;
4994 else if(buswidth == 32) ranksize <<= 2;
4996 if(buswidth == 64) ranksize <<= 1;
5002 if((ranksize * l) <= 256) {
5003 while((ranksize >>= 1)) reg += 0x10;
5008 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
5009 sisfb_post_xgi_delay(ivideo, 1);
5011 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5015 iounmap(ivideo->video_vbase);
5018 static void __devinit
5019 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5023 static const u8 cs90[8 * 3] = {
5033 static const u8 csb8[8 * 3] = {
5047 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5048 if(ivideo->haveXGIROM) {
5049 v1 = ivideo->bios_abase[0x90 + index];
5050 v2 = ivideo->bios_abase[0x90 + index + 1];
5051 v3 = ivideo->bios_abase[0x90 + index + 2];
5053 outSISIDXREG(SISSR, 0x28, v1);
5054 outSISIDXREG(SISSR, 0x29, v2);
5055 outSISIDXREG(SISSR, 0x2a, v3);
5056 sisfb_post_xgi_delay(ivideo, 0x43);
5057 sisfb_post_xgi_delay(ivideo, 0x43);
5058 sisfb_post_xgi_delay(ivideo, 0x43);
5060 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5061 if(ivideo->haveXGIROM) {
5062 v1 = ivideo->bios_abase[0xb8 + index];
5063 v2 = ivideo->bios_abase[0xb8 + index + 1];
5064 v3 = ivideo->bios_abase[0xb8 + index + 2];
5066 outSISIDXREG(SISSR, 0x2e, v1);
5067 outSISIDXREG(SISSR, 0x2f, v2);
5068 outSISIDXREG(SISSR, 0x30, v3);
5069 sisfb_post_xgi_delay(ivideo, 0x43);
5070 sisfb_post_xgi_delay(ivideo, 0x43);
5071 sisfb_post_xgi_delay(ivideo, 0x43);
5074 static int __devinit
5075 sisfb_post_xgi(struct pci_dev *pdev)
5077 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5078 unsigned char *bios = ivideo->bios_abase;
5079 struct pci_dev *mypdev = NULL;
5080 const u8 *ptr, *ptr2;
5081 u8 v1, v2, v3, v4, v5, reg, ramtype;
5082 u32 rega, regb, regd;
5084 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5085 static const u8 cs76[2] = { 0xa3, 0xfb };
5086 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5087 static const u8 cs158[8] = {
5088 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5090 static const u8 cs160[8] = {
5091 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5093 static const u8 cs168[8] = {
5094 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5096 static const u8 cs128[3 * 8] = {
5097 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5098 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5099 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5101 static const u8 cs148[2 * 8] = {
5102 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5105 static const u8 cs31a[8 * 4] = {
5106 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5107 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5111 static const u8 cs33a[8 * 4] = {
5112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5117 static const u8 cs45a[8 * 2] = {
5118 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5121 static const u8 cs170[7 * 8] = {
5122 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5123 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5124 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5125 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5126 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5127 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5128 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5130 static const u8 cs1a8[3 * 8] = {
5131 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5132 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5135 static const u8 cs100[2 * 8] = {
5136 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5137 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5141 reg = inSISREG(SISVGAENABLE) | 0x01;
5142 outSISREG(SISVGAENABLE, reg);
5145 reg = inSISREG(SISMISCR) | 0x01;
5146 outSISREG(SISMISCW, reg);
5149 outSISIDXREG(SISSR, 0x05, 0x86);
5150 inSISIDXREG(SISSR, 0x05, reg);
5154 /* Clear some regs */
5155 for(i = 0; i < 0x22; i++) {
5156 if(0x06 + i == 0x20) continue;
5157 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5159 for(i = 0; i < 0x0b; i++) {
5160 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5162 for(i = 0; i < 0x10; i++) {
5163 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5167 if(ivideo->haveXGIROM) {
5168 ptr = (const u8 *)&bios[0x78];
5170 for(i = 0; i < 3; i++) {
5171 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5175 if(ivideo->haveXGIROM) {
5176 ptr = (const u8 *)&bios[0x76];
5178 for(i = 0; i < 2; i++) {
5179 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5182 v1 = 0x18; v2 = 0x00;
5183 if(ivideo->haveXGIROM) {
5187 outSISIDXREG(SISSR, 0x07, v1);
5188 outSISIDXREG(SISSR, 0x11, 0x0f);
5189 outSISIDXREG(SISSR, 0x1f, v2);
5190 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5191 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5192 outSISIDXREG(SISSR, 0x27, 0x74);
5195 if(ivideo->haveXGIROM) {
5196 ptr = (const u8 *)&bios[0x7b];
5198 for(i = 0; i < 3; i++) {
5199 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5202 if(ivideo->chip == XGI_40) {
5203 if(ivideo->revision_id == 2) {
5204 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5206 outSISIDXREG(SISCR, 0x7d, 0xfe);
5207 outSISIDXREG(SISCR, 0x7e, 0x0f);
5209 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5210 andSISIDXREG(SISCR, 0x58, 0xd7);
5211 inSISIDXREG(SISCR, 0xcb, reg);
5213 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5217 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5218 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5220 if(ivideo->chip == XGI_20) {
5221 outSISIDXREG(SISSR, 0x36, 0x70);
5223 outSISIDXREG(SISVID, 0x00, 0x86);
5224 outSISIDXREG(SISVID, 0x32, 0x00);
5225 outSISIDXREG(SISVID, 0x30, 0x00);
5226 outSISIDXREG(SISVID, 0x32, 0x01);
5227 outSISIDXREG(SISVID, 0x30, 0x00);
5228 andSISIDXREG(SISVID, 0x2f, 0xdf);
5229 andSISIDXREG(SISCAP, 0x00, 0x3f);
5231 outSISIDXREG(SISPART1, 0x2f, 0x01);
5232 outSISIDXREG(SISPART1, 0x00, 0x00);
5233 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5234 outSISIDXREG(SISPART1, 0x2e, 0x08);
5235 andSISIDXREG(SISPART1, 0x35, 0x7f);
5236 andSISIDXREG(SISPART1, 0x50, 0xfe);
5238 inSISIDXREG(SISPART4, 0x00, reg);
5239 if(reg == 1 || reg == 2) {
5240 outSISIDXREG(SISPART2, 0x00, 0x1c);
5241 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5242 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5243 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5244 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5246 inSISIDXREG(SISPART4, 0x01, reg);
5247 if((reg & 0xf0) >= 0xb0) {
5248 inSISIDXREG(SISPART4, 0x23, reg);
5249 if(reg & 0x20) reg |= 0x40;
5250 outSISIDXREG(SISPART4, 0x23, reg);
5251 reg = (reg & 0x20) ? 0x02 : 0x00;
5252 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5258 inSISIDXREG(SISSR, 0x3b, reg);
5260 inSISIDXREG(SISSR, 0x3a, reg);
5261 v2 = (reg & 0x30) >> 3;
5262 if(!(v2 & 0x04)) v2 ^= 0x02;
5263 inSISIDXREG(SISSR, 0x39, reg);
5264 if(reg & 0x80) v2 |= 0x80;
5267 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5268 SIS_PCI_PUT_DEVICE(mypdev);
5269 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5274 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5276 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5278 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5280 pci_read_config_dword(mypdev, 0x94, ®d);
5282 pci_write_config_dword(mypdev, 0x94, regd);
5284 SIS_PCI_PUT_DEVICE(mypdev);
5285 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5287 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5288 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5289 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5290 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5291 if((v2 & 0x06) == 4)
5296 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5298 outSISIDXREG(SISSR, 0x22, v1);
5300 if(ivideo->revision_id == 2) {
5301 inSISIDXREG(SISSR, 0x3b, v1);
5302 inSISIDXREG(SISSR, 0x3a, v2);
5303 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5304 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5305 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5307 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5308 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5312 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5313 SIS_PCI_PUT_DEVICE(mypdev);
5318 inSISIDXREG(SISSR, 0x3b, reg);
5319 inSISIDXREG(SISCR, 0x5f, v2);
5320 if((!(reg & 0x02)) && (v2 & 0x0e))
5322 outSISIDXREG(SISSR, 0x27, v1);
5324 if(bios[0x64] & 0x01) {
5325 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5329 pci_read_config_dword(pdev, 0x50, ®d);
5330 regd = (regd >> 20) & 0x0f;
5333 orSISIDXREG(SISCR, 0x5f, 0x08);
5335 outSISIDXREG(SISCR, 0x48, v1);
5337 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5338 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5339 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5340 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5341 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5342 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5343 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5344 outSISIDXREG(SISCR, 0x74, 0xd0);
5345 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5346 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5347 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5349 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5351 SIS_PCI_PUT_DEVICE(mypdev);
5353 outSISIDXREG(SISCR, 0x77, v1);
5361 if(ivideo->haveXGIROM) {
5362 v1 = bios[0x140 + regb];
5364 outSISIDXREG(SISCR, 0x6d, v1);
5367 if(ivideo->haveXGIROM) {
5368 ptr = (const u8 *)&bios[0x128];
5370 for(i = 0, j = 0; i < 3; i++, j += 8) {
5371 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5376 if(ivideo->haveXGIROM) {
5377 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5378 ptr = (const u8 *)&bios[index];
5379 ptr2 = (const u8 *)&bios[index + 0x20];
5381 for(i = 0; i < 2; i++) {
5383 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5386 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5390 for(j = 0; j < 16; j++) {
5392 if(regd & 0x01) reg |= 0x04;
5393 if(regd & 0x02) reg |= 0x08;
5395 outSISIDXREG(SISCR, rega, reg);
5396 inSISIDXREG(SISCR, rega, reg);
5397 inSISIDXREG(SISCR, rega, reg);
5402 andSISIDXREG(SISCR, 0x6e, 0xfc);
5405 if(ivideo->haveXGIROM) {
5406 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5407 ptr = (const u8 *)&bios[index];
5409 for(i = 0; i < 4; i++) {
5410 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5412 for(j = 0; j < 2; j++) {
5415 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5419 for(k = 0; k < 16; k++) {
5421 if(regd & 0x01) reg |= 0x01;
5422 if(regd & 0x02) reg |= 0x02;
5424 outSISIDXREG(SISCR, 0x6f, reg);
5425 inSISIDXREG(SISCR, 0x6f, reg);
5426 inSISIDXREG(SISCR, 0x6f, reg);
5433 if(ivideo->haveXGIROM) {
5434 ptr = (const u8 *)&bios[0x148];
5436 for(i = 0, j = 0; i < 2; i++, j += 8) {
5437 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5440 andSISIDXREG(SISCR, 0x89, 0x8f);
5443 if(ivideo->haveXGIROM) {
5444 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5445 ptr = (const u8 *)&bios[index];
5447 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5449 for(i = 0; i < 5; i++) {
5451 if(regd & 0x01) reg |= 0x01;
5452 if(regd & 0x02) reg |= 0x02;
5454 outSISIDXREG(SISCR, 0x89, reg);
5455 inSISIDXREG(SISCR, 0x89, reg);
5456 inSISIDXREG(SISCR, 0x89, reg);
5460 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5461 if(ivideo->haveXGIROM) {
5462 v1 = bios[0x118 + regb];
5463 v2 = bios[0xf8 + regb];
5464 v3 = bios[0x120 + regb];
5467 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5468 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5469 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5470 outSISIDXREG(SISCR, 0x41, v2);
5473 if(ivideo->haveXGIROM) {
5474 ptr = (const u8 *)&bios[0x170];
5476 for(i = 0, j = 0; i < 7; i++, j += 8) {
5477 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5480 outSISIDXREG(SISCR, 0x59, v3);
5483 if(ivideo->haveXGIROM) {
5484 ptr = (const u8 *)&bios[0x1a8];
5486 for(i = 0, j = 0; i < 3; i++, j += 8) {
5487 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5491 if(ivideo->haveXGIROM) {
5492 ptr = (const u8 *)&bios[0x100];
5494 for(i = 0, j = 0; i < 2; i++, j += 8) {
5495 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5498 outSISIDXREG(SISCR, 0xcf, v4);
5500 outSISIDXREG(SISCR, 0x83, 0x09);
5501 outSISIDXREG(SISCR, 0x87, 0x00);
5503 if(ivideo->chip == XGI_40) {
5504 if( (ivideo->revision_id == 1) ||
5505 (ivideo->revision_id == 2) ) {
5506 outSISIDXREG(SISCR, 0x8c, 0x87);
5510 outSISIDXREG(SISSR, 0x17, 0x00);
5511 outSISIDXREG(SISSR, 0x1a, 0x87);
5513 if(ivideo->chip == XGI_20) {
5514 outSISIDXREG(SISSR, 0x15, 0x00);
5515 outSISIDXREG(SISSR, 0x1c, 0x00);
5518 ramtype = 0x00; v1 = 0x10;
5519 if(ivideo->haveXGIROM) {
5520 ramtype = bios[0x62];
5523 if(!(ramtype & 0x80)) {
5524 if(ivideo->chip == XGI_20) {
5525 outSISIDXREG(SISCR, 0x97, v1);
5526 inSISIDXREG(SISCR, 0x97, reg);
5528 ramtype = (reg & 0x01) << 1;
5531 inSISIDXREG(SISSR, 0x39, reg);
5532 ramtype = reg & 0x02;
5534 inSISIDXREG(SISSR, 0x3a, reg);
5535 ramtype = (reg >> 1) & 0x01;
5545 sisfb_post_xgi_setclocks(ivideo, regb);
5546 if((ivideo->chip == XGI_20) ||
5547 (ivideo->revision_id == 1) ||
5548 (ivideo->revision_id == 2)) {
5549 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5550 if(ivideo->haveXGIROM) {
5551 v1 = bios[regb + 0x158];
5552 v2 = bios[regb + 0x160];
5553 v3 = bios[regb + 0x168];
5555 outSISIDXREG(SISCR, 0x82, v1);
5556 outSISIDXREG(SISCR, 0x85, v2);
5557 outSISIDXREG(SISCR, 0x86, v3);
5559 outSISIDXREG(SISCR, 0x82, 0x88);
5560 outSISIDXREG(SISCR, 0x86, 0x00);
5561 inSISIDXREG(SISCR, 0x86, reg);
5562 outSISIDXREG(SISCR, 0x86, 0x88);
5563 inSISIDXREG(SISCR, 0x86, reg);
5564 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5565 outSISIDXREG(SISCR, 0x82, 0x77);
5566 outSISIDXREG(SISCR, 0x85, 0x00);
5567 inSISIDXREG(SISCR, 0x85, reg);
5568 outSISIDXREG(SISCR, 0x85, 0x88);
5569 inSISIDXREG(SISCR, 0x85, reg);
5570 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5571 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5573 if(ivideo->chip == XGI_40) {
5574 outSISIDXREG(SISCR, 0x97, 0x00);
5576 outSISIDXREG(SISCR, 0x98, 0x01);
5577 outSISIDXREG(SISCR, 0x9a, 0x02);
5579 outSISIDXREG(SISSR, 0x18, 0x01);
5580 if((ivideo->chip == XGI_20) ||
5581 (ivideo->revision_id == 2)) {
5582 outSISIDXREG(SISSR, 0x19, 0x40);
5584 outSISIDXREG(SISSR, 0x19, 0x20);
5586 outSISIDXREG(SISSR, 0x16, 0x00);
5587 outSISIDXREG(SISSR, 0x16, 0x80);
5588 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5589 sisfb_post_xgi_delay(ivideo, 0x43);
5590 sisfb_post_xgi_delay(ivideo, 0x43);
5591 sisfb_post_xgi_delay(ivideo, 0x43);
5592 outSISIDXREG(SISSR, 0x18, 0x00);
5593 if((ivideo->chip == XGI_20) ||
5594 (ivideo->revision_id == 2)) {
5595 outSISIDXREG(SISSR, 0x19, 0x40);
5597 outSISIDXREG(SISSR, 0x19, 0x20);
5599 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5600 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5602 outSISIDXREG(SISSR, 0x16, 0x00);
5603 outSISIDXREG(SISSR, 0x16, 0x80);
5604 sisfb_post_xgi_delay(ivideo, 4);
5605 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5606 if(ivideo->haveXGIROM) {
5608 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5610 v3 = bios[index + 1];
5611 v4 = bios[index + 2];
5612 v5 = bios[index + 3];
5614 outSISIDXREG(SISSR, 0x18, v1);
5615 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5616 outSISIDXREG(SISSR, 0x16, v2);
5617 outSISIDXREG(SISSR, 0x16, v3);
5618 sisfb_post_xgi_delay(ivideo, 0x43);
5619 outSISIDXREG(SISSR, 0x1b, 0x03);
5620 sisfb_post_xgi_delay(ivideo, 0x22);
5621 outSISIDXREG(SISSR, 0x18, v1);
5622 outSISIDXREG(SISSR, 0x19, 0x00);
5623 outSISIDXREG(SISSR, 0x16, v4);
5624 outSISIDXREG(SISSR, 0x16, v5);
5625 outSISIDXREG(SISSR, 0x1b, 0x00);
5628 outSISIDXREG(SISCR, 0x82, 0x77);
5629 outSISIDXREG(SISCR, 0x86, 0x00);
5630 inSISIDXREG(SISCR, 0x86, reg);
5631 outSISIDXREG(SISCR, 0x86, 0x88);
5632 inSISIDXREG(SISCR, 0x86, reg);
5633 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5634 if(ivideo->haveXGIROM) {
5635 v1 = bios[regb + 0x168];
5636 v2 = bios[regb + 0x160];
5637 v3 = bios[regb + 0x158];
5639 outSISIDXREG(SISCR, 0x86, v1);
5640 outSISIDXREG(SISCR, 0x82, 0x77);
5641 outSISIDXREG(SISCR, 0x85, 0x00);
5642 inSISIDXREG(SISCR, 0x85, reg);
5643 outSISIDXREG(SISCR, 0x85, 0x88);
5644 inSISIDXREG(SISCR, 0x85, reg);
5645 outSISIDXREG(SISCR, 0x85, v2);
5646 outSISIDXREG(SISCR, 0x82, v3);
5647 outSISIDXREG(SISCR, 0x98, 0x01);
5648 outSISIDXREG(SISCR, 0x9a, 0x02);
5650 outSISIDXREG(SISSR, 0x28, 0x64);
5651 outSISIDXREG(SISSR, 0x29, 0x63);
5652 sisfb_post_xgi_delay(ivideo, 15);
5653 outSISIDXREG(SISSR, 0x18, 0x00);
5654 outSISIDXREG(SISSR, 0x19, 0x20);
5655 outSISIDXREG(SISSR, 0x16, 0x00);
5656 outSISIDXREG(SISSR, 0x16, 0x80);
5657 outSISIDXREG(SISSR, 0x18, 0xc5);
5658 outSISIDXREG(SISSR, 0x19, 0x23);
5659 outSISIDXREG(SISSR, 0x16, 0x00);
5660 outSISIDXREG(SISSR, 0x16, 0x80);
5661 sisfb_post_xgi_delay(ivideo, 1);
5662 outSISIDXREG(SISCR, 0x97,0x11);
5663 sisfb_post_xgi_setclocks(ivideo, regb);
5664 sisfb_post_xgi_delay(ivideo, 0x46);
5665 outSISIDXREG(SISSR, 0x18, 0xc5);
5666 outSISIDXREG(SISSR, 0x19, 0x23);
5667 outSISIDXREG(SISSR, 0x16, 0x00);
5668 outSISIDXREG(SISSR, 0x16, 0x80);
5669 sisfb_post_xgi_delay(ivideo, 1);
5670 outSISIDXREG(SISSR, 0x1b, 0x04);
5671 sisfb_post_xgi_delay(ivideo, 1);
5672 outSISIDXREG(SISSR, 0x1b, 0x00);
5673 sisfb_post_xgi_delay(ivideo, 1);
5675 if(ivideo->haveXGIROM) {
5678 outSISIDXREG(SISSR, 0x18, v1);
5679 outSISIDXREG(SISSR, 0x19, 0x06);
5680 outSISIDXREG(SISSR, 0x16, 0x04);
5681 outSISIDXREG(SISSR, 0x16, 0x84);
5682 sisfb_post_xgi_delay(ivideo, 1);
5685 sisfb_post_xgi_setclocks(ivideo, regb);
5686 if((ivideo->chip == XGI_40) &&
5687 ((ivideo->revision_id == 1) ||
5688 (ivideo->revision_id == 2))) {
5689 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5690 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5691 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5693 outSISIDXREG(SISCR, 0x82, 0x88);
5694 outSISIDXREG(SISCR, 0x86, 0x00);
5695 inSISIDXREG(SISCR, 0x86, reg);
5696 outSISIDXREG(SISCR, 0x86, 0x88);
5697 outSISIDXREG(SISCR, 0x82, 0x77);
5698 outSISIDXREG(SISCR, 0x85, 0x00);
5699 inSISIDXREG(SISCR, 0x85, reg);
5700 outSISIDXREG(SISCR, 0x85, 0x88);
5701 inSISIDXREG(SISCR, 0x85, reg);
5702 v1 = cs160[regb]; v2 = cs158[regb];
5703 if(ivideo->haveXGIROM) {
5704 v1 = bios[regb + 0x160];
5705 v2 = bios[regb + 0x158];
5707 outSISIDXREG(SISCR, 0x85, v1);
5708 outSISIDXREG(SISCR, 0x82, v2);
5710 if(ivideo->chip == XGI_40) {
5711 outSISIDXREG(SISCR, 0x97, 0x11);
5713 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5714 outSISIDXREG(SISCR, 0x98, 0x01);
5716 outSISIDXREG(SISCR, 0x98, 0x03);
5718 outSISIDXREG(SISCR, 0x9a, 0x02);
5720 if(ivideo->chip == XGI_40) {
5721 outSISIDXREG(SISSR, 0x18, 0x01);
5723 outSISIDXREG(SISSR, 0x18, 0x00);
5725 outSISIDXREG(SISSR, 0x19, 0x40);
5726 outSISIDXREG(SISSR, 0x16, 0x00);
5727 outSISIDXREG(SISSR, 0x16, 0x80);
5728 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5729 sisfb_post_xgi_delay(ivideo, 0x43);
5730 sisfb_post_xgi_delay(ivideo, 0x43);
5731 sisfb_post_xgi_delay(ivideo, 0x43);
5732 outSISIDXREG(SISSR, 0x18, 0x00);
5733 outSISIDXREG(SISSR, 0x19, 0x40);
5734 outSISIDXREG(SISSR, 0x16, 0x00);
5735 outSISIDXREG(SISSR, 0x16, 0x80);
5737 sisfb_post_xgi_delay(ivideo, 4);
5739 if(ivideo->haveXGIROM) {
5742 outSISIDXREG(SISSR, 0x18, v1);
5743 outSISIDXREG(SISSR, 0x19, 0x01);
5744 if(ivideo->chip == XGI_40) {
5745 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5746 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5748 outSISIDXREG(SISSR, 0x16, 0x05);
5749 outSISIDXREG(SISSR, 0x16, 0x85);
5751 sisfb_post_xgi_delay(ivideo, 0x43);
5752 if(ivideo->chip == XGI_40) {
5753 outSISIDXREG(SISSR, 0x1b, 0x01);
5755 outSISIDXREG(SISSR, 0x1b, 0x03);
5757 sisfb_post_xgi_delay(ivideo, 0x22);
5758 outSISIDXREG(SISSR, 0x18, v1);
5759 outSISIDXREG(SISSR, 0x19, 0x00);
5760 if(ivideo->chip == XGI_40) {
5761 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5762 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5764 outSISIDXREG(SISSR, 0x16, 0x05);
5765 outSISIDXREG(SISSR, 0x16, 0x85);
5767 outSISIDXREG(SISSR, 0x1b, 0x00);
5772 if(ivideo->haveXGIROM) {
5773 v1 = bios[0x110 + regb];
5775 outSISIDXREG(SISSR, 0x1b, v1);
5778 v1 = 0x00; v2 = 0x00;
5779 if(ivideo->haveXGIROM) {
5785 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5787 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5788 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5792 /* Set default mode, don't clear screen */
5793 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5794 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5795 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5796 ivideo->curFSTN = ivideo->curDSTN = 0;
5797 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5798 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5800 outSISIDXREG(SISSR, 0x05, 0x86);
5802 /* Disable read-cache */
5803 andSISIDXREG(SISSR, 0x21, 0xdf);
5804 sisfb_post_xgi_ramsize(ivideo);
5805 /* Enable read-cache */
5806 orSISIDXREG(SISSR, 0x21, 0x20);
5811 printk(KERN_DEBUG "-----------------\n");
5812 for(i = 0; i < 0xff; i++) {
5813 inSISIDXREG(SISCR, i, reg);
5814 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5816 for(i = 0; i < 0x40; i++) {
5817 inSISIDXREG(SISSR, i, reg);
5818 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5820 printk(KERN_DEBUG "-----------------\n");
5824 if(ivideo->chip == XGI_20) {
5825 orSISIDXREG(SISCR, 0x32, 0x20);
5827 inSISIDXREG(SISPART4, 0x00, reg);
5828 if((reg == 1) || (reg == 2)) {
5829 sisfb_sense_crt1(ivideo);
5831 orSISIDXREG(SISCR, 0x32, 0x20);
5835 /* Set default mode, don't clear screen */
5836 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5837 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5838 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5839 ivideo->curFSTN = ivideo->curDSTN = 0;
5840 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5842 outSISIDXREG(SISSR, 0x05, 0x86);
5845 orSISIDXREG(SISSR, 0x01, 0x20);
5847 /* Save mode number in CR34 */
5848 outSISIDXREG(SISCR, 0x34, 0x2e);
5850 /* Let everyone know what the current mode is */
5851 ivideo->modeprechange = 0x2e;
5853 if(ivideo->chip == XGI_40) {
5854 inSISIDXREG(SISCR, 0xca, reg);
5855 inSISIDXREG(SISCR, 0xcc, v1);
5856 if((reg & 0x10) && (!(v1 & 0x04))) {
5858 "sisfb: Please connect power to the card.\n");
5867 static int __devinit
5868 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5870 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5871 struct sis_video_info *ivideo = NULL;
5872 struct fb_info *sis_fb_info = NULL;
5880 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5881 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5885 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
5888 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5889 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5892 ivideo = (struct sis_video_info *)sis_fb_info->par;
5893 ivideo->memyselfandi = sis_fb_info;
5895 ivideo->sisfb_id = SISFB_ID;
5897 if(card_list == NULL) {
5898 ivideo->cardnumber = 0;
5900 struct sis_video_info *countvideo = card_list;
5901 ivideo->cardnumber = 1;
5902 while((countvideo = countvideo->next) != 0)
5903 ivideo->cardnumber++;
5906 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5908 ivideo->warncount = 0;
5909 ivideo->chip_id = pdev->device;
5910 ivideo->chip_vendor = pdev->vendor;
5911 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
5912 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5913 pci_read_config_word(pdev, PCI_COMMAND, ®16);
5914 ivideo->sisvga_enabled = reg16 & 0x01;
5915 ivideo->pcibus = pdev->bus->number;
5916 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5917 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5918 ivideo->subsysvendor = pdev->subsystem_vendor;
5919 ivideo->subsysdevice = pdev->subsystem_device;
5920 #ifdef SIS_OLD_CONFIG_COMPAT
5921 ivideo->ioctl32registered = 0;
5925 if(sisfb_mode_idx == -1) {
5926 sisfb_get_vga_mode_from_kernel();
5930 ivideo->chip = chipinfo->chip;
5931 ivideo->sisvga_engine = chipinfo->vgaengine;
5932 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5933 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5934 ivideo->mni = chipinfo->mni;
5936 ivideo->detectedpdc = 0xff;
5937 ivideo->detectedpdca = 0xff;
5938 ivideo->detectedlcda = 0xff;
5940 ivideo->sisfb_thismonitor.datavalid = FALSE;
5942 ivideo->current_base = 0;
5944 ivideo->engineok = 0;
5946 ivideo->sisfb_was_boot_device = 0;
5947 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5948 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5949 if(ivideo->sisvga_enabled)
5950 ivideo->sisfb_was_boot_device = 1;
5952 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5953 "but marked as boot video device ???\n");
5954 printk(KERN_DEBUG "sisfb: I will not accept this "
5955 "as the primary VGA device\n");
5960 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5961 ivideo->sisfb_accel = sisfb_accel;
5962 ivideo->sisfb_ypan = sisfb_ypan;
5963 ivideo->sisfb_max = sisfb_max;
5964 ivideo->sisfb_userom = sisfb_userom;
5965 ivideo->sisfb_useoem = sisfb_useoem;
5966 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5967 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5968 ivideo->sisfb_crt1off = sisfb_crt1off;
5969 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5970 ivideo->sisfb_crt2type = sisfb_crt2type;
5971 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5972 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5973 ivideo->sisfb_dstn = sisfb_dstn;
5974 ivideo->sisfb_fstn = sisfb_fstn;
5975 ivideo->sisfb_tvplug = sisfb_tvplug;
5976 ivideo->sisfb_tvstd = sisfb_tvstd;
5977 ivideo->tvxpos = sisfb_tvxposoffset;
5978 ivideo->tvypos = sisfb_tvyposoffset;
5979 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5980 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5981 ivideo->sisfb_inverse = sisfb_inverse;
5984 ivideo->refresh_rate = 0;
5985 if(ivideo->sisfb_parm_rate != -1) {
5986 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5989 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5990 ivideo->SiS_Pr.CenterScreen = -1;
5991 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5992 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5994 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5995 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5996 ivideo->SiS_Pr.SiS_ChSW = FALSE;
5997 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5998 ivideo->SiS_Pr.HaveEMI = FALSE;
5999 ivideo->SiS_Pr.HaveEMILCD = FALSE;
6000 ivideo->SiS_Pr.OverruleEMI = FALSE;
6001 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
6002 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
6003 ivideo->SiS_Pr.PDC = -1;
6004 ivideo->SiS_Pr.PDCA = -1;
6005 ivideo->SiS_Pr.DDCPortMixup = FALSE;
6006 #ifdef CONFIG_FB_SIS_315
6007 if(ivideo->chip >= SIS_330) {
6008 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
6009 if(ivideo->chip >= SIS_661) {
6010 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
6015 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6017 pci_set_drvdata(pdev, ivideo);
6019 /* Patch special cases */
6020 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6021 switch(ivideo->nbridge->device) {
6022 #ifdef CONFIG_FB_SIS_300
6023 case PCI_DEVICE_ID_SI_730:
6024 ivideo->chip = SIS_730;
6025 strcpy(ivideo->myid, "SiS 730");
6028 #ifdef CONFIG_FB_SIS_315
6029 case PCI_DEVICE_ID_SI_651:
6030 /* ivideo->chip is ok */
6031 strcpy(ivideo->myid, "SiS 651");
6033 case PCI_DEVICE_ID_SI_740:
6034 ivideo->chip = SIS_740;
6035 strcpy(ivideo->myid, "SiS 740");
6037 case PCI_DEVICE_ID_SI_661:
6038 ivideo->chip = SIS_661;
6039 strcpy(ivideo->myid, "SiS 661");
6041 case PCI_DEVICE_ID_SI_741:
6042 ivideo->chip = SIS_741;
6043 strcpy(ivideo->myid, "SiS 741");
6045 case PCI_DEVICE_ID_SI_760:
6046 ivideo->chip = SIS_760;
6047 strcpy(ivideo->myid, "SiS 760");
6049 case PCI_DEVICE_ID_SI_761:
6050 ivideo->chip = SIS_761;
6051 strcpy(ivideo->myid, "SiS 761");
6059 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6060 strcpy(sis_fb_info->modename, ivideo->myid);
6063 ivideo->SiS_Pr.ChipType = ivideo->chip;
6065 ivideo->SiS_Pr.ivideo = (void *)ivideo;
6067 #ifdef CONFIG_FB_SIS_315
6068 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6069 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6070 ivideo->SiS_Pr.ChipType = SIS_315H;
6074 if(!ivideo->sisvga_enabled) {
6075 if(pci_enable_device(pdev)) {
6076 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6077 pci_set_drvdata(pdev, NULL);
6083 ivideo->video_base = pci_resource_start(pdev, 0);
6084 ivideo->mmio_base = pci_resource_start(pdev, 1);
6085 ivideo->mmio_size = pci_resource_len(pdev, 1);
6086 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
6087 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
6089 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
6091 #ifdef CONFIG_FB_SIS_300
6092 /* Find PCI systems for Chrontel/GPIO communication setup */
6093 if(ivideo->chip == SIS_630) {
6096 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6097 mychswtable[i].subsysCard == ivideo->subsysdevice) {
6098 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6099 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6100 "requiring Chrontel/GPIO setup\n",
6101 mychswtable[i].vendorName,
6102 mychswtable[i].cardName);
6103 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6107 } while(mychswtable[i].subsysVendor != 0);
6111 #ifdef CONFIG_FB_SIS_315
6112 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6113 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
6117 outSISIDXREG(SISSR, 0x05, 0x86);
6119 if( (!ivideo->sisvga_enabled)
6120 #if !defined(__i386__) && !defined(__x86_64__)
6121 || (sisfb_resetcard)
6124 for(i = 0x30; i <= 0x3f; i++) {
6125 outSISIDXREG(SISCR, i, 0x00);
6129 /* Find out about current video mode */
6130 ivideo->modeprechange = 0x03;
6131 inSISIDXREG(SISCR, 0x34, reg);
6133 ivideo->modeprechange = reg & 0x7f;
6134 } else if(ivideo->sisvga_enabled) {
6135 #if defined(__i386__) || defined(__x86_64__)
6136 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
6138 ivideo->modeprechange = readb(tt + 0x49);
6144 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6146 if((reg & 0x80) && (reg != 0xff)) {
6147 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6149 printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6150 "X server is active\n");
6158 /* Search and copy ROM image */
6159 ivideo->bios_abase = NULL;
6160 ivideo->SiS_Pr.VirtualRomBase = NULL;
6161 ivideo->SiS_Pr.UseROM = FALSE;
6162 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
6163 if(ivideo->sisfb_userom) {
6164 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6165 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6166 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6167 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6168 ivideo->SiS_Pr.UseROM ? "" : "not ");
6169 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6170 ivideo->SiS_Pr.UseROM = FALSE;
6171 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6172 if( (ivideo->revision_id == 2) &&
6173 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6174 ivideo->SiS_Pr.DDCPortMixup = TRUE;
6178 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6181 /* Find systems for special custom timing */
6182 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6183 sisfb_detect_custom_timing(ivideo);
6186 /* POST card in case this has not been done by the BIOS */
6187 if( (!ivideo->sisvga_enabled)
6188 #if !defined(__i386__) && !defined(__x86_64__)
6189 || (sisfb_resetcard)
6192 #ifdef CONFIG_FB_SIS_300
6193 if(ivideo->sisvga_engine == SIS_300_VGA) {
6194 if(ivideo->chip == SIS_300) {
6195 sisfb_post_sis300(pdev);
6196 ivideo->sisfb_can_post = 1;
6201 #ifdef CONFIG_FB_SIS_315
6202 if(ivideo->sisvga_engine == SIS_315_VGA) {
6204 /* if((ivideo->chip == SIS_315H) ||
6205 (ivideo->chip == SIS_315) ||
6206 (ivideo->chip == SIS_315PRO) ||
6207 (ivideo->chip == SIS_330)) {
6208 sisfb_post_sis315330(pdev);
6209 } else */ if(ivideo->chip == XGI_20) {
6210 result = sisfb_post_xgi(pdev);
6211 ivideo->sisfb_can_post = 1;
6212 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6213 result = sisfb_post_xgi(pdev);
6214 ivideo->sisfb_can_post = 1;
6216 printk(KERN_INFO "sisfb: Card is not "
6217 "POSTed and sisfb can't do this either.\n");
6220 printk(KERN_ERR "sisfb: Failed to POST card\n");
6228 ivideo->sisfb_card_posted = 1;
6230 /* Find out about RAM size */
6231 if(sisfb_get_dram_size(ivideo)) {
6232 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6238 /* Enable PCI addressing and MMIO */
6239 if((ivideo->sisfb_mode_idx < 0) ||
6240 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6241 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6242 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6243 /* Enable 2D accelerator engine */
6244 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6247 if(sisfb_pdc != 0xff) {
6248 if(ivideo->sisvga_engine == SIS_300_VGA)
6252 ivideo->SiS_Pr.PDC = sisfb_pdc;
6254 #ifdef CONFIG_FB_SIS_315
6255 if(ivideo->sisvga_engine == SIS_315_VGA) {
6256 if(sisfb_pdca != 0xff)
6257 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6261 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6262 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6263 (int)(ivideo->video_size >> 20));
6264 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6269 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6270 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6275 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6276 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6277 if(!ivideo->video_vbase) {
6278 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6283 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6284 if(!ivideo->mmio_vbase) {
6285 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6287 error_0: iounmap(ivideo->video_vbase);
6288 error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6289 error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6290 error_3: vfree(ivideo->bios_abase);
6291 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6295 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6297 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6298 pci_set_drvdata(pdev, NULL);
6299 if(!ivideo->sisvga_enabled)
6300 pci_disable_device(pdev);
6305 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6306 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6308 if(ivideo->video_offset) {
6309 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6310 ivideo->video_offset / 1024);
6313 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6314 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6317 /* Determine the size of the command queue */
6318 if(ivideo->sisvga_engine == SIS_300_VGA) {
6319 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6321 if(ivideo->chip == XGI_20) {
6322 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6324 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6328 /* Engines are no longer initialized here; this is
6329 * now done after the first mode-switch (if the
6330 * submitted var has its acceleration flags set).
6333 /* Calculate the base of the (unused) hw cursor */
6334 ivideo->hwcursor_vbase = ivideo->video_vbase
6335 + ivideo->video_size
6336 - ivideo->cmdQueueSize
6337 - ivideo->hwcursor_size;
6338 ivideo->caps |= HW_CURSOR_CAP;
6340 /* Initialize offscreen memory manager */
6341 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6342 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6345 /* Used for clearing the screen only, therefore respect our mem limit */
6346 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6347 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6351 ivideo->vbflags = 0;
6352 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6353 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6354 ivideo->defmodeidx = DEFAULT_MODE;
6357 if(ivideo->chip < XGI_20) {
6358 if(ivideo->bios_abase) {
6359 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6363 if((ivideo->sisfb_mode_idx < 0) ||
6364 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6366 sisfb_sense_crt1(ivideo);
6368 sisfb_get_VB_type(ivideo);
6370 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6371 sisfb_detect_VB_connect(ivideo);
6374 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6376 /* Decide on which CRT2 device to use */
6377 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6378 if(ivideo->sisfb_crt2type != -1) {
6379 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6380 (ivideo->vbflags & CRT2_LCD)) {
6381 ivideo->currentvbflags |= CRT2_LCD;
6382 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6383 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6386 /* Chrontel 700x TV detection often unreliable, therefore
6387 * use a different default order on such machines
6389 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6390 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6391 if(ivideo->vbflags & CRT2_LCD)
6392 ivideo->currentvbflags |= CRT2_LCD;
6393 else if(ivideo->vbflags & CRT2_TV)
6394 ivideo->currentvbflags |= CRT2_TV;
6395 else if(ivideo->vbflags & CRT2_VGA)
6396 ivideo->currentvbflags |= CRT2_VGA;
6398 if(ivideo->vbflags & CRT2_TV)
6399 ivideo->currentvbflags |= CRT2_TV;
6400 else if(ivideo->vbflags & CRT2_LCD)
6401 ivideo->currentvbflags |= CRT2_LCD;
6402 else if(ivideo->vbflags & CRT2_VGA)
6403 ivideo->currentvbflags |= CRT2_VGA;
6408 if(ivideo->vbflags & CRT2_LCD) {
6409 sisfb_detect_lcd_type(ivideo);
6412 sisfb_save_pdc_emi(ivideo);
6414 if(!ivideo->sisfb_crt1off) {
6415 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6417 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6418 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6419 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6423 if(ivideo->sisfb_mode_idx >= 0) {
6424 int bu = ivideo->sisfb_mode_idx;
6425 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6426 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6427 if(bu != ivideo->sisfb_mode_idx) {
6428 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6429 sisbios_mode[bu].xres,
6430 sisbios_mode[bu].yres,
6431 sisbios_mode[bu].bpp);
6435 if(ivideo->sisfb_mode_idx < 0) {
6436 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6438 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6441 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6444 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6449 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6451 if(ivideo->refresh_rate != 0) {
6452 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6453 ivideo->sisfb_mode_idx);
6456 if(ivideo->rate_idx == 0) {
6457 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6458 ivideo->refresh_rate = 60;
6461 if(ivideo->sisfb_thismonitor.datavalid) {
6462 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6463 ivideo->sisfb_mode_idx,
6465 ivideo->refresh_rate)) {
6466 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6467 "exceeds monitor specs!\n");
6471 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6472 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6473 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6475 sisfb_set_vparms(ivideo);
6477 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6479 /* ---------------- For 2.4: Now switch the mode ------------------ */
6481 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6482 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6483 ivideo->refresh_rate);
6485 /* Determine whether or not acceleration is to be
6486 * used. Need to know before pre/post_set_mode()
6489 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6490 if(ivideo->sisfb_accel) {
6492 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6495 /* Now switch the mode */
6496 sisfb_pre_setmode(ivideo);
6498 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
6499 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6502 iounmap(ivideo->mmio_vbase);
6506 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6508 sisfb_post_setmode(ivideo);
6510 /* Maximize regardless of sisfb_max at startup */
6511 ivideo->default_var.yres_virtual = 32767;
6513 /* Force reset of x virtual in crtc_to_var */
6514 ivideo->default_var.xres_virtual = 0;
6516 /* Copy mode timing to var */
6517 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6519 /* Find out about screen pitch */
6520 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6521 sisfb_set_pitch(ivideo);
6523 /* Init the accelerator (does nothing currently) */
6524 sisfb_initaccel(ivideo);
6526 /* Init some fbinfo entries */
6527 sis_fb_info->node = -1;
6528 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6529 sis_fb_info->fbops = &sisfb_ops;
6530 sis_fb_info->disp = &ivideo->sis_disp;
6531 sis_fb_info->blank = &sisfb_blank;
6532 sis_fb_info->switch_con = &sisfb_switch;
6533 sis_fb_info->updatevar = &sisfb_update_var;
6534 sis_fb_info->changevar = NULL;
6535 strcpy(sis_fb_info->fontname, sisfb_fontname);
6537 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6539 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6541 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6542 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6543 ivideo->refresh_rate);
6545 /* Set up the default var according to chosen default display mode */
6546 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6547 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6548 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6550 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6552 ivideo->default_var.pixclock = (u32) (1000000000 /
6553 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6555 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6556 ivideo->rate_idx, &ivideo->default_var)) {
6557 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6558 ivideo->default_var.pixclock <<= 1;
6562 if(ivideo->sisfb_ypan) {
6563 /* Maximize regardless of sisfb_max at startup */
6564 ivideo->default_var.yres_virtual =
6565 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6566 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6567 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6571 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6574 if(ivideo->sisfb_accel) {
6576 #ifdef STUPID_ACCELF_TEXT_SHIT
6577 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6580 sisfb_initaccel(ivideo);
6582 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6583 sis_fb_info->flags = FBINFO_DEFAULT |
6584 FBINFO_HWACCEL_YPAN |
6585 FBINFO_HWACCEL_XPAN |
6586 FBINFO_HWACCEL_COPYAREA |
6587 FBINFO_HWACCEL_FILLRECT |
6588 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6590 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6592 sis_fb_info->var = ivideo->default_var;
6593 sis_fb_info->fix = ivideo->sisfb_fix;
6594 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6595 sis_fb_info->fbops = &sisfb_ops;
6597 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6598 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6600 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6603 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6606 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6607 MTRR_TYPE_WRCOMB, 1);
6608 if(ivideo->mtrr < 0) {
6609 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6613 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6614 vc_resize_con(1, 1, 0);
6617 if(register_framebuffer(sis_fb_info) < 0) {
6618 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6620 iounmap(ivideo->mmio_vbase);
6624 ivideo->registered = 1;
6627 ivideo->next = card_list;
6630 #ifdef SIS_OLD_CONFIG_COMPAT
6633 /* Our ioctls are all "32/64bit compatible" */
6634 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6635 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6636 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6637 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6638 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6639 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6640 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6641 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6642 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6643 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6644 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6645 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6648 "sisfb: Error registering ioctl32 translations\n");
6650 ivideo->ioctl32registered = 1;
6654 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6655 ivideo->sisfb_accel ? "enabled" : "disabled",
6656 ivideo->sisfb_ypan ?
6657 (ivideo->sisfb_max ? "enabled (auto-max)" :
6658 "enabled (no auto-max)") :
6662 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6663 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6664 GET_FB_IDX(sis_fb_info->node),
6668 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6670 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6672 } /* if mode = "none" */
6677 /*****************************************************/
6678 /* PCI DEVICE HANDLING */
6679 /*****************************************************/
6681 static void __devexit sisfb_remove(struct pci_dev *pdev)
6683 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6684 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6685 int registered = ivideo->registered;
6686 int modechanged = ivideo->modechanged;
6688 #ifdef SIS_OLD_CONFIG_COMPAT
6689 if(ivideo->ioctl32registered) {
6691 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6692 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6693 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6694 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6695 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6696 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6697 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6698 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6699 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6700 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6701 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6702 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6705 "sisfb: Error unregistering ioctl32 translations\n");
6710 iounmap(ivideo->mmio_vbase);
6711 iounmap(ivideo->video_vbase);
6713 /* Release mem regions */
6714 release_mem_region(ivideo->video_base, ivideo->video_size);
6715 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6717 vfree(ivideo->bios_abase);
6720 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6723 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6726 /* Release MTRR region */
6727 if(ivideo->mtrr >= 0)
6728 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6731 pci_set_drvdata(pdev, NULL);
6733 /* If device was disabled when starting, disable
6736 if(!ivideo->sisvga_enabled)
6737 pci_disable_device(pdev);
6739 /* Unregister the framebuffer */
6740 if(ivideo->registered) {
6741 unregister_framebuffer(sis_fb_info);
6742 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6743 framebuffer_release(sis_fb_info);
6749 /* OK, our ivideo is gone for good from here. */
6751 /* TODO: Restore the initial mode
6752 * This sounds easy but is as good as impossible
6753 * on many machines with SiS chip and video bridge
6754 * since text modes are always set up differently
6755 * from machine to machine. Depends on the type
6756 * of integration between chipset and bridge.
6758 if(registered && modechanged)
6760 "sisfb: Restoring of text mode not supported yet\n");
6763 static struct pci_driver sisfb_driver = {
6765 .id_table = sisfb_pci_table,
6766 .probe = sisfb_probe,
6767 .remove = __devexit_p(sisfb_remove)
6770 SISINITSTATIC int __init sisfb_init(void)
6772 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6774 char *options = NULL;
6776 if(fb_get_options("sisfb", &options))
6779 sisfb_setup(options);
6782 return pci_register_driver(&sisfb_driver);
6785 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6787 module_init(sisfb_init);
6791 /*****************************************************/
6793 /*****************************************************/
6797 static char *mode = NULL;
6798 static int vesa = -1;
6799 static unsigned int rate = 0;
6800 static unsigned int crt1off = 1;
6801 static unsigned int mem = 0;
6802 static char *forcecrt2type = NULL;
6803 static int forcecrt1 = -1;
6804 static int pdc = -1;
6805 static int pdc1 = -1;
6806 static int noaccel = -1;
6807 static int noypan = -1;
6808 static int nomax = -1;
6809 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6810 static int inverse = 0;
6812 static int userom = -1;
6813 static int useoem = -1;
6814 static char *tvstandard = NULL;
6815 static int nocrt2rate = 0;
6816 static int scalelcd = -1;
6817 static char *specialtiming = NULL;
6818 static int lvdshl = -1;
6819 static int tvxposoffset = 0, tvyposoffset = 0;
6820 #if !defined(__i386__) && !defined(__x86_64__)
6821 static int resetcard = 0;
6822 static int videoram = 0;
6825 static int __init sisfb_init_module(void)
6827 sisfb_setdefaultparms();
6830 sisfb_parm_rate = rate;
6832 if((scalelcd == 0) || (scalelcd == 1))
6833 sisfb_scalelcd = scalelcd ^ 1;
6835 /* Need to check crt2 type first for fstn/dstn */
6838 sisfb_search_crt2type(forcecrt2type);
6841 sisfb_search_tvstd(tvstandard);
6844 sisfb_search_mode(mode, FALSE);
6846 sisfb_search_vesamode(vesa, FALSE);
6848 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6850 sisfb_forcecrt1 = forcecrt1;
6853 else if(forcecrt1 == 0)
6858 else if(noaccel == 0)
6863 else if(noypan == 0)
6871 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6872 if(inverse) sisfb_inverse = 1;
6876 sisfb_parm_mem = mem;
6879 sisfb_userom = userom;
6882 sisfb_useoem = useoem;
6885 sisfb_pdc = (pdc & 0x7f);
6888 sisfb_pdca = (pdc1 & 0x1f);
6890 sisfb_nocrt2rate = nocrt2rate;
6893 sisfb_search_specialtiming(specialtiming);
6895 if((lvdshl >= 0) && (lvdshl <= 3))
6896 sisfb_lvdshl = lvdshl;
6898 sisfb_tvxposoffset = tvxposoffset;
6899 sisfb_tvyposoffset = tvyposoffset;
6901 #if !defined(__i386__) && !defined(__x86_64__)
6902 sisfb_resetcard = (resetcard) ? 1 : 0;
6904 sisfb_videoram = videoram;
6907 return sisfb_init();
6910 static void __exit sisfb_remove_module(void)
6912 pci_unregister_driver(&sisfb_driver);
6913 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6916 module_init(sisfb_init_module);
6917 module_exit(sisfb_remove_module);
6919 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6920 MODULE_LICENSE("GPL");
6921 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6923 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6924 MODULE_PARM(mem, "i");
6925 MODULE_PARM(noaccel, "i");
6926 MODULE_PARM(noypan, "i");
6927 MODULE_PARM(nomax, "i");
6928 MODULE_PARM(userom, "i");
6929 MODULE_PARM(useoem, "i");
6930 MODULE_PARM(mode, "s");
6931 MODULE_PARM(vesa, "i");
6932 MODULE_PARM(rate, "i");
6933 MODULE_PARM(forcecrt1, "i");
6934 MODULE_PARM(forcecrt2type, "s");
6935 MODULE_PARM(scalelcd, "i");
6936 MODULE_PARM(pdc, "i");
6937 MODULE_PARM(pdc1, "i");
6938 MODULE_PARM(specialtiming, "s");
6939 MODULE_PARM(lvdshl, "i");
6940 MODULE_PARM(tvstandard, "s");
6941 MODULE_PARM(tvxposoffset, "i");
6942 MODULE_PARM(tvyposoffset, "i");
6943 MODULE_PARM(nocrt2rate, "i");
6944 MODULE_PARM(inverse, "i");
6945 #if !defined(__i386__) && !defined(__x86_64__)
6946 MODULE_PARM(resetcard, "i");
6947 MODULE_PARM(videoram, "i");
6951 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6952 module_param(mem, int, 0);
6953 module_param(noaccel, int, 0);
6954 module_param(noypan, int, 0);
6955 module_param(nomax, int, 0);
6956 module_param(userom, int, 0);
6957 module_param(useoem, int, 0);
6958 module_param(mode, charp, 0);
6959 module_param(vesa, int, 0);
6960 module_param(rate, int, 0);
6961 module_param(forcecrt1, int, 0);
6962 module_param(forcecrt2type, charp, 0);
6963 module_param(scalelcd, int, 0);
6964 module_param(pdc, int, 0);
6965 module_param(pdc1, int, 0);
6966 module_param(specialtiming, charp, 0);
6967 module_param(lvdshl, int, 0);
6968 module_param(tvstandard, charp, 0);
6969 module_param(tvxposoffset, int, 0);
6970 module_param(tvyposoffset, int, 0);
6971 module_param(nocrt2rate, int, 0);
6972 #if !defined(__i386__) && !defined(__x86_64__)
6973 module_param(resetcard, int, 0);
6974 module_param(videoram, int, 0);
6978 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6979 MODULE_PARM_DESC(mem,
6980 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6981 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6982 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6983 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6984 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6985 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6986 "for XFree86 4.x/X.org 6.7 and later.\n");
6988 MODULE_PARM_DESC(mem,
6989 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6990 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6991 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6992 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6993 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6994 "The value is to be specified without 'KB'.\n");
6997 MODULE_PARM_DESC(noaccel,
6998 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
7001 MODULE_PARM_DESC(noypan,
7002 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
7003 "will be performed by redrawing the screen. (default: 0)\n");
7005 MODULE_PARM_DESC(nomax,
7006 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
7007 "memory for the virtual screen in order to optimize scrolling performance. If\n"
7008 "this is set to anything other than 0, sisfb will not do this and thereby \n"
7009 "enable the user to positively specify a virtual Y size of the screen using\n"
7010 "fbset. (default: 0)\n");
7012 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7013 MODULE_PARM_DESC(mode,
7014 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7015 "1024x768x16. Other formats supported include XxY-Depth and\n"
7016 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7017 "number, it will be interpreted as a VESA mode number. (default: none if\n"
7018 "sisfb is a module; this leaves the console untouched and the driver will\n"
7019 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7020 "is in the kernel)\n");
7021 MODULE_PARM_DESC(vesa,
7022 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7023 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
7024 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7025 "0x0103 if sisfb is in the kernel)\n");
7028 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7029 MODULE_PARM_DESC(mode,
7030 "\nSelects the desired default display mode in the format XxYxDepth,\n"
7031 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
7032 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7033 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7035 MODULE_PARM_DESC(vesa,
7036 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7037 "0x117 (default: 0x0103)\n");
7040 MODULE_PARM_DESC(rate,
7041 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7042 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7043 "will be ignored (default: 60)\n");
7045 MODULE_PARM_DESC(forcecrt1,
7046 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7047 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7048 "0=CRT1 OFF) (default: [autodetected])\n");
7050 MODULE_PARM_DESC(forcecrt2type,
7051 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7052 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7053 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7054 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7055 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7056 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7057 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7058 "depends on the very hardware in use. (default: [autodetected])\n");
7060 MODULE_PARM_DESC(scalelcd,
7061 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7062 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7063 "show black bars around the image, TMDS panels will probably do the scaling\n"
7064 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7066 MODULE_PARM_DESC(pdc,
7067 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
7068 "should detect this correctly in most cases; however, sometimes this is not\n"
7069 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
7070 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7071 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7072 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
7074 #ifdef CONFIG_FB_SIS_315
7075 MODULE_PARM_DESC(pdc1,
7076 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
7077 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7078 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7079 "implemented yet.\n");
7082 MODULE_PARM_DESC(specialtiming,
7083 "\nPlease refer to documentation for more information on this option.\n");
7085 MODULE_PARM_DESC(lvdshl,
7086 "\nPlease refer to documentation for more information on this option.\n");
7088 MODULE_PARM_DESC(tvstandard,
7089 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7090 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7092 MODULE_PARM_DESC(tvxposoffset,
7093 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7096 MODULE_PARM_DESC(tvyposoffset,
7097 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7100 MODULE_PARM_DESC(nocrt2rate,
7101 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7102 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7104 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7105 MODULE_PARM_DESC(inverse,
7106 "\nSetting this to anything but 0 should invert the display colors, but this\n"
7107 "does not seem to work. (default: 0)\n");
7110 #if !defined(__i386__) && !defined(__x86_64__)
7111 #ifdef CONFIG_FB_SIS_300
7112 MODULE_PARM_DESC(resetcard,
7113 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
7114 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7115 "currently). Default: 0\n");
7117 MODULE_PARM_DESC(videoram,
7118 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7119 "some non-x86 architectures where the memory auto detection fails. Only\n"
7120 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
7124 #endif /* /MODULE */
7126 /* _GPL only for new symbols. */
7127 EXPORT_SYMBOL(sis_malloc);
7128 EXPORT_SYMBOL(sis_free);
7129 EXPORT_SYMBOL_GPL(sis_malloc_new);
7130 EXPORT_SYMBOL_GPL(sis_free_new);