Linux 2.6.21
[linux/fpc-iii.git] / drivers / video / sis / sis_main.c
blob01197d7402174a113ad103f40c2197be1c809d6d
1 /*
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],
4 * XGI V3XT/V5/V8, Z7
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:
26 * SiS (www.sis.com)
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/version.h>
37 #include <linux/module.h>
38 #include <linux/moduleparam.h>
39 #include <linux/kernel.h>
40 #include <linux/smp_lock.h>
41 #include <linux/spinlock.h>
42 #include <linux/errno.h>
43 #include <linux/string.h>
44 #include <linux/mm.h>
46 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
47 #include <linux/tty.h>
48 #else
49 #include <linux/screen_info.h>
50 #endif
52 #include <linux/slab.h>
53 #include <linux/fb.h>
54 #include <linux/selection.h>
55 #include <linux/ioport.h>
56 #include <linux/init.h>
57 #include <linux/pci.h>
58 #include <linux/vmalloc.h>
59 #include <linux/capability.h>
60 #include <linux/fs.h>
61 #include <linux/types.h>
62 #include <asm/uaccess.h>
63 #include <asm/io.h>
64 #ifdef CONFIG_MTRR
65 #include <asm/mtrr.h>
66 #endif
68 #include "sis.h"
69 #include "sis_main.h"
71 static void sisfb_handle_command(struct sis_video_info *ivideo,
72 struct sisfb_cmd *sisfb_command);
74 /* ------------------ Internal helper routines ----------------- */
76 static void __init
77 sisfb_setdefaultparms(void)
79 sisfb_off = 0;
80 sisfb_parm_mem = 0;
81 sisfb_accel = -1;
82 sisfb_ypan = -1;
83 sisfb_max = -1;
84 sisfb_userom = -1;
85 sisfb_useoem = -1;
86 sisfb_mode_idx = -1;
87 sisfb_parm_rate = -1;
88 sisfb_crt1off = 0;
89 sisfb_forcecrt1 = -1;
90 sisfb_crt2type = -1;
91 sisfb_crt2flags = 0;
92 sisfb_pdc = 0xff;
93 sisfb_pdca = 0xff;
94 sisfb_scalelcd = -1;
95 sisfb_specialtiming = CUT_NONE;
96 sisfb_lvdshl = -1;
97 sisfb_dstn = 0;
98 sisfb_fstn = 0;
99 sisfb_tvplug = -1;
100 sisfb_tvstd = -1;
101 sisfb_tvxposoffset = 0;
102 sisfb_tvyposoffset = 0;
103 sisfb_nocrt2rate = 0;
104 #if !defined(__i386__) && !defined(__x86_64__)
105 sisfb_resetcard = 0;
106 sisfb_videoram = 0;
107 #endif
110 /* ------------- Parameter parsing -------------- */
112 static void __devinit
113 sisfb_search_vesamode(unsigned int vesamode, bool quiet)
115 int i = 0, j = 0;
117 /* We don't know the hardware specs yet and there is no ivideo */
119 if(vesamode == 0) {
120 if(!quiet)
121 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
123 sisfb_mode_idx = DEFAULT_MODE;
125 return;
128 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
130 while(sisbios_mode[i++].mode_no[0] != 0) {
131 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
132 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
133 if(sisfb_fstn) {
134 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
135 sisbios_mode[i-1].mode_no[1] == 0x56 ||
136 sisbios_mode[i-1].mode_no[1] == 0x53)
137 continue;
138 } else {
139 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
140 sisbios_mode[i-1].mode_no[1] == 0x5b)
141 continue;
143 sisfb_mode_idx = i - 1;
144 j = 1;
145 break;
148 if((!j) && !quiet)
149 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
152 static void __devinit
153 sisfb_search_mode(char *name, bool quiet)
155 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
156 int i = 0;
157 char strbuf[16], strbuf1[20];
158 char *nameptr = name;
160 /* We don't know the hardware specs yet and there is no ivideo */
162 if(name == NULL) {
163 if(!quiet)
164 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
166 sisfb_mode_idx = DEFAULT_MODE;
167 return;
170 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
171 if(!quiet)
172 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
174 sisfb_mode_idx = DEFAULT_MODE;
175 return;
178 if(strlen(name) <= 19) {
179 strcpy(strbuf1, name);
180 for(i = 0; i < strlen(strbuf1); i++) {
181 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
184 /* This does some fuzzy mode naming detection */
185 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
186 if((rate <= 32) || (depth > 32)) {
187 j = rate; rate = depth; depth = j;
189 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
190 nameptr = strbuf;
191 sisfb_parm_rate = rate;
192 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
193 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
194 nameptr = strbuf;
195 } else {
196 xres = 0;
197 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
198 sprintf(strbuf, "%ux%ux8", xres, yres);
199 nameptr = strbuf;
200 } else {
201 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
202 return;
207 i = 0; j = 0;
208 while(sisbios_mode[i].mode_no[0] != 0) {
209 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
210 if(sisfb_fstn) {
211 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
212 sisbios_mode[i-1].mode_no[1] == 0x56 ||
213 sisbios_mode[i-1].mode_no[1] == 0x53)
214 continue;
215 } else {
216 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
217 sisbios_mode[i-1].mode_no[1] == 0x5b)
218 continue;
220 sisfb_mode_idx = i - 1;
221 j = 1;
222 break;
226 if((!j) && !quiet)
227 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
230 #ifndef MODULE
231 static void __devinit
232 sisfb_get_vga_mode_from_kernel(void)
234 #ifdef CONFIG_X86
235 char mymode[32];
236 int mydepth = screen_info.lfb_depth;
238 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
240 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
241 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
242 (mydepth >= 8) && (mydepth <= 32) ) {
244 if(mydepth == 24) mydepth = 32;
246 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
247 screen_info.lfb_height,
248 mydepth);
250 printk(KERN_DEBUG
251 "sisfb: Using vga mode %s pre-set by kernel as default\n",
252 mymode);
254 sisfb_search_mode(mymode, true);
256 #endif
257 return;
259 #endif
261 static void __init
262 sisfb_search_crt2type(const char *name)
264 int i = 0;
266 /* We don't know the hardware specs yet and there is no ivideo */
268 if(name == NULL) return;
270 while(sis_crt2type[i].type_no != -1) {
271 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
272 sisfb_crt2type = sis_crt2type[i].type_no;
273 sisfb_tvplug = sis_crt2type[i].tvplug_no;
274 sisfb_crt2flags = sis_crt2type[i].flags;
275 break;
277 i++;
280 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
281 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
283 if(sisfb_crt2type < 0)
284 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
287 static void __init
288 sisfb_search_tvstd(const char *name)
290 int i = 0;
292 /* We don't know the hardware specs yet and there is no ivideo */
294 if(name == NULL)
295 return;
297 while(sis_tvtype[i].type_no != -1) {
298 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
299 sisfb_tvstd = sis_tvtype[i].type_no;
300 break;
302 i++;
306 static void __init
307 sisfb_search_specialtiming(const char *name)
309 int i = 0;
310 bool found = false;
312 /* We don't know the hardware specs yet and there is no ivideo */
314 if(name == NULL)
315 return;
317 if(!strnicmp(name, "none", 4)) {
318 sisfb_specialtiming = CUT_FORCENONE;
319 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
320 } else {
321 while(mycustomttable[i].chipID != 0) {
322 if(!strnicmp(name,mycustomttable[i].optionName,
323 strlen(mycustomttable[i].optionName))) {
324 sisfb_specialtiming = mycustomttable[i].SpecialID;
325 found = true;
326 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
327 mycustomttable[i].vendorName,
328 mycustomttable[i].cardName,
329 mycustomttable[i].optionName);
330 break;
332 i++;
334 if(!found) {
335 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
336 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
337 i = 0;
338 while(mycustomttable[i].chipID != 0) {
339 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
340 mycustomttable[i].optionName,
341 mycustomttable[i].vendorName,
342 mycustomttable[i].cardName);
343 i++;
349 /* ----------- Various detection routines ----------- */
351 static void __devinit
352 sisfb_detect_custom_timing(struct sis_video_info *ivideo)
354 unsigned char *biosver = NULL;
355 unsigned char *biosdate = NULL;
356 bool footprint;
357 u32 chksum = 0;
358 int i, j;
360 if(ivideo->SiS_Pr.UseROM) {
361 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
362 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
363 for(i = 0; i < 32768; i++)
364 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
367 i = 0;
368 do {
369 if( (mycustomttable[i].chipID == ivideo->chip) &&
370 ((!strlen(mycustomttable[i].biosversion)) ||
371 (ivideo->SiS_Pr.UseROM &&
372 (!strncmp(mycustomttable[i].biosversion, biosver,
373 strlen(mycustomttable[i].biosversion))))) &&
374 ((!strlen(mycustomttable[i].biosdate)) ||
375 (ivideo->SiS_Pr.UseROM &&
376 (!strncmp(mycustomttable[i].biosdate, biosdate,
377 strlen(mycustomttable[i].biosdate))))) &&
378 ((!mycustomttable[i].bioschksum) ||
379 (ivideo->SiS_Pr.UseROM &&
380 (mycustomttable[i].bioschksum == chksum))) &&
381 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
382 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
383 footprint = true;
384 for(j = 0; j < 5; j++) {
385 if(mycustomttable[i].biosFootprintAddr[j]) {
386 if(ivideo->SiS_Pr.UseROM) {
387 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
388 mycustomttable[i].biosFootprintData[j]) {
389 footprint = false;
391 } else
392 footprint = false;
395 if(footprint) {
396 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
397 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
398 mycustomttable[i].vendorName,
399 mycustomttable[i].cardName);
400 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
401 mycustomttable[i].optionName);
402 break;
405 i++;
406 } while(mycustomttable[i].chipID);
409 static bool __devinit
410 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
412 int i, j, xres, yres, refresh, index;
413 u32 emodes;
415 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
416 buffer[2] != 0xff || buffer[3] != 0xff ||
417 buffer[4] != 0xff || buffer[5] != 0xff ||
418 buffer[6] != 0xff || buffer[7] != 0x00) {
419 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
420 return false;
423 if(buffer[0x12] != 0x01) {
424 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
425 buffer[0x12]);
426 return false;
429 monitor->feature = buffer[0x18];
431 if(!buffer[0x14] & 0x80) {
432 if(!(buffer[0x14] & 0x08)) {
433 printk(KERN_INFO
434 "sisfb: WARNING: Monitor does not support separate syncs\n");
438 if(buffer[0x13] >= 0x01) {
439 /* EDID V1 rev 1 and 2: Search for monitor descriptor
440 * to extract ranges
442 j = 0x36;
443 for(i=0; i<4; i++) {
444 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
445 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
446 buffer[j + 4] == 0x00) {
447 monitor->hmin = buffer[j + 7];
448 monitor->hmax = buffer[j + 8];
449 monitor->vmin = buffer[j + 5];
450 monitor->vmax = buffer[j + 6];
451 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
452 monitor->datavalid = true;
453 break;
455 j += 18;
459 if(!monitor->datavalid) {
460 /* Otherwise: Get a range from the list of supported
461 * Estabished Timings. This is not entirely accurate,
462 * because fixed frequency monitors are not supported
463 * that way.
465 monitor->hmin = 65535; monitor->hmax = 0;
466 monitor->vmin = 65535; monitor->vmax = 0;
467 monitor->dclockmax = 0;
468 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
469 for(i = 0; i < 13; i++) {
470 if(emodes & sisfb_ddcsmodes[i].mask) {
471 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
472 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
473 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
474 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
475 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
478 index = 0x26;
479 for(i = 0; i < 8; i++) {
480 xres = (buffer[index] + 31) * 8;
481 switch(buffer[index + 1] & 0xc0) {
482 case 0xc0: yres = (xres * 9) / 16; break;
483 case 0x80: yres = (xres * 4) / 5; break;
484 case 0x40: yres = (xres * 3) / 4; break;
485 default: yres = xres; break;
487 refresh = (buffer[index + 1] & 0x3f) + 60;
488 if((xres >= 640) && (yres >= 480)) {
489 for(j = 0; j < 8; j++) {
490 if((xres == sisfb_ddcfmodes[j].x) &&
491 (yres == sisfb_ddcfmodes[j].y) &&
492 (refresh == sisfb_ddcfmodes[j].v)) {
493 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
494 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
495 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
496 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
497 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
501 index += 2;
503 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
504 monitor->datavalid = true;
508 return monitor->datavalid;
511 static void __devinit
512 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
514 unsigned short temp, i, realcrtno = crtno;
515 unsigned char buffer[256];
517 monitor->datavalid = false;
519 if(crtno) {
520 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
521 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
522 else return;
525 if((ivideo->sisfb_crt1off) && (!crtno))
526 return;
528 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
529 realcrtno, 0, &buffer[0], ivideo->vbflags2);
530 if((!temp) || (temp == 0xffff)) {
531 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
532 return;
533 } else {
534 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
535 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
536 crtno + 1,
537 (temp & 0x1a) ? "" : "[none of the supported]",
538 (temp & 0x02) ? "2 " : "",
539 (temp & 0x08) ? "D&P" : "",
540 (temp & 0x10) ? "FPDI-2" : "");
541 if(temp & 0x02) {
542 i = 3; /* Number of retrys */
543 do {
544 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
545 realcrtno, 1, &buffer[0], ivideo->vbflags2);
546 } while((temp) && i--);
547 if(!temp) {
548 if(sisfb_interpret_edid(monitor, &buffer[0])) {
549 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
550 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
551 monitor->dclockmax / 1000);
552 } else {
553 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
555 } else {
556 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
558 } else {
559 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
564 /* -------------- Mode validation --------------- */
566 static bool
567 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
568 int mode_idx, int rate_idx, int rate)
570 int htotal, vtotal;
571 unsigned int dclock, hsync;
573 if(!monitor->datavalid)
574 return true;
576 if(mode_idx < 0)
577 return false;
579 /* Skip for 320x200, 320x240, 640x400 */
580 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
581 case 0x59:
582 case 0x41:
583 case 0x4f:
584 case 0x50:
585 case 0x56:
586 case 0x53:
587 case 0x2f:
588 case 0x5d:
589 case 0x5e:
590 return true;
591 #ifdef CONFIG_FB_SIS_315
592 case 0x5a:
593 case 0x5b:
594 if(ivideo->sisvga_engine == SIS_315_VGA) return true;
595 #endif
598 if(rate < (monitor->vmin - 1))
599 return false;
600 if(rate > (monitor->vmax + 1))
601 return false;
603 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
604 sisbios_mode[mode_idx].mode_no[ivideo->mni],
605 &htotal, &vtotal, rate_idx)) {
606 dclock = (htotal * vtotal * rate) / 1000;
607 if(dclock > (monitor->dclockmax + 1000))
608 return false;
609 hsync = dclock / htotal;
610 if(hsync < (monitor->hmin - 1))
611 return false;
612 if(hsync > (monitor->hmax + 1))
613 return false;
614 } else {
615 return false;
617 return true;
620 static int
621 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
623 u16 xres=0, yres, myres;
625 #ifdef CONFIG_FB_SIS_300
626 if(ivideo->sisvga_engine == SIS_300_VGA) {
627 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
628 return -1 ;
630 #endif
631 #ifdef CONFIG_FB_SIS_315
632 if(ivideo->sisvga_engine == SIS_315_VGA) {
633 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
634 return -1;
636 #endif
638 myres = sisbios_mode[myindex].yres;
640 switch(vbflags & VB_DISPTYPE_DISP2) {
642 case CRT2_LCD:
643 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
645 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
646 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
647 if(sisbios_mode[myindex].xres > xres)
648 return -1;
649 if(myres > yres)
650 return -1;
653 if(ivideo->sisfb_fstn) {
654 if(sisbios_mode[myindex].xres == 320) {
655 if(myres == 240) {
656 switch(sisbios_mode[myindex].mode_no[1]) {
657 case 0x50: myindex = MODE_FSTN_8; break;
658 case 0x56: myindex = MODE_FSTN_16; break;
659 case 0x53: return -1;
665 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
666 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
667 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
668 return -1;
670 break;
672 case CRT2_TV:
673 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
674 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
675 return -1;
677 break;
679 case CRT2_VGA:
680 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
681 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
682 return -1;
684 break;
687 return myindex;
690 static u8
691 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
693 int i = 0;
694 u16 xres = sisbios_mode[mode_idx].xres;
695 u16 yres = sisbios_mode[mode_idx].yres;
697 ivideo->rate_idx = 0;
698 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
699 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
700 if(sisfb_vrate[i].refresh == rate) {
701 ivideo->rate_idx = sisfb_vrate[i].idx;
702 break;
703 } else if(sisfb_vrate[i].refresh > rate) {
704 if((sisfb_vrate[i].refresh - rate) <= 3) {
705 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
706 rate, sisfb_vrate[i].refresh);
707 ivideo->rate_idx = sisfb_vrate[i].idx;
708 ivideo->refresh_rate = sisfb_vrate[i].refresh;
709 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
710 && (sisfb_vrate[i].idx != 1)) {
711 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
712 rate, sisfb_vrate[i-1].refresh);
713 ivideo->rate_idx = sisfb_vrate[i-1].idx;
714 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
716 break;
717 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
718 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
719 rate, sisfb_vrate[i].refresh);
720 ivideo->rate_idx = sisfb_vrate[i].idx;
721 break;
724 i++;
726 if(ivideo->rate_idx > 0) {
727 return ivideo->rate_idx;
728 } else {
729 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
730 rate, xres, yres);
731 return 0;
735 static bool
736 sisfb_bridgeisslave(struct sis_video_info *ivideo)
738 unsigned char P1_00;
740 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
741 return false;
743 inSISIDXREG(SISPART1,0x00,P1_00);
744 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
745 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
746 return true;
747 } else {
748 return false;
752 static bool
753 sisfballowretracecrt1(struct sis_video_info *ivideo)
755 u8 temp;
757 inSISIDXREG(SISCR,0x17,temp);
758 if(!(temp & 0x80))
759 return false;
761 inSISIDXREG(SISSR,0x1f,temp);
762 if(temp & 0xc0)
763 return false;
765 return true;
768 static bool
769 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
771 if(!sisfballowretracecrt1(ivideo))
772 return false;
774 if(inSISREG(SISINPSTAT) & 0x08)
775 return true;
776 else
777 return false;
780 static void
781 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
783 int watchdog;
785 if(!sisfballowretracecrt1(ivideo))
786 return;
788 watchdog = 65536;
789 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
790 watchdog = 65536;
791 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
794 static bool
795 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
797 unsigned char temp, reg;
799 switch(ivideo->sisvga_engine) {
800 case SIS_300_VGA: reg = 0x25; break;
801 case SIS_315_VGA: reg = 0x30; break;
802 default: return false;
805 inSISIDXREG(SISPART1, reg, temp);
806 if(temp & 0x02)
807 return true;
808 else
809 return false;
812 static bool
813 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
815 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
816 if(!sisfb_bridgeisslave(ivideo)) {
817 return sisfbcheckvretracecrt2(ivideo);
820 return sisfbcheckvretracecrt1(ivideo);
823 static u32
824 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
826 u8 idx, reg1, reg2, reg3, reg4;
827 u32 ret = 0;
829 (*vcount) = (*hcount) = 0;
831 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
833 ret |= (FB_VBLANK_HAVE_VSYNC |
834 FB_VBLANK_HAVE_HBLANK |
835 FB_VBLANK_HAVE_VBLANK |
836 FB_VBLANK_HAVE_VCOUNT |
837 FB_VBLANK_HAVE_HCOUNT);
838 switch(ivideo->sisvga_engine) {
839 case SIS_300_VGA: idx = 0x25; break;
840 default:
841 case SIS_315_VGA: idx = 0x30; break;
843 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
844 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
845 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
846 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
847 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
848 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
849 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
850 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
851 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
853 } else if(sisfballowretracecrt1(ivideo)) {
855 ret |= (FB_VBLANK_HAVE_VSYNC |
856 FB_VBLANK_HAVE_VBLANK |
857 FB_VBLANK_HAVE_VCOUNT |
858 FB_VBLANK_HAVE_HCOUNT);
859 reg1 = inSISREG(SISINPSTAT);
860 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
861 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
862 inSISIDXREG(SISCR,0x20,reg1);
863 inSISIDXREG(SISCR,0x1b,reg1);
864 inSISIDXREG(SISCR,0x1c,reg2);
865 inSISIDXREG(SISCR,0x1d,reg3);
866 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
867 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
870 return ret;
873 static int
874 sisfb_myblank(struct sis_video_info *ivideo, int blank)
876 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
877 bool backlight = true;
879 switch(blank) {
880 case FB_BLANK_UNBLANK: /* on */
881 sr01 = 0x00;
882 sr11 = 0x00;
883 sr1f = 0x00;
884 cr63 = 0x00;
885 p2_0 = 0x20;
886 p1_13 = 0x00;
887 backlight = true;
888 break;
889 case FB_BLANK_NORMAL: /* blank */
890 sr01 = 0x20;
891 sr11 = 0x00;
892 sr1f = 0x00;
893 cr63 = 0x00;
894 p2_0 = 0x20;
895 p1_13 = 0x00;
896 backlight = true;
897 break;
898 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
899 sr01 = 0x20;
900 sr11 = 0x08;
901 sr1f = 0x80;
902 cr63 = 0x40;
903 p2_0 = 0x40;
904 p1_13 = 0x80;
905 backlight = false;
906 break;
907 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
908 sr01 = 0x20;
909 sr11 = 0x08;
910 sr1f = 0x40;
911 cr63 = 0x40;
912 p2_0 = 0x80;
913 p1_13 = 0x40;
914 backlight = false;
915 break;
916 case FB_BLANK_POWERDOWN: /* off */
917 sr01 = 0x20;
918 sr11 = 0x08;
919 sr1f = 0xc0;
920 cr63 = 0x40;
921 p2_0 = 0xc0;
922 p1_13 = 0xc0;
923 backlight = false;
924 break;
925 default:
926 return 1;
929 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
931 if( (!ivideo->sisfb_thismonitor.datavalid) ||
932 ((ivideo->sisfb_thismonitor.datavalid) &&
933 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
935 if(ivideo->sisvga_engine == SIS_315_VGA) {
936 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
939 if(!(sisfb_bridgeisslave(ivideo))) {
940 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
941 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
947 if(ivideo->currentvbflags & CRT2_LCD) {
949 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
950 if(backlight) {
951 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
952 } else {
953 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
955 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
956 #ifdef CONFIG_FB_SIS_315
957 if(ivideo->vbflags2 & VB2_CHRONTEL) {
958 if(backlight) {
959 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
960 } else {
961 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
964 #endif
967 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
968 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
969 ((ivideo->sisvga_engine == SIS_315_VGA) &&
970 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
971 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
974 if(ivideo->sisvga_engine == SIS_300_VGA) {
975 if((ivideo->vbflags2 & VB2_30xB) &&
976 (!(ivideo->vbflags2 & VB2_30xBDH))) {
977 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
979 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
980 if((ivideo->vbflags2 & VB2_30xB) &&
981 (!(ivideo->vbflags2 & VB2_30xBDH))) {
982 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
986 } else if(ivideo->currentvbflags & CRT2_VGA) {
988 if(ivideo->vbflags2 & VB2_30xB) {
989 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
994 return 0;
997 /* ------------- Callbacks from init.c/init301.c -------------- */
999 #ifdef CONFIG_FB_SIS_300
1000 unsigned int
1001 sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1003 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1004 u32 val = 0;
1006 pci_read_config_dword(ivideo->nbridge, reg, &val);
1007 return (unsigned int)val;
1010 void
1011 sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1013 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1015 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1018 unsigned int
1019 sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1021 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1022 u32 val = 0;
1024 if(!ivideo->lpcdev) return 0;
1026 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1027 return (unsigned int)val;
1029 #endif
1031 #ifdef CONFIG_FB_SIS_315
1032 void
1033 sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1035 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1037 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1040 unsigned int
1041 sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1043 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1044 u16 val = 0;
1046 if(!ivideo->lpcdev) return 0;
1048 pci_read_config_word(ivideo->lpcdev, reg, &val);
1049 return (unsigned int)val;
1051 #endif
1053 /* ----------- FBDev related routines for all series ----------- */
1055 static int
1056 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1058 return (var->bits_per_pixel == 8) ? 256 : 16;
1061 static void
1062 sisfb_set_vparms(struct sis_video_info *ivideo)
1064 switch(ivideo->video_bpp) {
1065 case 8:
1066 ivideo->DstColor = 0x0000;
1067 ivideo->SiS310_AccelDepth = 0x00000000;
1068 ivideo->video_cmap_len = 256;
1069 break;
1070 case 16:
1071 ivideo->DstColor = 0x8000;
1072 ivideo->SiS310_AccelDepth = 0x00010000;
1073 ivideo->video_cmap_len = 16;
1074 break;
1075 case 32:
1076 ivideo->DstColor = 0xC000;
1077 ivideo->SiS310_AccelDepth = 0x00020000;
1078 ivideo->video_cmap_len = 16;
1079 break;
1080 default:
1081 ivideo->video_cmap_len = 16;
1082 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1083 ivideo->accel = 0;
1087 static int
1088 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1090 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1092 if(maxyres > 32767) maxyres = 32767;
1094 return maxyres;
1097 static void
1098 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1100 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1101 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1102 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1103 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1104 ivideo->scrnpitchCRT1 <<= 1;
1109 static void
1110 sisfb_set_pitch(struct sis_video_info *ivideo)
1112 bool isslavemode = false;
1113 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1114 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1116 if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
1118 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1119 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1120 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1121 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1124 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1125 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1126 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1127 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1128 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1132 static void
1133 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1135 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1137 switch(var->bits_per_pixel) {
1138 case 8:
1139 var->red.offset = var->green.offset = var->blue.offset = 0;
1140 var->red.length = var->green.length = var->blue.length = 6;
1141 break;
1142 case 16:
1143 var->red.offset = 11;
1144 var->red.length = 5;
1145 var->green.offset = 5;
1146 var->green.length = 6;
1147 var->blue.offset = 0;
1148 var->blue.length = 5;
1149 var->transp.offset = 0;
1150 var->transp.length = 0;
1151 break;
1152 case 32:
1153 var->red.offset = 16;
1154 var->red.length = 8;
1155 var->green.offset = 8;
1156 var->green.length = 8;
1157 var->blue.offset = 0;
1158 var->blue.length = 8;
1159 var->transp.offset = 24;
1160 var->transp.length = 8;
1161 break;
1165 static int
1166 sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1168 unsigned short modeno = ivideo->mode_no;
1170 /* >=2.6.12's fbcon clears the screen anyway */
1171 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
1172 if(!clrscrn) modeno |= 0x80;
1173 #else
1174 modeno |= 0x80;
1175 #endif
1177 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1179 sisfb_pre_setmode(ivideo);
1181 if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
1182 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1183 return -EINVAL;
1186 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1188 sisfb_post_setmode(ivideo);
1190 return 0;
1194 static int
1195 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1197 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1198 unsigned int htotal = 0, vtotal = 0;
1199 unsigned int drate = 0, hrate = 0;
1200 int found_mode = 0, ret;
1201 int old_mode;
1202 u32 pixclock;
1204 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1206 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1208 pixclock = var->pixclock;
1210 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1211 vtotal += var->yres;
1212 vtotal <<= 1;
1213 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1214 vtotal += var->yres;
1215 vtotal <<= 2;
1216 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1217 vtotal += var->yres;
1218 vtotal <<= 1;
1219 } else vtotal += var->yres;
1221 if(!(htotal) || !(vtotal)) {
1222 DPRINTK("sisfb: Invalid 'var' information\n");
1223 return -EINVAL;
1226 if(pixclock && htotal && vtotal) {
1227 drate = 1000000000 / pixclock;
1228 hrate = (drate * 1000) / htotal;
1229 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1230 } else {
1231 ivideo->refresh_rate = 60;
1234 old_mode = ivideo->sisfb_mode_idx;
1235 ivideo->sisfb_mode_idx = 0;
1237 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1238 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1239 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1240 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1241 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1242 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1243 found_mode = 1;
1244 break;
1246 ivideo->sisfb_mode_idx++;
1249 if(found_mode) {
1250 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1251 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1252 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1253 } else {
1254 ivideo->sisfb_mode_idx = -1;
1257 if(ivideo->sisfb_mode_idx < 0) {
1258 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1259 var->yres, var->bits_per_pixel);
1260 ivideo->sisfb_mode_idx = old_mode;
1261 return -EINVAL;
1264 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1265 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1266 ivideo->refresh_rate = 60;
1269 if(isactive) {
1270 /* If acceleration to be used? Need to know
1271 * before pre/post_set_mode()
1273 ivideo->accel = 0;
1274 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1275 #ifdef STUPID_ACCELF_TEXT_SHIT
1276 if(var->accel_flags & FB_ACCELF_TEXT) {
1277 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1278 } else {
1279 info->flags |= FBINFO_HWACCEL_DISABLED;
1281 #endif
1282 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1283 #else
1284 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1285 #endif
1287 if((ret = sisfb_set_mode(ivideo, 1))) {
1288 return ret;
1291 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1292 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1293 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1295 sisfb_calc_pitch(ivideo, var);
1296 sisfb_set_pitch(ivideo);
1298 sisfb_set_vparms(ivideo);
1300 ivideo->current_width = ivideo->video_width;
1301 ivideo->current_height = ivideo->video_height;
1302 ivideo->current_bpp = ivideo->video_bpp;
1303 ivideo->current_htotal = htotal;
1304 ivideo->current_vtotal = vtotal;
1305 ivideo->current_linelength = ivideo->video_linelength;
1306 ivideo->current_pixclock = var->pixclock;
1307 ivideo->current_refresh_rate = ivideo->refresh_rate;
1308 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1311 return 0;
1314 static void
1315 sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1317 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1319 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1320 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1321 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1322 if(ivideo->sisvga_engine == SIS_315_VGA) {
1323 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1327 static void
1328 sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1330 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1331 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1332 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1333 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1334 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1335 if(ivideo->sisvga_engine == SIS_315_VGA) {
1336 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1341 static int
1342 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1344 if(var->xoffset > (var->xres_virtual - var->xres)) {
1345 return -EINVAL;
1347 if(var->yoffset > (var->yres_virtual - var->yres)) {
1348 return -EINVAL;
1351 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
1353 /* calculate base bpp dep. */
1354 switch(var->bits_per_pixel) {
1355 case 32:
1356 break;
1357 case 16:
1358 ivideo->current_base >>= 1;
1359 break;
1360 case 8:
1361 default:
1362 ivideo->current_base >>= 2;
1363 break;
1366 ivideo->current_base += (ivideo->video_offset >> 2);
1368 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1369 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1371 return 0;
1374 static int
1375 sisfb_open(struct fb_info *info, int user)
1377 return 0;
1380 static int
1381 sisfb_release(struct fb_info *info, int user)
1383 return 0;
1386 static int
1387 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1388 unsigned transp, struct fb_info *info)
1390 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1392 if(regno >= sisfb_get_cmap_len(&info->var))
1393 return 1;
1395 switch(info->var.bits_per_pixel) {
1396 case 8:
1397 outSISREG(SISDACA, regno);
1398 outSISREG(SISDACD, (red >> 10));
1399 outSISREG(SISDACD, (green >> 10));
1400 outSISREG(SISDACD, (blue >> 10));
1401 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1402 outSISREG(SISDAC2A, regno);
1403 outSISREG(SISDAC2D, (red >> 8));
1404 outSISREG(SISDAC2D, (green >> 8));
1405 outSISREG(SISDAC2D, (blue >> 8));
1407 break;
1408 case 16:
1409 ((u32 *)(info->pseudo_palette))[regno] =
1410 (red & 0xf800) |
1411 ((green & 0xfc00) >> 5) |
1412 ((blue & 0xf800) >> 11);
1413 break;
1414 case 32:
1415 red >>= 8;
1416 green >>= 8;
1417 blue >>= 8;
1418 ((u32 *)(info->pseudo_palette))[regno] =
1419 (red << 16) | (green << 8) | (blue);
1420 break;
1422 return 0;
1425 static int
1426 sisfb_set_par(struct fb_info *info)
1428 int err;
1430 if((err = sisfb_do_set_var(&info->var, 1, info)))
1431 return err;
1433 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1434 sisfb_get_fix(&info->fix, info->currcon, info);
1435 #else
1436 sisfb_get_fix(&info->fix, -1, info);
1437 #endif
1438 return 0;
1441 static int
1442 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1444 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1445 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1446 unsigned int drate = 0, hrate = 0, maxyres;
1447 int found_mode = 0;
1448 int refresh_rate, search_idx, tidx;
1449 bool recalc_clock = false;
1450 u32 pixclock;
1452 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1454 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1456 pixclock = var->pixclock;
1458 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1459 vtotal += var->yres;
1460 vtotal <<= 1;
1461 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1462 vtotal += var->yres;
1463 vtotal <<= 2;
1464 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1465 vtotal += var->yres;
1466 vtotal <<= 1;
1467 } else
1468 vtotal += var->yres;
1470 if(!(htotal) || !(vtotal)) {
1471 SISFAIL("sisfb: no valid timing data");
1474 search_idx = 0;
1475 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1476 (sisbios_mode[search_idx].xres <= var->xres) ) {
1477 if( (sisbios_mode[search_idx].xres == var->xres) &&
1478 (sisbios_mode[search_idx].yres == var->yres) &&
1479 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1480 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1481 ivideo->currentvbflags)) > 0) {
1482 found_mode = 1;
1483 search_idx = tidx;
1484 break;
1487 search_idx++;
1490 if(!found_mode) {
1491 search_idx = 0;
1492 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1493 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1494 (var->yres <= sisbios_mode[search_idx].yres) &&
1495 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1496 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1497 ivideo->currentvbflags)) > 0) {
1498 found_mode = 1;
1499 search_idx = tidx;
1500 break;
1503 search_idx++;
1505 if(found_mode) {
1506 printk(KERN_DEBUG
1507 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1508 var->xres, var->yres, var->bits_per_pixel,
1509 sisbios_mode[search_idx].xres,
1510 sisbios_mode[search_idx].yres,
1511 var->bits_per_pixel);
1512 var->xres = sisbios_mode[search_idx].xres;
1513 var->yres = sisbios_mode[search_idx].yres;
1514 } else {
1515 printk(KERN_ERR
1516 "sisfb: Failed to find supported mode near %dx%dx%d\n",
1517 var->xres, var->yres, var->bits_per_pixel);
1518 return -EINVAL;
1522 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1523 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1524 (var->bits_per_pixel == 8) ) {
1525 /* Slave modes on LVDS and 301B-DH */
1526 refresh_rate = 60;
1527 recalc_clock = true;
1528 } else if( (ivideo->current_htotal == htotal) &&
1529 (ivideo->current_vtotal == vtotal) &&
1530 (ivideo->current_pixclock == pixclock) ) {
1531 /* x=x & y=y & c=c -> assume depth change */
1532 drate = 1000000000 / pixclock;
1533 hrate = (drate * 1000) / htotal;
1534 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1535 } else if( ( (ivideo->current_htotal != htotal) ||
1536 (ivideo->current_vtotal != vtotal) ) &&
1537 (ivideo->current_pixclock == var->pixclock) ) {
1538 /* x!=x | y!=y & c=c -> invalid pixclock */
1539 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1540 refresh_rate =
1541 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1542 } else if(ivideo->sisfb_parm_rate != -1) {
1543 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1544 refresh_rate = ivideo->sisfb_parm_rate;
1545 } else {
1546 refresh_rate = 60;
1548 recalc_clock = true;
1549 } else if((pixclock) && (htotal) && (vtotal)) {
1550 drate = 1000000000 / pixclock;
1551 hrate = (drate * 1000) / htotal;
1552 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1553 } else if(ivideo->current_refresh_rate) {
1554 refresh_rate = ivideo->current_refresh_rate;
1555 recalc_clock = true;
1556 } else {
1557 refresh_rate = 60;
1558 recalc_clock = true;
1561 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1563 /* Eventually recalculate timing and clock */
1564 if(recalc_clock) {
1565 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1566 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1567 sisbios_mode[search_idx].mode_no[ivideo->mni],
1568 myrateindex));
1569 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1570 sisbios_mode[search_idx].mode_no[ivideo->mni],
1571 myrateindex, var);
1572 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1573 var->pixclock <<= 1;
1577 if(ivideo->sisfb_thismonitor.datavalid) {
1578 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1579 myrateindex, refresh_rate)) {
1580 printk(KERN_INFO
1581 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1585 /* Adapt RGB settings */
1586 sisfb_bpp_to_var(ivideo, var);
1588 /* Sanity check for offsets */
1589 if(var->xoffset < 0) var->xoffset = 0;
1590 if(var->yoffset < 0) var->yoffset = 0;
1592 if(var->xres > var->xres_virtual)
1593 var->xres_virtual = var->xres;
1595 if(ivideo->sisfb_ypan) {
1596 maxyres = sisfb_calc_maxyres(ivideo, var);
1597 if(ivideo->sisfb_max) {
1598 var->yres_virtual = maxyres;
1599 } else {
1600 if(var->yres_virtual > maxyres) {
1601 var->yres_virtual = maxyres;
1604 if(var->yres_virtual <= var->yres) {
1605 var->yres_virtual = var->yres;
1607 } else {
1608 if(var->yres != var->yres_virtual) {
1609 var->yres_virtual = var->yres;
1611 var->xoffset = 0;
1612 var->yoffset = 0;
1615 /* Truncate offsets to maximum if too high */
1616 if(var->xoffset > var->xres_virtual - var->xres) {
1617 var->xoffset = var->xres_virtual - var->xres - 1;
1620 if(var->yoffset > var->yres_virtual - var->yres) {
1621 var->yoffset = var->yres_virtual - var->yres - 1;
1624 /* Set everything else to 0 */
1625 var->red.msb_right =
1626 var->green.msb_right =
1627 var->blue.msb_right =
1628 var->transp.offset =
1629 var->transp.length =
1630 var->transp.msb_right = 0;
1632 return 0;
1635 static int
1636 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1638 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1639 int err;
1641 if(var->xoffset > (var->xres_virtual - var->xres))
1642 return -EINVAL;
1644 if(var->yoffset > (var->yres_virtual - var->yres))
1645 return -EINVAL;
1647 if(var->vmode & FB_VMODE_YWRAP)
1648 return -EINVAL;
1650 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
1651 var->yoffset + info->var.yres > info->var.yres_virtual)
1652 return -EINVAL;
1654 if((err = sisfb_pan_var(ivideo, var)) < 0)
1655 return err;
1657 info->var.xoffset = var->xoffset;
1658 info->var.yoffset = var->yoffset;
1660 return 0;
1663 static int
1664 sisfb_blank(int blank, struct fb_info *info)
1666 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1668 return sisfb_myblank(ivideo, blank);
1671 /* ----------- FBDev related routines for all series ---------- */
1673 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1674 static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1675 unsigned long arg)
1676 #else
1677 static int sisfb_ioctl(struct inode *inode, struct file *file,
1678 unsigned int cmd, unsigned long arg,
1679 struct fb_info *info)
1680 #endif
1682 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1683 struct sis_memreq sismemreq;
1684 struct fb_vblank sisvbblank;
1685 u32 gpu32 = 0;
1686 #ifndef __user
1687 #define __user
1688 #endif
1689 u32 __user *argp = (u32 __user *)arg;
1691 switch(cmd) {
1692 case FBIO_ALLOC:
1693 if(!capable(CAP_SYS_RAWIO))
1694 return -EPERM;
1696 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1697 return -EFAULT;
1699 sis_malloc(&sismemreq);
1701 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1702 sis_free((u32)sismemreq.offset);
1703 return -EFAULT;
1705 break;
1707 case FBIO_FREE:
1708 if(!capable(CAP_SYS_RAWIO))
1709 return -EPERM;
1711 if(get_user(gpu32, argp))
1712 return -EFAULT;
1714 sis_free(gpu32);
1715 break;
1717 case FBIOGET_VBLANK:
1718 sisvbblank.count = 0;
1719 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1721 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1722 return -EFAULT;
1724 break;
1726 case SISFB_GET_INFO_SIZE:
1727 return put_user(sizeof(struct sisfb_info), argp);
1729 case SISFB_GET_INFO_OLD:
1730 if(ivideo->warncount++ < 10)
1731 printk(KERN_INFO
1732 "sisfb: Deprecated ioctl call received - update your application!\n");
1733 case SISFB_GET_INFO: /* For communication with X driver */
1734 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1735 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1736 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1737 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1738 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1739 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1740 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1741 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1742 if(ivideo->modechanged) {
1743 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1744 } else {
1745 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1747 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1748 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1749 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1750 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1751 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1752 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1753 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1754 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1755 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1756 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1757 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1758 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1759 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1760 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1761 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1762 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1763 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1764 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1765 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1766 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1767 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1768 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1769 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1770 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1771 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1772 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1773 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1774 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1776 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1777 sizeof(ivideo->sisfb_infoblock)))
1778 return -EFAULT;
1780 break;
1782 case SISFB_GET_VBRSTATUS_OLD:
1783 if(ivideo->warncount++ < 10)
1784 printk(KERN_INFO
1785 "sisfb: Deprecated ioctl call received - update your application!\n");
1786 case SISFB_GET_VBRSTATUS:
1787 if(sisfb_CheckVBRetrace(ivideo))
1788 return put_user((u32)1, argp);
1789 else
1790 return put_user((u32)0, argp);
1792 case SISFB_GET_AUTOMAXIMIZE_OLD:
1793 if(ivideo->warncount++ < 10)
1794 printk(KERN_INFO
1795 "sisfb: Deprecated ioctl call received - update your application!\n");
1796 case SISFB_GET_AUTOMAXIMIZE:
1797 if(ivideo->sisfb_max)
1798 return put_user((u32)1, argp);
1799 else
1800 return put_user((u32)0, argp);
1802 case SISFB_SET_AUTOMAXIMIZE_OLD:
1803 if(ivideo->warncount++ < 10)
1804 printk(KERN_INFO
1805 "sisfb: Deprecated ioctl call received - update your application!\n");
1806 case SISFB_SET_AUTOMAXIMIZE:
1807 if(get_user(gpu32, argp))
1808 return -EFAULT;
1810 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1811 break;
1813 case SISFB_SET_TVPOSOFFSET:
1814 if(get_user(gpu32, argp))
1815 return -EFAULT;
1817 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1818 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1819 break;
1821 case SISFB_GET_TVPOSOFFSET:
1822 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1823 argp);
1825 case SISFB_COMMAND:
1826 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1827 sizeof(struct sisfb_cmd)))
1828 return -EFAULT;
1830 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1832 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1833 sizeof(struct sisfb_cmd)))
1834 return -EFAULT;
1836 break;
1838 case SISFB_SET_LOCK:
1839 if(get_user(gpu32, argp))
1840 return -EFAULT;
1842 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1843 break;
1845 default:
1846 #ifdef SIS_NEW_CONFIG_COMPAT
1847 return -ENOIOCTLCMD;
1848 #else
1849 return -EINVAL;
1850 #endif
1852 return 0;
1855 static int
1856 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1858 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1860 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1862 strcpy(fix->id, ivideo->myid);
1864 fix->smem_start = ivideo->video_base + ivideo->video_offset;
1865 fix->smem_len = ivideo->sisfb_mem;
1866 fix->type = FB_TYPE_PACKED_PIXELS;
1867 fix->type_aux = 0;
1868 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1869 fix->xpanstep = 1;
1870 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1871 fix->ywrapstep = 0;
1872 fix->line_length = ivideo->video_linelength;
1873 fix->mmio_start = ivideo->mmio_base;
1874 fix->mmio_len = ivideo->mmio_size;
1875 if(ivideo->sisvga_engine == SIS_300_VGA) {
1876 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1877 } else if((ivideo->chip == SIS_330) ||
1878 (ivideo->chip == SIS_760) ||
1879 (ivideo->chip == SIS_761)) {
1880 fix->accel = FB_ACCEL_SIS_XABRE;
1881 } else if(ivideo->chip == XGI_20) {
1882 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1883 } else if(ivideo->chip >= XGI_40) {
1884 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1885 } else {
1886 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1889 return 0;
1892 /* ---------------- fb_ops structures ----------------- */
1894 static struct fb_ops sisfb_ops = {
1895 .owner = THIS_MODULE,
1896 .fb_open = sisfb_open,
1897 .fb_release = sisfb_release,
1898 .fb_check_var = sisfb_check_var,
1899 .fb_set_par = sisfb_set_par,
1900 .fb_setcolreg = sisfb_setcolreg,
1901 .fb_pan_display = sisfb_pan_display,
1902 .fb_blank = sisfb_blank,
1903 .fb_fillrect = fbcon_sis_fillrect,
1904 .fb_copyarea = fbcon_sis_copyarea,
1905 .fb_imageblit = cfb_imageblit,
1906 #ifdef CONFIG_FB_SOFT_CURSOR
1907 .fb_cursor = soft_cursor,
1908 #endif
1909 .fb_sync = fbcon_sis_sync,
1910 #ifdef SIS_NEW_CONFIG_COMPAT
1911 .fb_compat_ioctl= sisfb_ioctl,
1912 #endif
1913 .fb_ioctl = sisfb_ioctl
1916 /* ---------------- Chip generation dependent routines ---------------- */
1918 static struct pci_dev * __devinit
1919 sisfb_get_northbridge(int basechipid)
1921 struct pci_dev *pdev = NULL;
1922 int nbridgenum, nbridgeidx, i;
1923 static const unsigned short nbridgeids[] = {
1924 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1925 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1926 PCI_DEVICE_ID_SI_730,
1927 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1928 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1929 PCI_DEVICE_ID_SI_651,
1930 PCI_DEVICE_ID_SI_740,
1931 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
1932 PCI_DEVICE_ID_SI_741,
1933 PCI_DEVICE_ID_SI_660,
1934 PCI_DEVICE_ID_SI_760,
1935 PCI_DEVICE_ID_SI_761
1938 switch(basechipid) {
1939 #ifdef CONFIG_FB_SIS_300
1940 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1941 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1942 #endif
1943 #ifdef CONFIG_FB_SIS_315
1944 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1945 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
1946 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
1947 #endif
1948 default: return NULL;
1950 for(i = 0; i < nbridgenum; i++) {
1951 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
1952 nbridgeids[nbridgeidx+i], NULL)))
1953 break;
1955 return pdev;
1958 static int __devinit
1959 sisfb_get_dram_size(struct sis_video_info *ivideo)
1961 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1962 u8 reg;
1963 #endif
1965 ivideo->video_size = 0;
1966 ivideo->UMAsize = ivideo->LFBsize = 0;
1968 switch(ivideo->chip) {
1969 #ifdef CONFIG_FB_SIS_300
1970 case SIS_300:
1971 inSISIDXREG(SISSR, 0x14, reg);
1972 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1973 break;
1974 case SIS_540:
1975 case SIS_630:
1976 case SIS_730:
1977 if(!ivideo->nbridge)
1978 return -1;
1979 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
1980 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1981 break;
1982 #endif
1983 #ifdef CONFIG_FB_SIS_315
1984 case SIS_315H:
1985 case SIS_315PRO:
1986 case SIS_315:
1987 inSISIDXREG(SISSR, 0x14, reg);
1988 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1989 switch((reg >> 2) & 0x03) {
1990 case 0x01:
1991 case 0x03:
1992 ivideo->video_size <<= 1;
1993 break;
1994 case 0x02:
1995 ivideo->video_size += (ivideo->video_size/2);
1997 break;
1998 case SIS_330:
1999 inSISIDXREG(SISSR, 0x14, reg);
2000 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2001 if(reg & 0x0c) ivideo->video_size <<= 1;
2002 break;
2003 case SIS_550:
2004 case SIS_650:
2005 case SIS_740:
2006 inSISIDXREG(SISSR, 0x14, reg);
2007 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2008 break;
2009 case SIS_661:
2010 case SIS_741:
2011 inSISIDXREG(SISCR, 0x79, reg);
2012 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2013 break;
2014 case SIS_660:
2015 case SIS_760:
2016 case SIS_761:
2017 inSISIDXREG(SISCR, 0x79, reg);
2018 reg = (reg & 0xf0) >> 4;
2019 if(reg) {
2020 ivideo->video_size = (1 << reg) << 20;
2021 ivideo->UMAsize = ivideo->video_size;
2023 inSISIDXREG(SISCR, 0x78, reg);
2024 reg &= 0x30;
2025 if(reg) {
2026 if(reg == 0x10) {
2027 ivideo->LFBsize = (32 << 20);
2028 } else {
2029 ivideo->LFBsize = (64 << 20);
2031 ivideo->video_size += ivideo->LFBsize;
2033 break;
2034 case SIS_340:
2035 case XGI_20:
2036 case XGI_40:
2037 inSISIDXREG(SISSR, 0x14, reg);
2038 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2039 if(ivideo->chip != XGI_20) {
2040 reg = (reg & 0x0c) >> 2;
2041 if(ivideo->revision_id == 2) {
2042 if(reg & 0x01) reg = 0x02;
2043 else reg = 0x00;
2045 if(reg == 0x02) ivideo->video_size <<= 1;
2046 else if(reg == 0x03) ivideo->video_size <<= 2;
2048 break;
2049 #endif
2050 default:
2051 return -1;
2053 return 0;
2056 /* -------------- video bridge device detection --------------- */
2058 static void __devinit
2059 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2061 u8 cr32, temp;
2063 /* No CRT2 on XGI Z7 */
2064 if(ivideo->chip == XGI_20) {
2065 ivideo->sisfb_crt1off = 0;
2066 return;
2069 #ifdef CONFIG_FB_SIS_300
2070 if(ivideo->sisvga_engine == SIS_300_VGA) {
2071 inSISIDXREG(SISSR, 0x17, temp);
2072 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2073 /* PAL/NTSC is stored on SR16 on such machines */
2074 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2075 inSISIDXREG(SISSR, 0x16, temp);
2076 if(temp & 0x20)
2077 ivideo->vbflags |= TV_PAL;
2078 else
2079 ivideo->vbflags |= TV_NTSC;
2083 #endif
2085 inSISIDXREG(SISCR, 0x32, cr32);
2087 if(cr32 & SIS_CRT1) {
2088 ivideo->sisfb_crt1off = 0;
2089 } else {
2090 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2093 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2095 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2096 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2097 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2099 /* Check given parms for hardware compatibility.
2100 * (Cannot do this in the search_xx routines since we don't
2101 * know what hardware we are running on then)
2104 if(ivideo->chip != SIS_550) {
2105 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2108 if(ivideo->sisfb_tvplug != -1) {
2109 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2110 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2111 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2112 ivideo->sisfb_tvplug = -1;
2113 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2117 if(ivideo->sisfb_tvplug != -1) {
2118 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2119 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2120 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2121 ivideo->sisfb_tvplug = -1;
2122 printk(KERN_ERR "sisfb: HiVision not supported\n");
2126 if(ivideo->sisfb_tvstd != -1) {
2127 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2128 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2129 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2130 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2131 ivideo->sisfb_tvstd = -1;
2132 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2137 /* Detect/set TV plug & type */
2138 if(ivideo->sisfb_tvplug != -1) {
2139 ivideo->vbflags |= ivideo->sisfb_tvplug;
2140 } else {
2141 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2142 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2143 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2144 else {
2145 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2146 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2150 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2151 if(ivideo->sisfb_tvstd != -1) {
2152 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2153 ivideo->vbflags |= ivideo->sisfb_tvstd;
2155 if(ivideo->vbflags & TV_SCART) {
2156 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2157 ivideo->vbflags |= TV_PAL;
2159 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2160 if(ivideo->sisvga_engine == SIS_300_VGA) {
2161 inSISIDXREG(SISSR, 0x38, temp);
2162 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2163 else ivideo->vbflags |= TV_NTSC;
2164 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2165 inSISIDXREG(SISSR, 0x38, temp);
2166 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2167 else ivideo->vbflags |= TV_NTSC;
2168 } else {
2169 inSISIDXREG(SISCR, 0x79, temp);
2170 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2171 else ivideo->vbflags |= TV_NTSC;
2176 /* Copy forceCRT1 option to CRT1off if option is given */
2177 if(ivideo->sisfb_forcecrt1 != -1) {
2178 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2182 /* ------------------ Sensing routines ------------------ */
2184 static bool __devinit
2185 sisfb_test_DDC1(struct sis_video_info *ivideo)
2187 unsigned short old;
2188 int count = 48;
2190 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2191 do {
2192 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2193 } while(count--);
2194 return (count != -1);
2197 static void __devinit
2198 sisfb_sense_crt1(struct sis_video_info *ivideo)
2200 bool mustwait = false;
2201 u8 sr1F, cr17;
2202 #ifdef CONFIG_FB_SIS_315
2203 u8 cr63=0;
2204 #endif
2205 u16 temp = 0xffff;
2206 int i;
2208 inSISIDXREG(SISSR,0x1F,sr1F);
2209 orSISIDXREG(SISSR,0x1F,0x04);
2210 andSISIDXREG(SISSR,0x1F,0x3F);
2211 if(sr1F & 0xc0) mustwait = true;
2213 #ifdef CONFIG_FB_SIS_315
2214 if(ivideo->sisvga_engine == SIS_315_VGA) {
2215 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2216 cr63 &= 0x40;
2217 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2219 #endif
2221 inSISIDXREG(SISCR,0x17,cr17);
2222 cr17 &= 0x80;
2223 if(!cr17) {
2224 orSISIDXREG(SISCR,0x17,0x80);
2225 mustwait = true;
2226 outSISIDXREG(SISSR, 0x00, 0x01);
2227 outSISIDXREG(SISSR, 0x00, 0x03);
2230 if(mustwait) {
2231 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2234 #ifdef CONFIG_FB_SIS_315
2235 if(ivideo->chip >= SIS_330) {
2236 andSISIDXREG(SISCR,0x32,~0x20);
2237 if(ivideo->chip >= SIS_340) {
2238 outSISIDXREG(SISCR, 0x57, 0x4a);
2239 } else {
2240 outSISIDXREG(SISCR, 0x57, 0x5f);
2242 orSISIDXREG(SISCR, 0x53, 0x02);
2243 while((inSISREG(SISINPSTAT)) & 0x01) break;
2244 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2245 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2246 andSISIDXREG(SISCR, 0x53, 0xfd);
2247 andSISIDXREG(SISCR, 0x57, 0x00);
2249 #endif
2251 if(temp == 0xffff) {
2252 i = 3;
2253 do {
2254 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2255 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2256 } while(((temp == 0) || (temp == 0xffff)) && i--);
2258 if((temp == 0) || (temp == 0xffff)) {
2259 if(sisfb_test_DDC1(ivideo)) temp = 1;
2263 if((temp) && (temp != 0xffff)) {
2264 orSISIDXREG(SISCR,0x32,0x20);
2267 #ifdef CONFIG_FB_SIS_315
2268 if(ivideo->sisvga_engine == SIS_315_VGA) {
2269 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2271 #endif
2273 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2275 outSISIDXREG(SISSR,0x1F,sr1F);
2278 /* Determine and detect attached devices on SiS30x */
2279 static void __devinit
2280 SiS_SenseLCD(struct sis_video_info *ivideo)
2282 unsigned char buffer[256];
2283 unsigned short temp, realcrtno, i;
2284 u8 reg, cr37 = 0, paneltype = 0;
2285 u16 xres, yres;
2287 ivideo->SiS_Pr.PanelSelfDetected = false;
2289 /* LCD detection only for TMDS bridges */
2290 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2291 return;
2292 if(ivideo->vbflags2 & VB2_30xBDH)
2293 return;
2295 /* If LCD already set up by BIOS, skip it */
2296 inSISIDXREG(SISCR, 0x32, reg);
2297 if(reg & 0x08)
2298 return;
2300 realcrtno = 1;
2301 if(ivideo->SiS_Pr.DDCPortMixup)
2302 realcrtno = 0;
2304 /* Check DDC capabilities */
2305 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2306 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2308 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2309 return;
2311 /* Read DDC data */
2312 i = 3; /* Number of retrys */
2313 do {
2314 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2315 ivideo->sisvga_engine, realcrtno, 1,
2316 &buffer[0], ivideo->vbflags2);
2317 } while((temp) && i--);
2319 if(temp)
2320 return;
2322 /* No digital device */
2323 if(!(buffer[0x14] & 0x80))
2324 return;
2326 /* First detailed timing preferred timing? */
2327 if(!(buffer[0x18] & 0x02))
2328 return;
2330 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2331 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2333 switch(xres) {
2334 case 1024:
2335 if(yres == 768)
2336 paneltype = 0x02;
2337 break;
2338 case 1280:
2339 if(yres == 1024)
2340 paneltype = 0x03;
2341 break;
2342 case 1600:
2343 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2344 paneltype = 0x0b;
2345 break;
2348 if(!paneltype)
2349 return;
2351 if(buffer[0x23])
2352 cr37 |= 0x10;
2354 if((buffer[0x47] & 0x18) == 0x18)
2355 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2356 else
2357 cr37 |= 0xc0;
2359 outSISIDXREG(SISCR, 0x36, paneltype);
2360 cr37 &= 0xf1;
2361 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2362 orSISIDXREG(SISCR, 0x32, 0x08);
2364 ivideo->SiS_Pr.PanelSelfDetected = true;
2367 static int __devinit
2368 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2370 int temp, mytest, result, i, j;
2372 for(j = 0; j < 10; j++) {
2373 result = 0;
2374 for(i = 0; i < 3; i++) {
2375 mytest = test;
2376 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2377 temp = (type >> 8) | (mytest & 0x00ff);
2378 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2379 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2380 mytest >>= 8;
2381 mytest &= 0x7f;
2382 inSISIDXREG(SISPART4,0x03,temp);
2383 temp ^= 0x0e;
2384 temp &= mytest;
2385 if(temp == mytest) result++;
2386 #if 1
2387 outSISIDXREG(SISPART4,0x11,0x00);
2388 andSISIDXREG(SISPART4,0x10,0xe0);
2389 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2390 #endif
2392 if((result == 0) || (result >= 2)) break;
2394 return result;
2397 static void __devinit
2398 SiS_Sense30x(struct sis_video_info *ivideo)
2400 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2401 u16 svhs=0, svhs_c=0;
2402 u16 cvbs=0, cvbs_c=0;
2403 u16 vga2=0, vga2_c=0;
2404 int myflag, result;
2405 char stdstr[] = "sisfb: Detected";
2406 char tvstr[] = "TV connected to";
2408 if(ivideo->vbflags2 & VB2_301) {
2409 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2410 inSISIDXREG(SISPART4,0x01,myflag);
2411 if(myflag & 0x04) {
2412 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2414 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2415 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2416 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2417 svhs = 0x0200; cvbs = 0x0100;
2418 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2419 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2420 } else
2421 return;
2423 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2424 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2425 svhs_c = 0x0408; cvbs_c = 0x0808;
2428 biosflag = 2;
2429 if(ivideo->haveXGIROM) {
2430 biosflag = ivideo->bios_abase[0x58] & 0x03;
2431 } else if(ivideo->newrom) {
2432 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2433 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2434 if(ivideo->bios_abase) {
2435 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2439 if(ivideo->chip == SIS_300) {
2440 inSISIDXREG(SISSR,0x3b,myflag);
2441 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2444 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2445 vga2 = vga2_c = 0;
2448 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2449 orSISIDXREG(SISSR,0x1e,0x20);
2451 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2452 if(ivideo->vbflags2 & VB2_30xC) {
2453 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2454 } else {
2455 orSISIDXREG(SISPART4,0x0d,0x04);
2457 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2459 inSISIDXREG(SISPART2,0x00,backupP2_00);
2460 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2462 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2463 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2464 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2467 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2468 SISDoSense(ivideo, 0, 0);
2471 andSISIDXREG(SISCR, 0x32, ~0x14);
2473 if(vga2_c || vga2) {
2474 if(SISDoSense(ivideo, vga2, vga2_c)) {
2475 if(biosflag & 0x01) {
2476 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2477 orSISIDXREG(SISCR, 0x32, 0x04);
2478 } else {
2479 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2480 orSISIDXREG(SISCR, 0x32, 0x10);
2485 andSISIDXREG(SISCR, 0x32, 0x3f);
2487 if(ivideo->vbflags2 & VB2_30xCLV) {
2488 orSISIDXREG(SISPART4,0x0d,0x04);
2491 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2492 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2493 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2494 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2495 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2496 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2497 orSISIDXREG(SISCR,0x32,0x80);
2500 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2503 andSISIDXREG(SISCR, 0x32, ~0x03);
2505 if(!(ivideo->vbflags & TV_YPBPR)) {
2506 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2507 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2508 orSISIDXREG(SISCR, 0x32, 0x02);
2510 if((biosflag & 0x02) || (!result)) {
2511 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2512 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2513 orSISIDXREG(SISCR, 0x32, 0x01);
2518 SISDoSense(ivideo, 0, 0);
2520 outSISIDXREG(SISPART2,0x00,backupP2_00);
2521 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2522 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2524 if(ivideo->vbflags2 & VB2_30xCLV) {
2525 inSISIDXREG(SISPART2,0x00,biosflag);
2526 if(biosflag & 0x20) {
2527 for(myflag = 2; myflag > 0; myflag--) {
2528 biosflag ^= 0x20;
2529 outSISIDXREG(SISPART2,0x00,biosflag);
2534 outSISIDXREG(SISPART2,0x00,backupP2_00);
2537 /* Determine and detect attached TV's on Chrontel */
2538 static void __devinit
2539 SiS_SenseCh(struct sis_video_info *ivideo)
2541 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2542 u8 temp1, temp2;
2543 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2544 #endif
2545 #ifdef CONFIG_FB_SIS_300
2546 unsigned char test[3];
2547 int i;
2548 #endif
2550 if(ivideo->chip < SIS_315H) {
2552 #ifdef CONFIG_FB_SIS_300
2553 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2554 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2555 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2556 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2557 /* See Chrontel TB31 for explanation */
2558 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2559 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2560 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2561 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2563 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2564 if(temp2 != temp1) temp1 = temp2;
2566 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2567 /* Read power status */
2568 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2569 if((temp1 & 0x03) != 0x03) {
2570 /* Power all outputs */
2571 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2572 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2574 /* Sense connected TV devices */
2575 for(i = 0; i < 3; i++) {
2576 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2577 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2578 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2579 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2580 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2581 if(!(temp1 & 0x08)) test[i] = 0x02;
2582 else if(!(temp1 & 0x02)) test[i] = 0x01;
2583 else test[i] = 0;
2584 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2587 if(test[0] == test[1]) temp1 = test[0];
2588 else if(test[0] == test[2]) temp1 = test[0];
2589 else if(test[1] == test[2]) temp1 = test[1];
2590 else {
2591 printk(KERN_INFO
2592 "sisfb: TV detection unreliable - test results varied\n");
2593 temp1 = test[2];
2595 if(temp1 == 0x02) {
2596 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2597 ivideo->vbflags |= TV_SVIDEO;
2598 orSISIDXREG(SISCR, 0x32, 0x02);
2599 andSISIDXREG(SISCR, 0x32, ~0x05);
2600 } else if (temp1 == 0x01) {
2601 printk(KERN_INFO "%s CVBS output\n", stdstr);
2602 ivideo->vbflags |= TV_AVIDEO;
2603 orSISIDXREG(SISCR, 0x32, 0x01);
2604 andSISIDXREG(SISCR, 0x32, ~0x06);
2605 } else {
2606 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2607 andSISIDXREG(SISCR, 0x32, ~0x07);
2609 } else if(temp1 == 0) {
2610 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2611 andSISIDXREG(SISCR, 0x32, ~0x07);
2613 /* Set general purpose IO for Chrontel communication */
2614 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2615 #endif
2617 } else {
2619 #ifdef CONFIG_FB_SIS_315
2620 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2621 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2622 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2623 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2624 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2625 temp2 |= 0x01;
2626 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2627 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2628 temp2 ^= 0x01;
2629 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2630 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2631 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2632 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2633 temp1 = 0;
2634 if(temp2 & 0x02) temp1 |= 0x01;
2635 if(temp2 & 0x10) temp1 |= 0x01;
2636 if(temp2 & 0x04) temp1 |= 0x02;
2637 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2638 switch(temp1) {
2639 case 0x01:
2640 printk(KERN_INFO "%s CVBS output\n", stdstr);
2641 ivideo->vbflags |= TV_AVIDEO;
2642 orSISIDXREG(SISCR, 0x32, 0x01);
2643 andSISIDXREG(SISCR, 0x32, ~0x06);
2644 break;
2645 case 0x02:
2646 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2647 ivideo->vbflags |= TV_SVIDEO;
2648 orSISIDXREG(SISCR, 0x32, 0x02);
2649 andSISIDXREG(SISCR, 0x32, ~0x05);
2650 break;
2651 case 0x04:
2652 printk(KERN_INFO "%s SCART output\n", stdstr);
2653 orSISIDXREG(SISCR, 0x32, 0x04);
2654 andSISIDXREG(SISCR, 0x32, ~0x03);
2655 break;
2656 default:
2657 andSISIDXREG(SISCR, 0x32, ~0x07);
2659 #endif
2663 static void __devinit
2664 sisfb_get_VB_type(struct sis_video_info *ivideo)
2666 char stdstr[] = "sisfb: Detected";
2667 char bridgestr[] = "video bridge";
2668 u8 vb_chipid;
2669 u8 reg;
2671 /* No CRT2 on XGI Z7 */
2672 if(ivideo->chip == XGI_20)
2673 return;
2675 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2676 switch(vb_chipid) {
2677 case 0x01:
2678 inSISIDXREG(SISPART4, 0x01, reg);
2679 if(reg < 0xb0) {
2680 ivideo->vbflags |= VB_301; /* Deprecated */
2681 ivideo->vbflags2 |= VB2_301;
2682 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2683 } else if(reg < 0xc0) {
2684 ivideo->vbflags |= VB_301B; /* Deprecated */
2685 ivideo->vbflags2 |= VB2_301B;
2686 inSISIDXREG(SISPART4,0x23,reg);
2687 if(!(reg & 0x02)) {
2688 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2689 ivideo->vbflags2 |= VB2_30xBDH;
2690 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2691 } else {
2692 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2694 } else if(reg < 0xd0) {
2695 ivideo->vbflags |= VB_301C; /* Deprecated */
2696 ivideo->vbflags2 |= VB2_301C;
2697 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2698 } else if(reg < 0xe0) {
2699 ivideo->vbflags |= VB_301LV; /* Deprecated */
2700 ivideo->vbflags2 |= VB2_301LV;
2701 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2702 } else if(reg <= 0xe1) {
2703 inSISIDXREG(SISPART4,0x39,reg);
2704 if(reg == 0xff) {
2705 ivideo->vbflags |= VB_302LV; /* Deprecated */
2706 ivideo->vbflags2 |= VB2_302LV;
2707 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2708 } else {
2709 ivideo->vbflags |= VB_301C; /* Deprecated */
2710 ivideo->vbflags2 |= VB2_301C;
2711 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2712 #if 0
2713 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2714 ivideo->vbflags2 |= VB2_302ELV;
2715 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2716 #endif
2719 break;
2720 case 0x02:
2721 ivideo->vbflags |= VB_302B; /* Deprecated */
2722 ivideo->vbflags2 |= VB2_302B;
2723 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2724 break;
2727 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2728 inSISIDXREG(SISCR, 0x37, reg);
2729 reg &= SIS_EXTERNAL_CHIP_MASK;
2730 reg >>= 1;
2731 if(ivideo->sisvga_engine == SIS_300_VGA) {
2732 #ifdef CONFIG_FB_SIS_300
2733 switch(reg) {
2734 case SIS_EXTERNAL_CHIP_LVDS:
2735 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2736 ivideo->vbflags2 |= VB2_LVDS;
2737 break;
2738 case SIS_EXTERNAL_CHIP_TRUMPION:
2739 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2740 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2741 break;
2742 case SIS_EXTERNAL_CHIP_CHRONTEL:
2743 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2744 ivideo->vbflags2 |= VB2_CHRONTEL;
2745 break;
2746 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2747 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2748 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2749 break;
2751 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2752 #endif
2753 } else if(ivideo->chip < SIS_661) {
2754 #ifdef CONFIG_FB_SIS_315
2755 switch (reg) {
2756 case SIS310_EXTERNAL_CHIP_LVDS:
2757 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2758 ivideo->vbflags2 |= VB2_LVDS;
2759 break;
2760 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2761 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2762 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2763 break;
2765 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2766 #endif
2767 } else if(ivideo->chip >= SIS_661) {
2768 #ifdef CONFIG_FB_SIS_315
2769 inSISIDXREG(SISCR, 0x38, reg);
2770 reg >>= 5;
2771 switch(reg) {
2772 case 0x02:
2773 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2774 ivideo->vbflags2 |= VB2_LVDS;
2775 break;
2776 case 0x03:
2777 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2778 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2779 break;
2780 case 0x04:
2781 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2782 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2783 break;
2785 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2786 #endif
2788 if(ivideo->vbflags2 & VB2_LVDS) {
2789 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2791 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2792 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2794 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2795 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2797 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2798 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2802 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2803 SiS_SenseLCD(ivideo);
2804 SiS_Sense30x(ivideo);
2805 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2806 SiS_SenseCh(ivideo);
2810 /* ---------- Engine initialization routines ------------ */
2812 static void
2813 sisfb_engine_init(struct sis_video_info *ivideo)
2816 /* Initialize command queue (we use MMIO only) */
2818 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2820 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2821 MMIO_CMD_QUEUE_CAP |
2822 VM_CMD_QUEUE_CAP |
2823 AGP_CMD_QUEUE_CAP);
2825 #ifdef CONFIG_FB_SIS_300
2826 if(ivideo->sisvga_engine == SIS_300_VGA) {
2827 u32 tqueue_pos;
2828 u8 tq_state;
2830 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2832 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2833 tq_state |= 0xf0;
2834 tq_state &= 0xfc;
2835 tq_state |= (u8)(tqueue_pos >> 8);
2836 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2838 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2840 ivideo->caps |= TURBO_QUEUE_CAP;
2842 #endif
2844 #ifdef CONFIG_FB_SIS_315
2845 if(ivideo->sisvga_engine == SIS_315_VGA) {
2846 u32 tempq = 0, templ;
2847 u8 temp;
2849 if(ivideo->chip == XGI_20) {
2850 switch(ivideo->cmdQueueSize) {
2851 case (64 * 1024):
2852 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2853 break;
2854 case (128 * 1024):
2855 default:
2856 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2858 } else {
2859 switch(ivideo->cmdQueueSize) {
2860 case (4 * 1024 * 1024):
2861 temp = SIS_CMD_QUEUE_SIZE_4M;
2862 break;
2863 case (2 * 1024 * 1024):
2864 temp = SIS_CMD_QUEUE_SIZE_2M;
2865 break;
2866 case (1 * 1024 * 1024):
2867 temp = SIS_CMD_QUEUE_SIZE_1M;
2868 break;
2869 default:
2870 case (512 * 1024):
2871 temp = SIS_CMD_QUEUE_SIZE_512k;
2875 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2876 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2878 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2879 /* Must disable dual pipe on XGI_40. Can't do
2880 * this in MMIO mode, because it requires
2881 * setting/clearing a bit in the MMIO fire trigger
2882 * register.
2884 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2886 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2888 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2890 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2891 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2893 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2894 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2896 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2897 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2898 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2899 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2901 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2903 sisfb_syncaccel(ivideo);
2905 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2910 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2911 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2913 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2914 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2916 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2917 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2919 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2921 #endif
2923 ivideo->engineok = 1;
2926 static void __devinit
2927 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2929 u8 reg;
2930 int i;
2932 inSISIDXREG(SISCR, 0x36, reg);
2933 reg &= 0x0f;
2934 if(ivideo->sisvga_engine == SIS_300_VGA) {
2935 ivideo->CRT2LCDType = sis300paneltype[reg];
2936 } else if(ivideo->chip >= SIS_661) {
2937 ivideo->CRT2LCDType = sis661paneltype[reg];
2938 } else {
2939 ivideo->CRT2LCDType = sis310paneltype[reg];
2940 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2941 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2942 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2943 ivideo->CRT2LCDType = LCD_320x240;
2948 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2949 /* For broken BIOSes: Assume 1024x768, RGB18 */
2950 ivideo->CRT2LCDType = LCD_1024x768;
2951 setSISIDXREG(SISCR,0x36,0xf0,0x02);
2952 setSISIDXREG(SISCR,0x37,0xee,0x01);
2953 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2956 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2957 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2958 ivideo->lcdxres = sis_lcd_data[i].xres;
2959 ivideo->lcdyres = sis_lcd_data[i].yres;
2960 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2961 break;
2965 #ifdef CONFIG_FB_SIS_300
2966 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2967 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2968 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2969 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2970 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2971 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2972 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2973 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2974 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2976 #endif
2978 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2979 ivideo->lcdxres, ivideo->lcdyres);
2982 static void __devinit
2983 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2985 #ifdef CONFIG_FB_SIS_300
2986 /* Save the current PanelDelayCompensation if the LCD is currently used */
2987 if(ivideo->sisvga_engine == SIS_300_VGA) {
2988 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2989 int tmp;
2990 inSISIDXREG(SISCR,0x30,tmp);
2991 if(tmp & 0x20) {
2992 /* Currently on LCD? If yes, read current pdc */
2993 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2994 ivideo->detectedpdc &= 0x3c;
2995 if(ivideo->SiS_Pr.PDC == -1) {
2996 /* Let option override detection */
2997 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2999 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3000 ivideo->detectedpdc);
3002 if((ivideo->SiS_Pr.PDC != -1) &&
3003 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3004 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3005 ivideo->SiS_Pr.PDC);
3009 #endif
3011 #ifdef CONFIG_FB_SIS_315
3012 if(ivideo->sisvga_engine == SIS_315_VGA) {
3014 /* Try to find about LCDA */
3015 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3016 int tmp;
3017 inSISIDXREG(SISPART1,0x13,tmp);
3018 if(tmp & 0x04) {
3019 ivideo->SiS_Pr.SiS_UseLCDA = true;
3020 ivideo->detectedlcda = 0x03;
3024 /* Save PDC */
3025 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3026 int tmp;
3027 inSISIDXREG(SISCR,0x30,tmp);
3028 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3029 /* Currently on LCD? If yes, read current pdc */
3030 u8 pdc;
3031 inSISIDXREG(SISPART1,0x2D,pdc);
3032 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3033 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3034 inSISIDXREG(SISPART1,0x35,pdc);
3035 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3036 inSISIDXREG(SISPART1,0x20,pdc);
3037 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3038 if(ivideo->newrom) {
3039 /* New ROM invalidates other PDC resp. */
3040 if(ivideo->detectedlcda != 0xff) {
3041 ivideo->detectedpdc = 0xff;
3042 } else {
3043 ivideo->detectedpdca = 0xff;
3046 if(ivideo->SiS_Pr.PDC == -1) {
3047 if(ivideo->detectedpdc != 0xff) {
3048 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3051 if(ivideo->SiS_Pr.PDCA == -1) {
3052 if(ivideo->detectedpdca != 0xff) {
3053 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3056 if(ivideo->detectedpdc != 0xff) {
3057 printk(KERN_INFO
3058 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3059 ivideo->detectedpdc);
3061 if(ivideo->detectedpdca != 0xff) {
3062 printk(KERN_INFO
3063 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3064 ivideo->detectedpdca);
3068 /* Save EMI */
3069 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3070 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3071 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3072 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3073 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3074 ivideo->SiS_Pr.HaveEMI = true;
3075 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3076 ivideo->SiS_Pr.HaveEMILCD = true;
3081 /* Let user override detected PDCs (all bridges) */
3082 if(ivideo->vbflags2 & VB2_30xBLV) {
3083 if((ivideo->SiS_Pr.PDC != -1) &&
3084 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3085 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3086 ivideo->SiS_Pr.PDC);
3088 if((ivideo->SiS_Pr.PDCA != -1) &&
3089 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3090 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3091 ivideo->SiS_Pr.PDCA);
3096 #endif
3099 /* -------------------- Memory manager routines ---------------------- */
3101 static u32 __devinit
3102 sisfb_getheapstart(struct sis_video_info *ivideo)
3104 u32 ret = ivideo->sisfb_parm_mem * 1024;
3105 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3106 u32 def;
3108 /* Calculate heap start = end of memory for console
3110 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3111 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3113 * On 76x in UMA+LFB mode, the layout is as follows:
3114 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3115 * where the heap is the entire UMA area, eventually
3116 * into the LFB area if the given mem parameter is
3117 * higher than the size of the UMA memory.
3119 * Basically given by "mem" parameter
3121 * maximum = videosize - cmd_queue - hwcursor
3122 * (results in a heap of size 0)
3123 * default = SiS 300: depends on videosize
3124 * SiS 315/330/340/XGI: 32k below max
3127 if(ivideo->sisvga_engine == SIS_300_VGA) {
3128 if(ivideo->video_size > 0x1000000) {
3129 def = 0xc00000;
3130 } else if(ivideo->video_size > 0x800000) {
3131 def = 0x800000;
3132 } else {
3133 def = 0x400000;
3135 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3136 ret = def = 0;
3137 } else {
3138 def = maxoffs - 0x8000;
3141 /* Use default for secondary card for now (FIXME) */
3142 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3143 ret = def;
3145 return ret;
3148 static u32 __devinit
3149 sisfb_getheapsize(struct sis_video_info *ivideo)
3151 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3152 u32 ret = 0;
3154 if(ivideo->UMAsize && ivideo->LFBsize) {
3155 if( (!ivideo->sisfb_parm_mem) ||
3156 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3157 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3158 ret = ivideo->UMAsize;
3159 max -= ivideo->UMAsize;
3160 } else {
3161 ret = max - (ivideo->sisfb_parm_mem * 1024);
3162 max = ivideo->sisfb_parm_mem * 1024;
3164 ivideo->video_offset = ret;
3165 ivideo->sisfb_mem = max;
3166 } else {
3167 ret = max - ivideo->heapstart;
3168 ivideo->sisfb_mem = ivideo->heapstart;
3171 return ret;
3174 static int __devinit
3175 sisfb_heap_init(struct sis_video_info *ivideo)
3177 struct SIS_OH *poh;
3179 ivideo->video_offset = 0;
3180 if(ivideo->sisfb_parm_mem) {
3181 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3182 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3183 ivideo->sisfb_parm_mem = 0;
3187 ivideo->heapstart = sisfb_getheapstart(ivideo);
3188 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3190 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3191 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3193 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3194 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3196 ivideo->sisfb_heap.vinfo = ivideo;
3198 ivideo->sisfb_heap.poha_chain = NULL;
3199 ivideo->sisfb_heap.poh_freelist = NULL;
3201 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3202 if(poh == NULL)
3203 return 1;
3205 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3206 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3207 poh->size = ivideo->sisfb_heap_size;
3208 poh->offset = ivideo->heapstart;
3210 ivideo->sisfb_heap.oh_free.poh_next = poh;
3211 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3212 ivideo->sisfb_heap.oh_free.size = 0;
3213 ivideo->sisfb_heap.max_freesize = poh->size;
3215 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3216 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3217 ivideo->sisfb_heap.oh_used.size = SENTINEL;
3219 if(ivideo->cardnumber == 0) {
3220 /* For the first card, make this heap the "global" one
3221 * for old DRM (which could handle only one card)
3223 sisfb_heap = &ivideo->sisfb_heap;
3226 return 0;
3229 static struct SIS_OH *
3230 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3232 struct SIS_OHALLOC *poha;
3233 struct SIS_OH *poh;
3234 unsigned long cOhs;
3235 int i;
3237 if(memheap->poh_freelist == NULL) {
3238 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3239 if(!poha)
3240 return NULL;
3242 poha->poha_next = memheap->poha_chain;
3243 memheap->poha_chain = poha;
3245 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3247 poh = &poha->aoh[0];
3248 for(i = cOhs - 1; i != 0; i--) {
3249 poh->poh_next = poh + 1;
3250 poh = poh + 1;
3253 poh->poh_next = NULL;
3254 memheap->poh_freelist = &poha->aoh[0];
3257 poh = memheap->poh_freelist;
3258 memheap->poh_freelist = poh->poh_next;
3260 return poh;
3263 static struct SIS_OH *
3264 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3266 struct SIS_OH *pohThis;
3267 struct SIS_OH *pohRoot;
3268 int bAllocated = 0;
3270 if(size > memheap->max_freesize) {
3271 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3272 (unsigned int) size / 1024);
3273 return NULL;
3276 pohThis = memheap->oh_free.poh_next;
3278 while(pohThis != &memheap->oh_free) {
3279 if(size <= pohThis->size) {
3280 bAllocated = 1;
3281 break;
3283 pohThis = pohThis->poh_next;
3286 if(!bAllocated) {
3287 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3288 (unsigned int) size / 1024);
3289 return NULL;
3292 if(size == pohThis->size) {
3293 pohRoot = pohThis;
3294 sisfb_delete_node(pohThis);
3295 } else {
3296 pohRoot = sisfb_poh_new_node(memheap);
3297 if(pohRoot == NULL)
3298 return NULL;
3300 pohRoot->offset = pohThis->offset;
3301 pohRoot->size = size;
3303 pohThis->offset += size;
3304 pohThis->size -= size;
3307 memheap->max_freesize -= size;
3309 pohThis = &memheap->oh_used;
3310 sisfb_insert_node(pohThis, pohRoot);
3312 return pohRoot;
3315 static void
3316 sisfb_delete_node(struct SIS_OH *poh)
3318 poh->poh_prev->poh_next = poh->poh_next;
3319 poh->poh_next->poh_prev = poh->poh_prev;
3322 static void
3323 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3325 struct SIS_OH *pohTemp = pohList->poh_next;
3327 pohList->poh_next = poh;
3328 pohTemp->poh_prev = poh;
3330 poh->poh_prev = pohList;
3331 poh->poh_next = pohTemp;
3334 static struct SIS_OH *
3335 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3337 struct SIS_OH *pohThis;
3338 struct SIS_OH *poh_freed;
3339 struct SIS_OH *poh_prev;
3340 struct SIS_OH *poh_next;
3341 u32 ulUpper;
3342 u32 ulLower;
3343 int foundNode = 0;
3345 poh_freed = memheap->oh_used.poh_next;
3347 while(poh_freed != &memheap->oh_used) {
3348 if(poh_freed->offset == base) {
3349 foundNode = 1;
3350 break;
3353 poh_freed = poh_freed->poh_next;
3356 if(!foundNode)
3357 return NULL;
3359 memheap->max_freesize += poh_freed->size;
3361 poh_prev = poh_next = NULL;
3362 ulUpper = poh_freed->offset + poh_freed->size;
3363 ulLower = poh_freed->offset;
3365 pohThis = memheap->oh_free.poh_next;
3367 while(pohThis != &memheap->oh_free) {
3368 if(pohThis->offset == ulUpper) {
3369 poh_next = pohThis;
3370 } else if((pohThis->offset + pohThis->size) == ulLower) {
3371 poh_prev = pohThis;
3373 pohThis = pohThis->poh_next;
3376 sisfb_delete_node(poh_freed);
3378 if(poh_prev && poh_next) {
3379 poh_prev->size += (poh_freed->size + poh_next->size);
3380 sisfb_delete_node(poh_next);
3381 sisfb_free_node(memheap, poh_freed);
3382 sisfb_free_node(memheap, poh_next);
3383 return poh_prev;
3386 if(poh_prev) {
3387 poh_prev->size += poh_freed->size;
3388 sisfb_free_node(memheap, poh_freed);
3389 return poh_prev;
3392 if(poh_next) {
3393 poh_next->size += poh_freed->size;
3394 poh_next->offset = poh_freed->offset;
3395 sisfb_free_node(memheap, poh_freed);
3396 return poh_next;
3399 sisfb_insert_node(&memheap->oh_free, poh_freed);
3401 return poh_freed;
3404 static void
3405 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3407 if(poh == NULL)
3408 return;
3410 poh->poh_next = memheap->poh_freelist;
3411 memheap->poh_freelist = poh;
3414 static void
3415 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3417 struct SIS_OH *poh = NULL;
3419 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3420 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3422 if(poh == NULL) {
3423 req->offset = req->size = 0;
3424 DPRINTK("sisfb: Video RAM allocation failed\n");
3425 } else {
3426 req->offset = poh->offset;
3427 req->size = poh->size;
3428 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3429 (poh->offset + ivideo->video_vbase));
3433 void
3434 sis_malloc(struct sis_memreq *req)
3436 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3438 if(&ivideo->sisfb_heap == sisfb_heap)
3439 sis_int_malloc(ivideo, req);
3440 else
3441 req->offset = req->size = 0;
3444 void
3445 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3447 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3449 sis_int_malloc(ivideo, req);
3452 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3454 static void
3455 sis_int_free(struct sis_video_info *ivideo, u32 base)
3457 struct SIS_OH *poh;
3459 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3460 return;
3462 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3464 if(poh == NULL) {
3465 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3466 (unsigned int) base);
3470 void
3471 sis_free(u32 base)
3473 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3475 sis_int_free(ivideo, base);
3478 void
3479 sis_free_new(struct pci_dev *pdev, u32 base)
3481 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3483 sis_int_free(ivideo, base);
3486 /* --------------------- SetMode routines ------------------------- */
3488 static void
3489 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3491 u8 cr30, cr31;
3493 /* Check if MMIO and engines are enabled,
3494 * and sync in case they are. Can't use
3495 * ivideo->accel here, as this might have
3496 * been changed before this is called.
3498 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3499 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3500 /* MMIO and 2D/3D engine enabled? */
3501 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3502 #ifdef CONFIG_FB_SIS_300
3503 if(ivideo->sisvga_engine == SIS_300_VGA) {
3504 /* Don't care about TurboQueue. It's
3505 * enough to know that the engines
3506 * are enabled
3508 sisfb_syncaccel(ivideo);
3510 #endif
3511 #ifdef CONFIG_FB_SIS_315
3512 if(ivideo->sisvga_engine == SIS_315_VGA) {
3513 /* Check that any queue mode is
3514 * enabled, and that the queue
3515 * is not in the state of "reset"
3517 inSISIDXREG(SISSR, 0x26, cr30);
3518 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3519 sisfb_syncaccel(ivideo);
3522 #endif
3526 static void
3527 sisfb_pre_setmode(struct sis_video_info *ivideo)
3529 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3530 int tvregnum = 0;
3532 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3534 outSISIDXREG(SISSR, 0x05, 0x86);
3536 inSISIDXREG(SISCR, 0x31, cr31);
3537 cr31 &= ~0x60;
3538 cr31 |= 0x04;
3540 cr33 = ivideo->rate_idx & 0x0F;
3542 #ifdef CONFIG_FB_SIS_315
3543 if(ivideo->sisvga_engine == SIS_315_VGA) {
3544 if(ivideo->chip >= SIS_661) {
3545 inSISIDXREG(SISCR, 0x38, cr38);
3546 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3547 } else {
3548 tvregnum = 0x38;
3549 inSISIDXREG(SISCR, tvregnum, cr38);
3550 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3553 #endif
3554 #ifdef CONFIG_FB_SIS_300
3555 if(ivideo->sisvga_engine == SIS_300_VGA) {
3556 tvregnum = 0x35;
3557 inSISIDXREG(SISCR, tvregnum, cr38);
3559 #endif
3561 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3562 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
3563 ivideo->curFSTN = ivideo->curDSTN = 0;
3565 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3567 case CRT2_TV:
3568 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3569 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3570 #ifdef CONFIG_FB_SIS_315
3571 if(ivideo->chip >= SIS_661) {
3572 cr38 |= 0x04;
3573 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3574 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3575 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3576 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3577 cr35 &= ~0x01;
3578 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3579 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3580 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3581 cr38 |= 0x08;
3582 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3583 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3584 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3585 cr31 &= ~0x01;
3586 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3588 #endif
3589 } else if((ivideo->vbflags & TV_HIVISION) &&
3590 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3591 if(ivideo->chip >= SIS_661) {
3592 cr38 |= 0x04;
3593 cr35 |= 0x60;
3594 } else {
3595 cr30 |= 0x80;
3597 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3598 cr31 |= 0x01;
3599 cr35 |= 0x01;
3600 ivideo->currentvbflags |= TV_HIVISION;
3601 } else if(ivideo->vbflags & TV_SCART) {
3602 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3603 cr31 |= 0x01;
3604 cr35 |= 0x01;
3605 ivideo->currentvbflags |= TV_SCART;
3606 } else {
3607 if(ivideo->vbflags & TV_SVIDEO) {
3608 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3609 ivideo->currentvbflags |= TV_SVIDEO;
3611 if(ivideo->vbflags & TV_AVIDEO) {
3612 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3613 ivideo->currentvbflags |= TV_AVIDEO;
3616 cr31 |= SIS_DRIVER_MODE;
3618 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3619 if(ivideo->vbflags & TV_PAL) {
3620 cr31 |= 0x01; cr35 |= 0x01;
3621 ivideo->currentvbflags |= TV_PAL;
3622 if(ivideo->vbflags & TV_PALM) {
3623 cr38 |= 0x40; cr35 |= 0x04;
3624 ivideo->currentvbflags |= TV_PALM;
3625 } else if(ivideo->vbflags & TV_PALN) {
3626 cr38 |= 0x80; cr35 |= 0x08;
3627 ivideo->currentvbflags |= TV_PALN;
3629 } else {
3630 cr31 &= ~0x01; cr35 &= ~0x01;
3631 ivideo->currentvbflags |= TV_NTSC;
3632 if(ivideo->vbflags & TV_NTSCJ) {
3633 cr38 |= 0x40; cr35 |= 0x02;
3634 ivideo->currentvbflags |= TV_NTSCJ;
3638 break;
3640 case CRT2_LCD:
3641 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3642 cr31 |= SIS_DRIVER_MODE;
3643 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3644 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3645 ivideo->curFSTN = ivideo->sisfb_fstn;
3646 ivideo->curDSTN = ivideo->sisfb_dstn;
3647 break;
3649 case CRT2_VGA:
3650 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3651 cr31 |= SIS_DRIVER_MODE;
3652 if(ivideo->sisfb_nocrt2rate) {
3653 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3654 } else {
3655 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3657 break;
3659 default: /* disable CRT2 */
3660 cr30 = 0x00;
3661 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3664 outSISIDXREG(SISCR, 0x30, cr30);
3665 outSISIDXREG(SISCR, 0x33, cr33);
3667 if(ivideo->chip >= SIS_661) {
3668 #ifdef CONFIG_FB_SIS_315
3669 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3670 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3671 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3672 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3673 #endif
3674 } else if(ivideo->chip != SIS_300) {
3675 outSISIDXREG(SISCR, tvregnum, cr38);
3677 outSISIDXREG(SISCR, 0x31, cr31);
3679 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3681 sisfb_check_engine_and_sync(ivideo);
3684 /* Fix SR11 for 661 and later */
3685 #ifdef CONFIG_FB_SIS_315
3686 static void
3687 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3689 u8 tmpreg;
3691 if(ivideo->chip >= SIS_661) {
3692 inSISIDXREG(SISSR,0x11,tmpreg);
3693 if(tmpreg & 0x20) {
3694 inSISIDXREG(SISSR,0x3e,tmpreg);
3695 tmpreg = (tmpreg + 1) & 0xff;
3696 outSISIDXREG(SISSR,0x3e,tmpreg);
3697 inSISIDXREG(SISSR,0x11,tmpreg);
3699 if(tmpreg & 0xf0) {
3700 andSISIDXREG(SISSR,0x11,0x0f);
3704 #endif
3706 static void
3707 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3709 if(val > 32) val = 32;
3710 if(val < -32) val = -32;
3711 ivideo->tvxpos = val;
3713 if(ivideo->sisfblocked) return;
3714 if(!ivideo->modechanged) return;
3716 if(ivideo->currentvbflags & CRT2_TV) {
3718 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3720 int x = ivideo->tvx;
3722 switch(ivideo->chronteltype) {
3723 case 1:
3724 x += val;
3725 if(x < 0) x = 0;
3726 outSISIDXREG(SISSR,0x05,0x86);
3727 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3728 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3729 break;
3730 case 2:
3731 /* Not supported by hardware */
3732 break;
3735 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3737 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3738 unsigned short temp;
3740 p2_1f = ivideo->p2_1f;
3741 p2_20 = ivideo->p2_20;
3742 p2_2b = ivideo->p2_2b;
3743 p2_42 = ivideo->p2_42;
3744 p2_43 = ivideo->p2_43;
3746 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3747 temp += (val * 2);
3748 p2_1f = temp & 0xff;
3749 p2_20 = (temp & 0xf00) >> 4;
3750 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3751 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3752 temp += (val * 2);
3753 p2_43 = temp & 0xff;
3754 p2_42 = (temp & 0xf00) >> 4;
3755 outSISIDXREG(SISPART2,0x1f,p2_1f);
3756 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3757 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3758 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3759 outSISIDXREG(SISPART2,0x43,p2_43);
3764 static void
3765 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3767 if(val > 32) val = 32;
3768 if(val < -32) val = -32;
3769 ivideo->tvypos = val;
3771 if(ivideo->sisfblocked) return;
3772 if(!ivideo->modechanged) return;
3774 if(ivideo->currentvbflags & CRT2_TV) {
3776 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3778 int y = ivideo->tvy;
3780 switch(ivideo->chronteltype) {
3781 case 1:
3782 y -= val;
3783 if(y < 0) y = 0;
3784 outSISIDXREG(SISSR,0x05,0x86);
3785 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3786 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3787 break;
3788 case 2:
3789 /* Not supported by hardware */
3790 break;
3793 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3795 char p2_01, p2_02;
3796 val /= 2;
3797 p2_01 = ivideo->p2_01;
3798 p2_02 = ivideo->p2_02;
3800 p2_01 += val;
3801 p2_02 += val;
3802 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3803 while((p2_01 <= 0) || (p2_02 <= 0)) {
3804 p2_01 += 2;
3805 p2_02 += 2;
3808 outSISIDXREG(SISPART2,0x01,p2_01);
3809 outSISIDXREG(SISPART2,0x02,p2_02);
3814 static void
3815 sisfb_post_setmode(struct sis_video_info *ivideo)
3817 bool crt1isoff = false;
3818 bool doit = true;
3819 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3820 u8 reg;
3821 #endif
3822 #ifdef CONFIG_FB_SIS_315
3823 u8 reg1;
3824 #endif
3826 outSISIDXREG(SISSR, 0x05, 0x86);
3828 #ifdef CONFIG_FB_SIS_315
3829 sisfb_fixup_SR11(ivideo);
3830 #endif
3832 /* Now we actually HAVE changed the display mode */
3833 ivideo->modechanged = 1;
3835 /* We can't switch off CRT1 if bridge is in slave mode */
3836 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3837 if(sisfb_bridgeisslave(ivideo)) doit = false;
3838 } else
3839 ivideo->sisfb_crt1off = 0;
3841 #ifdef CONFIG_FB_SIS_300
3842 if(ivideo->sisvga_engine == SIS_300_VGA) {
3843 if((ivideo->sisfb_crt1off) && (doit)) {
3844 crt1isoff = true;
3845 reg = 0x00;
3846 } else {
3847 crt1isoff = false;
3848 reg = 0x80;
3850 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3852 #endif
3853 #ifdef CONFIG_FB_SIS_315
3854 if(ivideo->sisvga_engine == SIS_315_VGA) {
3855 if((ivideo->sisfb_crt1off) && (doit)) {
3856 crt1isoff = true;
3857 reg = 0x40;
3858 reg1 = 0xc0;
3859 } else {
3860 crt1isoff = false;
3861 reg = 0x00;
3862 reg1 = 0x00;
3864 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3865 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3867 #endif
3869 if(crt1isoff) {
3870 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3871 ivideo->currentvbflags |= VB_SINGLE_MODE;
3872 } else {
3873 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3874 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3875 ivideo->currentvbflags |= VB_MIRROR_MODE;
3876 } else {
3877 ivideo->currentvbflags |= VB_SINGLE_MODE;
3881 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3883 if(ivideo->currentvbflags & CRT2_TV) {
3884 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3885 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3886 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3887 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3888 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3889 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3890 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3891 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3892 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3893 if(ivideo->chronteltype == 1) {
3894 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3895 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3896 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3897 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3902 if(ivideo->tvxpos) {
3903 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3905 if(ivideo->tvypos) {
3906 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3909 /* Eventually sync engines */
3910 sisfb_check_engine_and_sync(ivideo);
3912 /* (Re-)Initialize chip engines */
3913 if(ivideo->accel) {
3914 sisfb_engine_init(ivideo);
3915 } else {
3916 ivideo->engineok = 0;
3920 static int
3921 sisfb_reset_mode(struct sis_video_info *ivideo)
3923 if(sisfb_set_mode(ivideo, 0))
3924 return 1;
3926 sisfb_set_pitch(ivideo);
3927 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3928 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3930 return 0;
3933 static void
3934 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3936 int mycrt1off;
3938 switch(sisfb_command->sisfb_cmd) {
3939 case SISFB_CMD_GETVBFLAGS:
3940 if(!ivideo->modechanged) {
3941 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3942 } else {
3943 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3944 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3945 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
3947 break;
3948 case SISFB_CMD_SWITCHCRT1:
3949 /* arg[0]: 0 = off, 1 = on, 99 = query */
3950 if(!ivideo->modechanged) {
3951 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3952 } else if(sisfb_command->sisfb_arg[0] == 99) {
3953 /* Query */
3954 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3955 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3956 } else if(ivideo->sisfblocked) {
3957 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3958 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3959 (sisfb_command->sisfb_arg[0] == 0)) {
3960 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3961 } else {
3962 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3963 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3964 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3965 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3966 ivideo->sisfb_crt1off = mycrt1off;
3967 if(sisfb_reset_mode(ivideo)) {
3968 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
3971 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3973 break;
3974 /* more to come */
3975 default:
3976 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3977 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3978 sisfb_command->sisfb_cmd);
3982 #ifndef MODULE
3983 SISINITSTATIC int __init
3984 sisfb_setup(char *options)
3986 char *this_opt;
3988 sisfb_setdefaultparms();
3990 if(!options || !(*options))
3991 return 0;
3993 while((this_opt = strsep(&options, ",")) != NULL) {
3995 if(!(*this_opt)) continue;
3997 if(!strnicmp(this_opt, "off", 3)) {
3998 sisfb_off = 1;
3999 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4000 /* Need to check crt2 type first for fstn/dstn */
4001 sisfb_search_crt2type(this_opt + 14);
4002 } else if(!strnicmp(this_opt, "tvmode:",7)) {
4003 sisfb_search_tvstd(this_opt + 7);
4004 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4005 sisfb_search_tvstd(this_opt + 11);
4006 } else if(!strnicmp(this_opt, "mode:", 5)) {
4007 sisfb_search_mode(this_opt + 5, false);
4008 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4009 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
4010 } else if(!strnicmp(this_opt, "rate:", 5)) {
4011 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4012 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4013 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4014 } else if(!strnicmp(this_opt, "mem:",4)) {
4015 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4016 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4017 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4018 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4019 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4020 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4021 sisfb_accel = 0;
4022 } else if(!strnicmp(this_opt, "accel", 5)) {
4023 sisfb_accel = -1;
4024 } else if(!strnicmp(this_opt, "noypan", 6)) {
4025 sisfb_ypan = 0;
4026 } else if(!strnicmp(this_opt, "ypan", 4)) {
4027 sisfb_ypan = -1;
4028 } else if(!strnicmp(this_opt, "nomax", 5)) {
4029 sisfb_max = 0;
4030 } else if(!strnicmp(this_opt, "max", 3)) {
4031 sisfb_max = -1;
4032 } else if(!strnicmp(this_opt, "userom:", 7)) {
4033 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4034 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4035 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4036 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4037 sisfb_nocrt2rate = 1;
4038 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4039 unsigned long temp = 2;
4040 temp = simple_strtoul(this_opt + 9, NULL, 0);
4041 if((temp == 0) || (temp == 1)) {
4042 sisfb_scalelcd = temp ^ 1;
4044 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4045 int temp = 0;
4046 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4047 if((temp >= -32) && (temp <= 32)) {
4048 sisfb_tvxposoffset = temp;
4050 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4051 int temp = 0;
4052 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4053 if((temp >= -32) && (temp <= 32)) {
4054 sisfb_tvyposoffset = temp;
4056 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4057 sisfb_search_specialtiming(this_opt + 14);
4058 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4059 int temp = 4;
4060 temp = simple_strtoul(this_opt + 7, NULL, 0);
4061 if((temp >= 0) && (temp <= 3)) {
4062 sisfb_lvdshl = temp;
4064 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4065 sisfb_search_mode(this_opt, true);
4066 #if !defined(__i386__) && !defined(__x86_64__)
4067 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4068 sisfb_resetcard = 1;
4069 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4070 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4071 #endif
4072 } else {
4073 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4078 return 0;
4080 #endif
4082 static int __devinit
4083 sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4085 SIS_IOTYPE1 *rom;
4086 int romptr;
4088 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4089 return 0;
4091 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4092 if(romptr > (0x10000 - 8))
4093 return 0;
4095 rom = rom_base + romptr;
4097 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4098 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4099 return 0;
4101 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4102 return 0;
4104 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4105 return 0;
4107 return 1;
4110 static unsigned char * __devinit
4111 sisfb_find_rom(struct pci_dev *pdev)
4113 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4114 SIS_IOTYPE1 *rom_base;
4115 unsigned char *myrombase = NULL;
4116 u32 temp;
4117 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4118 size_t romsize;
4120 /* First, try the official pci ROM functions (except
4121 * on integrated chipsets which have no ROM).
4124 if(!ivideo->nbridge) {
4126 if((rom_base = pci_map_rom(pdev, &romsize))) {
4128 if(sisfb_check_rom(rom_base, ivideo)) {
4130 if((myrombase = vmalloc(65536))) {
4132 /* Work around bug in pci/rom.c: Folks forgot to check
4133 * whether the size retrieved from the BIOS image eventually
4134 * is larger than the mapped size
4136 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4137 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4139 memcpy_fromio(myrombase, rom_base,
4140 (romsize > 65536) ? 65536 : romsize);
4143 pci_unmap_rom(pdev, rom_base);
4147 if(myrombase) return myrombase;
4148 #endif
4150 /* Otherwise do it the conventional way. */
4152 #if defined(__i386__) || defined(__x86_64__)
4154 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4156 rom_base = ioremap(temp, 65536);
4157 if(!rom_base)
4158 continue;
4160 if(!sisfb_check_rom(rom_base, ivideo)) {
4161 iounmap(rom_base);
4162 continue;
4165 if((myrombase = vmalloc(65536)))
4166 memcpy_fromio(myrombase, rom_base, 65536);
4168 iounmap(rom_base);
4169 break;
4173 #else
4175 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4176 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4177 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4179 rom_base = ioremap(ivideo->video_base, 65536);
4180 if(rom_base) {
4181 if(sisfb_check_rom(rom_base, ivideo)) {
4182 if((myrombase = vmalloc(65536)))
4183 memcpy_fromio(myrombase, rom_base, 65536);
4185 iounmap(rom_base);
4188 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4190 #endif
4192 return myrombase;
4195 static void __devinit
4196 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4197 unsigned int min)
4199 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4201 if(!ivideo->video_vbase) {
4202 printk(KERN_ERR
4203 "sisfb: Unable to map maximum video RAM for size detection\n");
4204 (*mapsize) >>= 1;
4205 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4206 (*mapsize) >>= 1;
4207 if((*mapsize) < (min << 20))
4208 break;
4210 if(ivideo->video_vbase) {
4211 printk(KERN_ERR
4212 "sisfb: Video RAM size detection limited to %dMB\n",
4213 (int)((*mapsize) >> 20));
4218 #ifdef CONFIG_FB_SIS_300
4219 static int __devinit
4220 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4222 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4223 unsigned short temp;
4224 unsigned char reg;
4225 int i, j;
4227 andSISIDXREG(SISSR, 0x15, 0xFB);
4228 orSISIDXREG(SISSR, 0x15, 0x04);
4229 outSISIDXREG(SISSR, 0x13, 0x00);
4230 outSISIDXREG(SISSR, 0x14, 0xBF);
4232 for(i = 0; i < 2; i++) {
4233 temp = 0x1234;
4234 for(j = 0; j < 4; j++) {
4235 writew(temp, FBAddress);
4236 if(readw(FBAddress) == temp)
4237 break;
4238 orSISIDXREG(SISSR, 0x3c, 0x01);
4239 inSISIDXREG(SISSR, 0x05, reg);
4240 inSISIDXREG(SISSR, 0x05, reg);
4241 andSISIDXREG(SISSR, 0x3c, 0xfe);
4242 inSISIDXREG(SISSR, 0x05, reg);
4243 inSISIDXREG(SISSR, 0x05, reg);
4244 temp++;
4248 writel(0x01234567L, FBAddress);
4249 writel(0x456789ABL, (FBAddress + 4));
4250 writel(0x89ABCDEFL, (FBAddress + 8));
4251 writel(0xCDEF0123L, (FBAddress + 12));
4253 inSISIDXREG(SISSR, 0x3b, reg);
4254 if(reg & 0x01) {
4255 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4256 return 4; /* Channel A 128bit */
4259 if(readl((FBAddress + 4)) == 0x456789ABL)
4260 return 2; /* Channel B 64bit */
4262 return 1; /* 32bit */
4265 static int __devinit
4266 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4267 int PseudoRankCapacity, int PseudoAdrPinCount,
4268 unsigned int mapsize)
4270 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4271 unsigned short sr14;
4272 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4273 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4274 static const unsigned short SiS_DRAMType[17][5] = {
4275 {0x0C,0x0A,0x02,0x40,0x39},
4276 {0x0D,0x0A,0x01,0x40,0x48},
4277 {0x0C,0x09,0x02,0x20,0x35},
4278 {0x0D,0x09,0x01,0x20,0x44},
4279 {0x0C,0x08,0x02,0x10,0x31},
4280 {0x0D,0x08,0x01,0x10,0x40},
4281 {0x0C,0x0A,0x01,0x20,0x34},
4282 {0x0C,0x09,0x01,0x08,0x32},
4283 {0x0B,0x08,0x02,0x08,0x21},
4284 {0x0C,0x08,0x01,0x08,0x30},
4285 {0x0A,0x08,0x02,0x04,0x11},
4286 {0x0B,0x0A,0x01,0x10,0x28},
4287 {0x09,0x08,0x02,0x02,0x01},
4288 {0x0B,0x09,0x01,0x08,0x24},
4289 {0x0B,0x08,0x01,0x04,0x20},
4290 {0x0A,0x08,0x01,0x02,0x10},
4291 {0x09,0x08,0x01,0x01,0x00}
4294 for(k = 0; k <= 16; k++) {
4296 RankCapacity = buswidth * SiS_DRAMType[k][3];
4298 if(RankCapacity != PseudoRankCapacity)
4299 continue;
4301 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4302 continue;
4304 BankNumHigh = RankCapacity * 16 * iteration - 1;
4305 if(iteration == 3) { /* Rank No */
4306 BankNumMid = RankCapacity * 16 - 1;
4307 } else {
4308 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4311 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4312 PhysicalAdrHigh = BankNumHigh;
4313 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4314 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4316 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4317 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4318 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4319 if(buswidth == 4) sr14 |= 0x80;
4320 else if(buswidth == 2) sr14 |= 0x40;
4321 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4322 outSISIDXREG(SISSR, 0x14, sr14);
4324 BankNumHigh <<= 16;
4325 BankNumMid <<= 16;
4327 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4328 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4329 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4330 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4331 continue;
4333 /* Write data */
4334 writew(((unsigned short)PhysicalAdrHigh),
4335 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4336 writew(((unsigned short)BankNumMid),
4337 (FBAddr + BankNumMid + PhysicalAdrHigh));
4338 writew(((unsigned short)PhysicalAdrHalfPage),
4339 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4340 writew(((unsigned short)PhysicalAdrOtherPage),
4341 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4343 /* Read data */
4344 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4345 return 1;
4348 return 0;
4351 static void __devinit
4352 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4354 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4355 int i, j, buswidth;
4356 int PseudoRankCapacity, PseudoAdrPinCount;
4358 buswidth = sisfb_post_300_buswidth(ivideo);
4360 for(i = 6; i >= 0; i--) {
4361 PseudoRankCapacity = 1 << i;
4362 for(j = 4; j >= 1; j--) {
4363 PseudoAdrPinCount = 15 - j;
4364 if((PseudoRankCapacity * j) <= 64) {
4365 if(sisfb_post_300_rwtest(ivideo,
4367 buswidth,
4368 PseudoRankCapacity,
4369 PseudoAdrPinCount,
4370 mapsize))
4371 return;
4377 static void __devinit
4378 sisfb_post_sis300(struct pci_dev *pdev)
4380 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4381 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4382 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4383 u16 index, rindex, memtype = 0;
4384 unsigned int mapsize;
4386 if(!ivideo->SiS_Pr.UseROM)
4387 bios = NULL;
4389 outSISIDXREG(SISSR, 0x05, 0x86);
4391 if(bios) {
4392 if(bios[0x52] & 0x80) {
4393 memtype = bios[0x52];
4394 } else {
4395 inSISIDXREG(SISSR, 0x3a, memtype);
4397 memtype &= 0x07;
4400 v3 = 0x80; v6 = 0x80;
4401 if(ivideo->revision_id <= 0x13) {
4402 v1 = 0x44; v2 = 0x42;
4403 v4 = 0x44; v5 = 0x42;
4404 } else {
4405 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4406 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4407 if(bios) {
4408 index = memtype * 5;
4409 rindex = index + 0x54;
4410 v1 = bios[rindex++];
4411 v2 = bios[rindex++];
4412 v3 = bios[rindex++];
4413 rindex = index + 0x7c;
4414 v4 = bios[rindex++];
4415 v5 = bios[rindex++];
4416 v6 = bios[rindex++];
4419 outSISIDXREG(SISSR, 0x28, v1);
4420 outSISIDXREG(SISSR, 0x29, v2);
4421 outSISIDXREG(SISSR, 0x2a, v3);
4422 outSISIDXREG(SISSR, 0x2e, v4);
4423 outSISIDXREG(SISSR, 0x2f, v5);
4424 outSISIDXREG(SISSR, 0x30, v6);
4426 v1 = 0x10;
4427 if(bios)
4428 v1 = bios[0xa4];
4429 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4431 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4433 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4434 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4435 if(bios) {
4436 memtype += 0xa5;
4437 v1 = bios[memtype];
4438 v2 = bios[memtype + 8];
4439 v3 = bios[memtype + 16];
4440 v4 = bios[memtype + 24];
4441 v5 = bios[memtype + 32];
4442 v6 = bios[memtype + 40];
4443 v7 = bios[memtype + 48];
4444 v8 = bios[memtype + 56];
4446 if(ivideo->revision_id >= 0x80)
4447 v3 &= 0xfd;
4448 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4449 outSISIDXREG(SISSR, 0x16, v2);
4450 outSISIDXREG(SISSR, 0x17, v3);
4451 outSISIDXREG(SISSR, 0x18, v4);
4452 outSISIDXREG(SISSR, 0x19, v5);
4453 outSISIDXREG(SISSR, 0x1a, v6);
4454 outSISIDXREG(SISSR, 0x1b, v7);
4455 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4456 andSISIDXREG(SISSR, 0x15 ,0xfb);
4457 orSISIDXREG(SISSR, 0x15, 0x04);
4458 if(bios) {
4459 if(bios[0x53] & 0x02) {
4460 orSISIDXREG(SISSR, 0x19, 0x20);
4463 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4464 if(ivideo->revision_id >= 0x80)
4465 v1 |= 0x01;
4466 outSISIDXREG(SISSR, 0x1f, v1);
4467 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4468 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4469 if(bios) {
4470 v1 = bios[0xe8];
4471 v2 = bios[0xe9];
4472 v3 = bios[0xea];
4474 outSISIDXREG(SISSR, 0x23, v1);
4475 outSISIDXREG(SISSR, 0x24, v2);
4476 outSISIDXREG(SISSR, 0x25, v3);
4477 outSISIDXREG(SISSR, 0x21, 0x84);
4478 outSISIDXREG(SISSR, 0x22, 0x00);
4479 outSISIDXREG(SISCR, 0x37, 0x00);
4480 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4481 outSISIDXREG(SISPART1, 0x00, 0x00);
4482 v1 = 0x40; v2 = 0x11;
4483 if(bios) {
4484 v1 = bios[0xec];
4485 v2 = bios[0xeb];
4487 outSISIDXREG(SISPART1, 0x02, v1);
4489 if(ivideo->revision_id >= 0x80)
4490 v2 &= ~0x01;
4492 inSISIDXREG(SISPART4, 0x00, reg);
4493 if((reg == 1) || (reg == 2)) {
4494 outSISIDXREG(SISCR, 0x37, 0x02);
4495 outSISIDXREG(SISPART2, 0x00, 0x1c);
4496 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4497 if(ivideo->SiS_Pr.UseROM) {
4498 v4 = bios[0xf5];
4499 v5 = bios[0xf6];
4500 v6 = bios[0xf7];
4502 outSISIDXREG(SISPART4, 0x0d, v4);
4503 outSISIDXREG(SISPART4, 0x0e, v5);
4504 outSISIDXREG(SISPART4, 0x10, v6);
4505 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4506 inSISIDXREG(SISPART4, 0x01, reg);
4507 if(reg >= 0xb0) {
4508 inSISIDXREG(SISPART4, 0x23, reg);
4509 reg &= 0x20;
4510 reg <<= 1;
4511 outSISIDXREG(SISPART4, 0x23, reg);
4513 } else {
4514 v2 &= ~0x10;
4516 outSISIDXREG(SISSR, 0x32, v2);
4518 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4520 inSISIDXREG(SISSR, 0x16, reg);
4521 reg &= 0xc3;
4522 outSISIDXREG(SISCR, 0x35, reg);
4523 outSISIDXREG(SISCR, 0x83, 0x00);
4524 #if !defined(__i386__) && !defined(__x86_64__)
4525 if(sisfb_videoram) {
4526 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4527 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4528 outSISIDXREG(SISSR, 0x14, reg);
4529 } else {
4530 #endif
4531 /* Need to map max FB size for finding out about RAM size */
4532 mapsize = 64 << 20;
4533 sisfb_post_map_vram(ivideo, &mapsize, 4);
4535 if(ivideo->video_vbase) {
4536 sisfb_post_300_ramsize(pdev, mapsize);
4537 iounmap(ivideo->video_vbase);
4538 } else {
4539 printk(KERN_DEBUG
4540 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4541 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4542 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4544 #if !defined(__i386__) && !defined(__x86_64__)
4546 #endif
4547 if(bios) {
4548 v1 = bios[0xe6];
4549 v2 = bios[0xe7];
4550 } else {
4551 inSISIDXREG(SISSR, 0x3a, reg);
4552 if((reg & 0x30) == 0x30) {
4553 v1 = 0x04; /* PCI */
4554 v2 = 0x92;
4555 } else {
4556 v1 = 0x14; /* AGP */
4557 v2 = 0xb2;
4560 outSISIDXREG(SISSR, 0x21, v1);
4561 outSISIDXREG(SISSR, 0x22, v2);
4563 /* Sense CRT1 */
4564 sisfb_sense_crt1(ivideo);
4566 /* Set default mode, don't clear screen */
4567 ivideo->SiS_Pr.SiS_UseOEM = false;
4568 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4569 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
4570 ivideo->curFSTN = ivideo->curDSTN = 0;
4571 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4572 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4574 outSISIDXREG(SISSR, 0x05, 0x86);
4576 /* Display off */
4577 orSISIDXREG(SISSR, 0x01, 0x20);
4579 /* Save mode number in CR34 */
4580 outSISIDXREG(SISCR, 0x34, 0x2e);
4582 /* Let everyone know what the current mode is */
4583 ivideo->modeprechange = 0x2e;
4585 #endif
4587 #ifdef CONFIG_FB_SIS_315
4588 #if 0
4589 static void __devinit
4590 sisfb_post_sis315330(struct pci_dev *pdev)
4592 /* TODO */
4594 #endif
4596 static void __devinit
4597 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4599 unsigned int i;
4600 u8 reg;
4602 for(i = 0; i <= (delay * 10 * 36); i++) {
4603 inSISIDXREG(SISSR, 0x05, reg);
4604 reg++;
4608 static int __devinit
4609 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4610 unsigned short pcivendor)
4612 struct pci_dev *pdev = NULL;
4613 unsigned short temp;
4614 int ret = 0;
4616 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4617 temp = pdev->vendor;
4618 SIS_PCI_PUT_DEVICE(pdev);
4619 if(temp == pcivendor) {
4620 ret = 1;
4621 break;
4625 return ret;
4628 static int __devinit
4629 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4630 unsigned int enda, unsigned int mapsize)
4632 unsigned int pos;
4633 int i;
4635 writel(0, ivideo->video_vbase);
4637 for(i = starta; i <= enda; i++) {
4638 pos = 1 << i;
4639 if(pos < mapsize)
4640 writel(pos, ivideo->video_vbase + pos);
4643 sisfb_post_xgi_delay(ivideo, 150);
4645 if(readl(ivideo->video_vbase) != 0)
4646 return 0;
4648 for(i = starta; i <= enda; i++) {
4649 pos = 1 << i;
4650 if(pos < mapsize) {
4651 if(readl(ivideo->video_vbase + pos) != pos)
4652 return 0;
4653 } else
4654 return 0;
4657 return 1;
4660 static void __devinit
4661 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4663 unsigned int buswidth, ranksize, channelab, mapsize;
4664 int i, j, k, l;
4665 u8 reg, sr14;
4666 static const u8 dramsr13[12 * 5] = {
4667 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4668 0x02, 0x0e, 0x0a, 0x40, 0x59,
4669 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4670 0x02, 0x0e, 0x09, 0x20, 0x55,
4671 0x02, 0x0d, 0x0a, 0x20, 0x49,
4672 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4673 0x02, 0x0e, 0x08, 0x10, 0x51,
4674 0x02, 0x0d, 0x09, 0x10, 0x45,
4675 0x02, 0x0c, 0x0a, 0x10, 0x39,
4676 0x02, 0x0d, 0x08, 0x08, 0x41,
4677 0x02, 0x0c, 0x09, 0x08, 0x35,
4678 0x02, 0x0c, 0x08, 0x04, 0x31
4680 static const u8 dramsr13_4[4 * 5] = {
4681 0x02, 0x0d, 0x09, 0x40, 0x45,
4682 0x02, 0x0c, 0x09, 0x20, 0x35,
4683 0x02, 0x0c, 0x08, 0x10, 0x31,
4684 0x02, 0x0b, 0x08, 0x08, 0x21
4687 /* Enable linear mode, disable 0xa0000 address decoding */
4688 /* We disable a0000 address decoding, because
4689 * - if running on x86, if the card is disabled, it means
4690 * that another card is in the system. We don't want
4691 * to interphere with that primary card's textmode.
4692 * - if running on non-x86, there usually is no VGA window
4693 * at a0000.
4695 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4697 /* Need to map max FB size for finding out about RAM size */
4698 mapsize = 256 << 20;
4699 sisfb_post_map_vram(ivideo, &mapsize, 32);
4701 if(!ivideo->video_vbase) {
4702 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4703 outSISIDXREG(SISSR, 0x13, 0x35);
4704 outSISIDXREG(SISSR, 0x14, 0x41);
4705 /* TODO */
4706 return;
4709 /* Non-interleaving */
4710 outSISIDXREG(SISSR, 0x15, 0x00);
4711 /* No tiling */
4712 outSISIDXREG(SISSR, 0x1c, 0x00);
4714 if(ivideo->chip == XGI_20) {
4716 channelab = 1;
4717 inSISIDXREG(SISCR, 0x97, reg);
4718 if(!(reg & 0x01)) { /* Single 32/16 */
4719 buswidth = 32;
4720 outSISIDXREG(SISSR, 0x13, 0xb1);
4721 outSISIDXREG(SISSR, 0x14, 0x52);
4722 sisfb_post_xgi_delay(ivideo, 1);
4723 sr14 = 0x02;
4724 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4725 goto bail_out;
4727 outSISIDXREG(SISSR, 0x13, 0x31);
4728 outSISIDXREG(SISSR, 0x14, 0x42);
4729 sisfb_post_xgi_delay(ivideo, 1);
4730 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4731 goto bail_out;
4733 buswidth = 16;
4734 outSISIDXREG(SISSR, 0x13, 0xb1);
4735 outSISIDXREG(SISSR, 0x14, 0x41);
4736 sisfb_post_xgi_delay(ivideo, 1);
4737 sr14 = 0x01;
4738 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4739 goto bail_out;
4740 else
4741 outSISIDXREG(SISSR, 0x13, 0x31);
4742 } else { /* Dual 16/8 */
4743 buswidth = 16;
4744 outSISIDXREG(SISSR, 0x13, 0xb1);
4745 outSISIDXREG(SISSR, 0x14, 0x41);
4746 sisfb_post_xgi_delay(ivideo, 1);
4747 sr14 = 0x01;
4748 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4749 goto bail_out;
4751 outSISIDXREG(SISSR, 0x13, 0x31);
4752 outSISIDXREG(SISSR, 0x14, 0x31);
4753 sisfb_post_xgi_delay(ivideo, 1);
4754 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4755 goto bail_out;
4757 buswidth = 8;
4758 outSISIDXREG(SISSR, 0x13, 0xb1);
4759 outSISIDXREG(SISSR, 0x14, 0x30);
4760 sisfb_post_xgi_delay(ivideo, 1);
4761 sr14 = 0x00;
4762 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4763 goto bail_out;
4764 else
4765 outSISIDXREG(SISSR, 0x13, 0x31);
4768 } else { /* XGI_40 */
4770 inSISIDXREG(SISCR, 0x97, reg);
4771 if(!(reg & 0x10)) {
4772 inSISIDXREG(SISSR, 0x39, reg);
4773 reg >>= 1;
4776 if(reg & 0x01) { /* DDRII */
4777 buswidth = 32;
4778 if(ivideo->revision_id == 2) {
4779 channelab = 2;
4780 outSISIDXREG(SISSR, 0x13, 0xa1);
4781 outSISIDXREG(SISSR, 0x14, 0x44);
4782 sr14 = 0x04;
4783 sisfb_post_xgi_delay(ivideo, 1);
4784 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4785 goto bail_out;
4787 outSISIDXREG(SISSR, 0x13, 0x21);
4788 outSISIDXREG(SISSR, 0x14, 0x34);
4789 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4790 goto bail_out;
4792 channelab = 1;
4793 outSISIDXREG(SISSR, 0x13, 0xa1);
4794 outSISIDXREG(SISSR, 0x14, 0x40);
4795 sr14 = 0x00;
4796 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4797 goto bail_out;
4799 outSISIDXREG(SISSR, 0x13, 0x21);
4800 outSISIDXREG(SISSR, 0x14, 0x30);
4801 } else {
4802 channelab = 3;
4803 outSISIDXREG(SISSR, 0x13, 0xa1);
4804 outSISIDXREG(SISSR, 0x14, 0x4c);
4805 sr14 = 0x0c;
4806 sisfb_post_xgi_delay(ivideo, 1);
4807 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4808 goto bail_out;
4810 channelab = 2;
4811 outSISIDXREG(SISSR, 0x14, 0x48);
4812 sisfb_post_xgi_delay(ivideo, 1);
4813 sr14 = 0x08;
4814 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4815 goto bail_out;
4817 outSISIDXREG(SISSR, 0x13, 0x21);
4818 outSISIDXREG(SISSR, 0x14, 0x3c);
4819 sr14 = 0x0c;
4821 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4822 channelab = 3;
4823 } else {
4824 channelab = 2;
4825 outSISIDXREG(SISSR, 0x14, 0x38);
4826 sr14 = 0x08;
4829 sisfb_post_xgi_delay(ivideo, 1);
4831 } else { /* DDR */
4833 buswidth = 64;
4834 if(ivideo->revision_id == 2) {
4835 channelab = 1;
4836 outSISIDXREG(SISSR, 0x13, 0xa1);
4837 outSISIDXREG(SISSR, 0x14, 0x52);
4838 sisfb_post_xgi_delay(ivideo, 1);
4839 sr14 = 0x02;
4840 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4841 goto bail_out;
4843 outSISIDXREG(SISSR, 0x13, 0x21);
4844 outSISIDXREG(SISSR, 0x14, 0x42);
4845 } else {
4846 channelab = 2;
4847 outSISIDXREG(SISSR, 0x13, 0xa1);
4848 outSISIDXREG(SISSR, 0x14, 0x5a);
4849 sisfb_post_xgi_delay(ivideo, 1);
4850 sr14 = 0x0a;
4851 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4852 goto bail_out;
4854 outSISIDXREG(SISSR, 0x13, 0x21);
4855 outSISIDXREG(SISSR, 0x14, 0x4a);
4857 sisfb_post_xgi_delay(ivideo, 1);
4862 bail_out:
4863 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4864 sisfb_post_xgi_delay(ivideo, 1);
4866 j = (ivideo->chip == XGI_20) ? 5 : 9;
4867 k = (ivideo->chip == XGI_20) ? 12 : 4;
4869 for(i = 0; i < k; i++) {
4871 reg = (ivideo->chip == XGI_20) ?
4872 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4873 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4874 sisfb_post_xgi_delay(ivideo, 50);
4876 ranksize = (ivideo->chip == XGI_20) ?
4877 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4879 inSISIDXREG(SISSR, 0x13, reg);
4880 if(reg & 0x80) ranksize <<= 1;
4882 if(ivideo->chip == XGI_20) {
4883 if(buswidth == 16) ranksize <<= 1;
4884 else if(buswidth == 32) ranksize <<= 2;
4885 } else {
4886 if(buswidth == 64) ranksize <<= 1;
4889 reg = 0;
4890 l = channelab;
4891 if(l == 3) l = 4;
4892 if((ranksize * l) <= 256) {
4893 while((ranksize >>= 1)) reg += 0x10;
4896 if(!reg) continue;
4898 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4899 sisfb_post_xgi_delay(ivideo, 1);
4901 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4902 break;
4905 iounmap(ivideo->video_vbase);
4908 static void __devinit
4909 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4911 u8 v1, v2, v3;
4912 int index;
4913 static const u8 cs90[8 * 3] = {
4914 0x16, 0x01, 0x01,
4915 0x3e, 0x03, 0x01,
4916 0x7c, 0x08, 0x01,
4917 0x79, 0x06, 0x01,
4918 0x29, 0x01, 0x81,
4919 0x5c, 0x23, 0x01,
4920 0x5c, 0x23, 0x01,
4921 0x5c, 0x23, 0x01
4923 static const u8 csb8[8 * 3] = {
4924 0x5c, 0x23, 0x01,
4925 0x29, 0x01, 0x01,
4926 0x7c, 0x08, 0x01,
4927 0x79, 0x06, 0x01,
4928 0x29, 0x01, 0x81,
4929 0x5c, 0x23, 0x01,
4930 0x5c, 0x23, 0x01,
4931 0x5c, 0x23, 0x01
4934 regb = 0; /* ! */
4936 index = regb * 3;
4937 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4938 if(ivideo->haveXGIROM) {
4939 v1 = ivideo->bios_abase[0x90 + index];
4940 v2 = ivideo->bios_abase[0x90 + index + 1];
4941 v3 = ivideo->bios_abase[0x90 + index + 2];
4943 outSISIDXREG(SISSR, 0x28, v1);
4944 outSISIDXREG(SISSR, 0x29, v2);
4945 outSISIDXREG(SISSR, 0x2a, v3);
4946 sisfb_post_xgi_delay(ivideo, 0x43);
4947 sisfb_post_xgi_delay(ivideo, 0x43);
4948 sisfb_post_xgi_delay(ivideo, 0x43);
4949 index = regb * 3;
4950 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4951 if(ivideo->haveXGIROM) {
4952 v1 = ivideo->bios_abase[0xb8 + index];
4953 v2 = ivideo->bios_abase[0xb8 + index + 1];
4954 v3 = ivideo->bios_abase[0xb8 + index + 2];
4956 outSISIDXREG(SISSR, 0x2e, v1);
4957 outSISIDXREG(SISSR, 0x2f, v2);
4958 outSISIDXREG(SISSR, 0x30, v3);
4959 sisfb_post_xgi_delay(ivideo, 0x43);
4960 sisfb_post_xgi_delay(ivideo, 0x43);
4961 sisfb_post_xgi_delay(ivideo, 0x43);
4964 static int __devinit
4965 sisfb_post_xgi(struct pci_dev *pdev)
4967 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4968 unsigned char *bios = ivideo->bios_abase;
4969 struct pci_dev *mypdev = NULL;
4970 const u8 *ptr, *ptr2;
4971 u8 v1, v2, v3, v4, v5, reg, ramtype;
4972 u32 rega, regb, regd;
4973 int i, j, k, index;
4974 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4975 static const u8 cs76[2] = { 0xa3, 0xfb };
4976 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4977 static const u8 cs158[8] = {
4978 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4980 static const u8 cs160[8] = {
4981 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4983 static const u8 cs168[8] = {
4984 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4986 static const u8 cs128[3 * 8] = {
4987 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4988 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4989 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4991 static const u8 cs148[2 * 8] = {
4992 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4993 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4995 static const u8 cs31a[8 * 4] = {
4996 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
4997 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
4998 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4999 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5001 static const u8 cs33a[8 * 4] = {
5002 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5003 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5004 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5005 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5007 static const u8 cs45a[8 * 2] = {
5008 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5009 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5011 static const u8 cs170[7 * 8] = {
5012 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5013 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5014 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5015 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5016 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5017 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5018 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5020 static const u8 cs1a8[3 * 8] = {
5021 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5022 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5023 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5025 static const u8 cs100[2 * 8] = {
5026 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5027 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5030 /* VGA enable */
5031 reg = inSISREG(SISVGAENABLE) | 0x01;
5032 outSISREG(SISVGAENABLE, reg);
5034 /* Misc */
5035 reg = inSISREG(SISMISCR) | 0x01;
5036 outSISREG(SISMISCW, reg);
5038 /* Unlock SR */
5039 outSISIDXREG(SISSR, 0x05, 0x86);
5040 inSISIDXREG(SISSR, 0x05, reg);
5041 if(reg != 0xa1)
5042 return 0;
5044 /* Clear some regs */
5045 for(i = 0; i < 0x22; i++) {
5046 if(0x06 + i == 0x20) continue;
5047 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5049 for(i = 0; i < 0x0b; i++) {
5050 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5052 for(i = 0; i < 0x10; i++) {
5053 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5056 ptr = cs78;
5057 if(ivideo->haveXGIROM) {
5058 ptr = (const u8 *)&bios[0x78];
5060 for(i = 0; i < 3; i++) {
5061 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5064 ptr = cs76;
5065 if(ivideo->haveXGIROM) {
5066 ptr = (const u8 *)&bios[0x76];
5068 for(i = 0; i < 2; i++) {
5069 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5072 v1 = 0x18; v2 = 0x00;
5073 if(ivideo->haveXGIROM) {
5074 v1 = bios[0x74];
5075 v2 = bios[0x75];
5077 outSISIDXREG(SISSR, 0x07, v1);
5078 outSISIDXREG(SISSR, 0x11, 0x0f);
5079 outSISIDXREG(SISSR, 0x1f, v2);
5080 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5081 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5082 outSISIDXREG(SISSR, 0x27, 0x74);
5084 ptr = cs7b;
5085 if(ivideo->haveXGIROM) {
5086 ptr = (const u8 *)&bios[0x7b];
5088 for(i = 0; i < 3; i++) {
5089 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5092 if(ivideo->chip == XGI_40) {
5093 if(ivideo->revision_id == 2) {
5094 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5096 outSISIDXREG(SISCR, 0x7d, 0xfe);
5097 outSISIDXREG(SISCR, 0x7e, 0x0f);
5099 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5100 andSISIDXREG(SISCR, 0x58, 0xd7);
5101 inSISIDXREG(SISCR, 0xcb, reg);
5102 if(reg & 0x20) {
5103 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5107 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5108 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5110 if(ivideo->chip == XGI_20) {
5111 outSISIDXREG(SISSR, 0x36, 0x70);
5112 } else {
5113 outSISIDXREG(SISVID, 0x00, 0x86);
5114 outSISIDXREG(SISVID, 0x32, 0x00);
5115 outSISIDXREG(SISVID, 0x30, 0x00);
5116 outSISIDXREG(SISVID, 0x32, 0x01);
5117 outSISIDXREG(SISVID, 0x30, 0x00);
5118 andSISIDXREG(SISVID, 0x2f, 0xdf);
5119 andSISIDXREG(SISCAP, 0x00, 0x3f);
5121 outSISIDXREG(SISPART1, 0x2f, 0x01);
5122 outSISIDXREG(SISPART1, 0x00, 0x00);
5123 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5124 outSISIDXREG(SISPART1, 0x2e, 0x08);
5125 andSISIDXREG(SISPART1, 0x35, 0x7f);
5126 andSISIDXREG(SISPART1, 0x50, 0xfe);
5128 inSISIDXREG(SISPART4, 0x00, reg);
5129 if(reg == 1 || reg == 2) {
5130 outSISIDXREG(SISPART2, 0x00, 0x1c);
5131 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5132 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5133 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5134 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5136 inSISIDXREG(SISPART4, 0x01, reg);
5137 if((reg & 0xf0) >= 0xb0) {
5138 inSISIDXREG(SISPART4, 0x23, reg);
5139 if(reg & 0x20) reg |= 0x40;
5140 outSISIDXREG(SISPART4, 0x23, reg);
5141 reg = (reg & 0x20) ? 0x02 : 0x00;
5142 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5146 v1 = bios[0x77];
5148 inSISIDXREG(SISSR, 0x3b, reg);
5149 if(reg & 0x02) {
5150 inSISIDXREG(SISSR, 0x3a, reg);
5151 v2 = (reg & 0x30) >> 3;
5152 if(!(v2 & 0x04)) v2 ^= 0x02;
5153 inSISIDXREG(SISSR, 0x39, reg);
5154 if(reg & 0x80) v2 |= 0x80;
5155 v2 |= 0x01;
5157 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5158 SIS_PCI_PUT_DEVICE(mypdev);
5159 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5160 v2 &= 0xf9;
5161 v2 |= 0x08;
5162 v1 &= 0xfe;
5163 } else {
5164 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5165 if(!mypdev)
5166 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5167 if(!mypdev)
5168 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5169 if(mypdev) {
5170 pci_read_config_dword(mypdev, 0x94, &regd);
5171 regd &= 0xfffffeff;
5172 pci_write_config_dword(mypdev, 0x94, regd);
5173 v1 &= 0xfe;
5174 SIS_PCI_PUT_DEVICE(mypdev);
5175 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5176 v1 &= 0xfe;
5177 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5178 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5179 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5180 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5181 if((v2 & 0x06) == 4)
5182 v2 ^= 0x06;
5183 v2 |= 0x08;
5186 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5188 outSISIDXREG(SISSR, 0x22, v1);
5190 if(ivideo->revision_id == 2) {
5191 inSISIDXREG(SISSR, 0x3b, v1);
5192 inSISIDXREG(SISSR, 0x3a, v2);
5193 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5194 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5195 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5197 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5198 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5199 * of nforce 2 ROM
5201 if(0)
5202 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5203 SIS_PCI_PUT_DEVICE(mypdev);
5207 v1 = 0x30;
5208 inSISIDXREG(SISSR, 0x3b, reg);
5209 inSISIDXREG(SISCR, 0x5f, v2);
5210 if((!(reg & 0x02)) && (v2 & 0x0e))
5211 v1 |= 0x08;
5212 outSISIDXREG(SISSR, 0x27, v1);
5214 if(bios[0x64] & 0x01) {
5215 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5218 v1 = bios[0x4f7];
5219 pci_read_config_dword(pdev, 0x50, &regd);
5220 regd = (regd >> 20) & 0x0f;
5221 if(regd == 1) {
5222 v1 &= 0xfc;
5223 orSISIDXREG(SISCR, 0x5f, 0x08);
5225 outSISIDXREG(SISCR, 0x48, v1);
5227 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5228 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5229 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5230 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5231 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5232 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5233 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5234 outSISIDXREG(SISCR, 0x74, 0xd0);
5235 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5236 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5237 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5238 v1 = bios[0x501];
5239 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5240 v1 = 0xf0;
5241 SIS_PCI_PUT_DEVICE(mypdev);
5243 outSISIDXREG(SISCR, 0x77, v1);
5246 /* RAM type */
5248 regb = 0; /* ! */
5250 v1 = 0xff;
5251 if(ivideo->haveXGIROM) {
5252 v1 = bios[0x140 + regb];
5254 outSISIDXREG(SISCR, 0x6d, v1);
5256 ptr = cs128;
5257 if(ivideo->haveXGIROM) {
5258 ptr = (const u8 *)&bios[0x128];
5260 for(i = 0, j = 0; i < 3; i++, j += 8) {
5261 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5264 ptr = cs31a;
5265 ptr2 = cs33a;
5266 if(ivideo->haveXGIROM) {
5267 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5268 ptr = (const u8 *)&bios[index];
5269 ptr2 = (const u8 *)&bios[index + 0x20];
5271 for(i = 0; i < 2; i++) {
5272 if(i == 0) {
5273 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5274 rega = 0x6b;
5275 } else {
5276 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5277 rega = 0x6e;
5279 reg = 0x00;
5280 for(j = 0; j < 16; j++) {
5281 reg &= 0xf3;
5282 if(regd & 0x01) reg |= 0x04;
5283 if(regd & 0x02) reg |= 0x08;
5284 regd >>= 2;
5285 outSISIDXREG(SISCR, rega, reg);
5286 inSISIDXREG(SISCR, rega, reg);
5287 inSISIDXREG(SISCR, rega, reg);
5288 reg += 0x10;
5292 andSISIDXREG(SISCR, 0x6e, 0xfc);
5294 ptr = NULL;
5295 if(ivideo->haveXGIROM) {
5296 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5297 ptr = (const u8 *)&bios[index];
5299 for(i = 0; i < 4; i++) {
5300 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5301 reg = 0x00;
5302 for(j = 0; j < 2; j++) {
5303 regd = 0;
5304 if(ptr) {
5305 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5306 ptr += 4;
5308 /* reg = 0x00; */
5309 for(k = 0; k < 16; k++) {
5310 reg &= 0xfc;
5311 if(regd & 0x01) reg |= 0x01;
5312 if(regd & 0x02) reg |= 0x02;
5313 regd >>= 2;
5314 outSISIDXREG(SISCR, 0x6f, reg);
5315 inSISIDXREG(SISCR, 0x6f, reg);
5316 inSISIDXREG(SISCR, 0x6f, reg);
5317 reg += 0x08;
5322 ptr = cs148;
5323 if(ivideo->haveXGIROM) {
5324 ptr = (const u8 *)&bios[0x148];
5326 for(i = 0, j = 0; i < 2; i++, j += 8) {
5327 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5330 andSISIDXREG(SISCR, 0x89, 0x8f);
5332 ptr = cs45a;
5333 if(ivideo->haveXGIROM) {
5334 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5335 ptr = (const u8 *)&bios[index];
5337 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5338 reg = 0x80;
5339 for(i = 0; i < 5; i++) {
5340 reg &= 0xfc;
5341 if(regd & 0x01) reg |= 0x01;
5342 if(regd & 0x02) reg |= 0x02;
5343 regd >>= 2;
5344 outSISIDXREG(SISCR, 0x89, reg);
5345 inSISIDXREG(SISCR, 0x89, reg);
5346 inSISIDXREG(SISCR, 0x89, reg);
5347 reg += 0x10;
5350 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5351 if(ivideo->haveXGIROM) {
5352 v1 = bios[0x118 + regb];
5353 v2 = bios[0xf8 + regb];
5354 v3 = bios[0x120 + regb];
5355 v4 = bios[0x1ca];
5357 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5358 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5359 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5360 outSISIDXREG(SISCR, 0x41, v2);
5362 ptr = cs170;
5363 if(ivideo->haveXGIROM) {
5364 ptr = (const u8 *)&bios[0x170];
5366 for(i = 0, j = 0; i < 7; i++, j += 8) {
5367 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5370 outSISIDXREG(SISCR, 0x59, v3);
5372 ptr = cs1a8;
5373 if(ivideo->haveXGIROM) {
5374 ptr = (const u8 *)&bios[0x1a8];
5376 for(i = 0, j = 0; i < 3; i++, j += 8) {
5377 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5380 ptr = cs100;
5381 if(ivideo->haveXGIROM) {
5382 ptr = (const u8 *)&bios[0x100];
5384 for(i = 0, j = 0; i < 2; i++, j += 8) {
5385 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5388 outSISIDXREG(SISCR, 0xcf, v4);
5390 outSISIDXREG(SISCR, 0x83, 0x09);
5391 outSISIDXREG(SISCR, 0x87, 0x00);
5393 if(ivideo->chip == XGI_40) {
5394 if( (ivideo->revision_id == 1) ||
5395 (ivideo->revision_id == 2) ) {
5396 outSISIDXREG(SISCR, 0x8c, 0x87);
5400 outSISIDXREG(SISSR, 0x17, 0x00);
5401 outSISIDXREG(SISSR, 0x1a, 0x87);
5403 if(ivideo->chip == XGI_20) {
5404 outSISIDXREG(SISSR, 0x15, 0x00);
5405 outSISIDXREG(SISSR, 0x1c, 0x00);
5408 ramtype = 0x00; v1 = 0x10;
5409 if(ivideo->haveXGIROM) {
5410 ramtype = bios[0x62];
5411 v1 = bios[0x1d2];
5413 if(!(ramtype & 0x80)) {
5414 if(ivideo->chip == XGI_20) {
5415 outSISIDXREG(SISCR, 0x97, v1);
5416 inSISIDXREG(SISCR, 0x97, reg);
5417 if(reg & 0x10) {
5418 ramtype = (reg & 0x01) << 1;
5420 } else {
5421 inSISIDXREG(SISSR, 0x39, reg);
5422 ramtype = reg & 0x02;
5423 if(!(ramtype)) {
5424 inSISIDXREG(SISSR, 0x3a, reg);
5425 ramtype = (reg >> 1) & 0x01;
5429 ramtype &= 0x07;
5431 regb = 0; /* ! */
5433 switch(ramtype) {
5434 case 0:
5435 sisfb_post_xgi_setclocks(ivideo, regb);
5436 if((ivideo->chip == XGI_20) ||
5437 (ivideo->revision_id == 1) ||
5438 (ivideo->revision_id == 2)) {
5439 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5440 if(ivideo->haveXGIROM) {
5441 v1 = bios[regb + 0x158];
5442 v2 = bios[regb + 0x160];
5443 v3 = bios[regb + 0x168];
5445 outSISIDXREG(SISCR, 0x82, v1);
5446 outSISIDXREG(SISCR, 0x85, v2);
5447 outSISIDXREG(SISCR, 0x86, v3);
5448 } else {
5449 outSISIDXREG(SISCR, 0x82, 0x88);
5450 outSISIDXREG(SISCR, 0x86, 0x00);
5451 inSISIDXREG(SISCR, 0x86, reg);
5452 outSISIDXREG(SISCR, 0x86, 0x88);
5453 inSISIDXREG(SISCR, 0x86, reg);
5454 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5455 outSISIDXREG(SISCR, 0x82, 0x77);
5456 outSISIDXREG(SISCR, 0x85, 0x00);
5457 inSISIDXREG(SISCR, 0x85, reg);
5458 outSISIDXREG(SISCR, 0x85, 0x88);
5459 inSISIDXREG(SISCR, 0x85, reg);
5460 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5461 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5463 if(ivideo->chip == XGI_40) {
5464 outSISIDXREG(SISCR, 0x97, 0x00);
5466 outSISIDXREG(SISCR, 0x98, 0x01);
5467 outSISIDXREG(SISCR, 0x9a, 0x02);
5469 outSISIDXREG(SISSR, 0x18, 0x01);
5470 if((ivideo->chip == XGI_20) ||
5471 (ivideo->revision_id == 2)) {
5472 outSISIDXREG(SISSR, 0x19, 0x40);
5473 } else {
5474 outSISIDXREG(SISSR, 0x19, 0x20);
5476 outSISIDXREG(SISSR, 0x16, 0x00);
5477 outSISIDXREG(SISSR, 0x16, 0x80);
5478 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5479 sisfb_post_xgi_delay(ivideo, 0x43);
5480 sisfb_post_xgi_delay(ivideo, 0x43);
5481 sisfb_post_xgi_delay(ivideo, 0x43);
5482 outSISIDXREG(SISSR, 0x18, 0x00);
5483 if((ivideo->chip == XGI_20) ||
5484 (ivideo->revision_id == 2)) {
5485 outSISIDXREG(SISSR, 0x19, 0x40);
5486 } else {
5487 outSISIDXREG(SISSR, 0x19, 0x20);
5489 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5490 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5492 outSISIDXREG(SISSR, 0x16, 0x00);
5493 outSISIDXREG(SISSR, 0x16, 0x80);
5494 sisfb_post_xgi_delay(ivideo, 4);
5495 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5496 if(ivideo->haveXGIROM) {
5497 v1 = bios[0xf0];
5498 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5499 v2 = bios[index];
5500 v3 = bios[index + 1];
5501 v4 = bios[index + 2];
5502 v5 = bios[index + 3];
5504 outSISIDXREG(SISSR, 0x18, v1);
5505 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5506 outSISIDXREG(SISSR, 0x16, v2);
5507 outSISIDXREG(SISSR, 0x16, v3);
5508 sisfb_post_xgi_delay(ivideo, 0x43);
5509 outSISIDXREG(SISSR, 0x1b, 0x03);
5510 sisfb_post_xgi_delay(ivideo, 0x22);
5511 outSISIDXREG(SISSR, 0x18, v1);
5512 outSISIDXREG(SISSR, 0x19, 0x00);
5513 outSISIDXREG(SISSR, 0x16, v4);
5514 outSISIDXREG(SISSR, 0x16, v5);
5515 outSISIDXREG(SISSR, 0x1b, 0x00);
5516 break;
5517 case 1:
5518 outSISIDXREG(SISCR, 0x82, 0x77);
5519 outSISIDXREG(SISCR, 0x86, 0x00);
5520 inSISIDXREG(SISCR, 0x86, reg);
5521 outSISIDXREG(SISCR, 0x86, 0x88);
5522 inSISIDXREG(SISCR, 0x86, reg);
5523 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5524 if(ivideo->haveXGIROM) {
5525 v1 = bios[regb + 0x168];
5526 v2 = bios[regb + 0x160];
5527 v3 = bios[regb + 0x158];
5529 outSISIDXREG(SISCR, 0x86, v1);
5530 outSISIDXREG(SISCR, 0x82, 0x77);
5531 outSISIDXREG(SISCR, 0x85, 0x00);
5532 inSISIDXREG(SISCR, 0x85, reg);
5533 outSISIDXREG(SISCR, 0x85, 0x88);
5534 inSISIDXREG(SISCR, 0x85, reg);
5535 outSISIDXREG(SISCR, 0x85, v2);
5536 outSISIDXREG(SISCR, 0x82, v3);
5537 outSISIDXREG(SISCR, 0x98, 0x01);
5538 outSISIDXREG(SISCR, 0x9a, 0x02);
5540 outSISIDXREG(SISSR, 0x28, 0x64);
5541 outSISIDXREG(SISSR, 0x29, 0x63);
5542 sisfb_post_xgi_delay(ivideo, 15);
5543 outSISIDXREG(SISSR, 0x18, 0x00);
5544 outSISIDXREG(SISSR, 0x19, 0x20);
5545 outSISIDXREG(SISSR, 0x16, 0x00);
5546 outSISIDXREG(SISSR, 0x16, 0x80);
5547 outSISIDXREG(SISSR, 0x18, 0xc5);
5548 outSISIDXREG(SISSR, 0x19, 0x23);
5549 outSISIDXREG(SISSR, 0x16, 0x00);
5550 outSISIDXREG(SISSR, 0x16, 0x80);
5551 sisfb_post_xgi_delay(ivideo, 1);
5552 outSISIDXREG(SISCR, 0x97,0x11);
5553 sisfb_post_xgi_setclocks(ivideo, regb);
5554 sisfb_post_xgi_delay(ivideo, 0x46);
5555 outSISIDXREG(SISSR, 0x18, 0xc5);
5556 outSISIDXREG(SISSR, 0x19, 0x23);
5557 outSISIDXREG(SISSR, 0x16, 0x00);
5558 outSISIDXREG(SISSR, 0x16, 0x80);
5559 sisfb_post_xgi_delay(ivideo, 1);
5560 outSISIDXREG(SISSR, 0x1b, 0x04);
5561 sisfb_post_xgi_delay(ivideo, 1);
5562 outSISIDXREG(SISSR, 0x1b, 0x00);
5563 sisfb_post_xgi_delay(ivideo, 1);
5564 v1 = 0x31;
5565 if(ivideo->haveXGIROM) {
5566 v1 = bios[0xf0];
5568 outSISIDXREG(SISSR, 0x18, v1);
5569 outSISIDXREG(SISSR, 0x19, 0x06);
5570 outSISIDXREG(SISSR, 0x16, 0x04);
5571 outSISIDXREG(SISSR, 0x16, 0x84);
5572 sisfb_post_xgi_delay(ivideo, 1);
5573 break;
5574 default:
5575 sisfb_post_xgi_setclocks(ivideo, regb);
5576 if((ivideo->chip == XGI_40) &&
5577 ((ivideo->revision_id == 1) ||
5578 (ivideo->revision_id == 2))) {
5579 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5580 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5581 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5582 } else {
5583 outSISIDXREG(SISCR, 0x82, 0x88);
5584 outSISIDXREG(SISCR, 0x86, 0x00);
5585 inSISIDXREG(SISCR, 0x86, reg);
5586 outSISIDXREG(SISCR, 0x86, 0x88);
5587 outSISIDXREG(SISCR, 0x82, 0x77);
5588 outSISIDXREG(SISCR, 0x85, 0x00);
5589 inSISIDXREG(SISCR, 0x85, reg);
5590 outSISIDXREG(SISCR, 0x85, 0x88);
5591 inSISIDXREG(SISCR, 0x85, reg);
5592 v1 = cs160[regb]; v2 = cs158[regb];
5593 if(ivideo->haveXGIROM) {
5594 v1 = bios[regb + 0x160];
5595 v2 = bios[regb + 0x158];
5597 outSISIDXREG(SISCR, 0x85, v1);
5598 outSISIDXREG(SISCR, 0x82, v2);
5600 if(ivideo->chip == XGI_40) {
5601 outSISIDXREG(SISCR, 0x97, 0x11);
5603 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5604 outSISIDXREG(SISCR, 0x98, 0x01);
5605 } else {
5606 outSISIDXREG(SISCR, 0x98, 0x03);
5608 outSISIDXREG(SISCR, 0x9a, 0x02);
5610 if(ivideo->chip == XGI_40) {
5611 outSISIDXREG(SISSR, 0x18, 0x01);
5612 } else {
5613 outSISIDXREG(SISSR, 0x18, 0x00);
5615 outSISIDXREG(SISSR, 0x19, 0x40);
5616 outSISIDXREG(SISSR, 0x16, 0x00);
5617 outSISIDXREG(SISSR, 0x16, 0x80);
5618 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5619 sisfb_post_xgi_delay(ivideo, 0x43);
5620 sisfb_post_xgi_delay(ivideo, 0x43);
5621 sisfb_post_xgi_delay(ivideo, 0x43);
5622 outSISIDXREG(SISSR, 0x18, 0x00);
5623 outSISIDXREG(SISSR, 0x19, 0x40);
5624 outSISIDXREG(SISSR, 0x16, 0x00);
5625 outSISIDXREG(SISSR, 0x16, 0x80);
5627 sisfb_post_xgi_delay(ivideo, 4);
5628 v1 = 0x31;
5629 if(ivideo->haveXGIROM) {
5630 v1 = bios[0xf0];
5632 outSISIDXREG(SISSR, 0x18, v1);
5633 outSISIDXREG(SISSR, 0x19, 0x01);
5634 if(ivideo->chip == XGI_40) {
5635 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5636 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5637 } else {
5638 outSISIDXREG(SISSR, 0x16, 0x05);
5639 outSISIDXREG(SISSR, 0x16, 0x85);
5641 sisfb_post_xgi_delay(ivideo, 0x43);
5642 if(ivideo->chip == XGI_40) {
5643 outSISIDXREG(SISSR, 0x1b, 0x01);
5644 } else {
5645 outSISIDXREG(SISSR, 0x1b, 0x03);
5647 sisfb_post_xgi_delay(ivideo, 0x22);
5648 outSISIDXREG(SISSR, 0x18, v1);
5649 outSISIDXREG(SISSR, 0x19, 0x00);
5650 if(ivideo->chip == XGI_40) {
5651 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5652 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5653 } else {
5654 outSISIDXREG(SISSR, 0x16, 0x05);
5655 outSISIDXREG(SISSR, 0x16, 0x85);
5657 outSISIDXREG(SISSR, 0x1b, 0x00);
5660 regb = 0; /* ! */
5661 v1 = 0x03;
5662 if(ivideo->haveXGIROM) {
5663 v1 = bios[0x110 + regb];
5665 outSISIDXREG(SISSR, 0x1b, v1);
5667 /* RAM size */
5668 v1 = 0x00; v2 = 0x00;
5669 if(ivideo->haveXGIROM) {
5670 v1 = bios[0x62];
5671 v2 = bios[0x63];
5673 regb = 0; /* ! */
5674 regd = 1 << regb;
5675 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5677 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5678 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5680 } else {
5682 /* Set default mode, don't clear screen */
5683 ivideo->SiS_Pr.SiS_UseOEM = false;
5684 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5685 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5686 ivideo->curFSTN = ivideo->curDSTN = 0;
5687 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5688 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5690 outSISIDXREG(SISSR, 0x05, 0x86);
5692 /* Disable read-cache */
5693 andSISIDXREG(SISSR, 0x21, 0xdf);
5694 sisfb_post_xgi_ramsize(ivideo);
5695 /* Enable read-cache */
5696 orSISIDXREG(SISSR, 0x21, 0x20);
5700 #if 0
5701 printk(KERN_DEBUG "-----------------\n");
5702 for(i = 0; i < 0xff; i++) {
5703 inSISIDXREG(SISCR, i, reg);
5704 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5706 for(i = 0; i < 0x40; i++) {
5707 inSISIDXREG(SISSR, i, reg);
5708 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5710 printk(KERN_DEBUG "-----------------\n");
5711 #endif
5713 /* Sense CRT1 */
5714 if(ivideo->chip == XGI_20) {
5715 orSISIDXREG(SISCR, 0x32, 0x20);
5716 } else {
5717 inSISIDXREG(SISPART4, 0x00, reg);
5718 if((reg == 1) || (reg == 2)) {
5719 sisfb_sense_crt1(ivideo);
5720 } else {
5721 orSISIDXREG(SISCR, 0x32, 0x20);
5725 /* Set default mode, don't clear screen */
5726 ivideo->SiS_Pr.SiS_UseOEM = false;
5727 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5728 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5729 ivideo->curFSTN = ivideo->curDSTN = 0;
5730 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5732 outSISIDXREG(SISSR, 0x05, 0x86);
5734 /* Display off */
5735 orSISIDXREG(SISSR, 0x01, 0x20);
5737 /* Save mode number in CR34 */
5738 outSISIDXREG(SISCR, 0x34, 0x2e);
5740 /* Let everyone know what the current mode is */
5741 ivideo->modeprechange = 0x2e;
5743 if(ivideo->chip == XGI_40) {
5744 inSISIDXREG(SISCR, 0xca, reg);
5745 inSISIDXREG(SISCR, 0xcc, v1);
5746 if((reg & 0x10) && (!(v1 & 0x04))) {
5747 printk(KERN_ERR
5748 "sisfb: Please connect power to the card.\n");
5749 return 0;
5753 return 1;
5755 #endif
5757 static int __devinit
5758 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5760 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5761 struct sis_video_info *ivideo = NULL;
5762 struct fb_info *sis_fb_info = NULL;
5763 u16 reg16;
5764 u8 reg;
5765 int i, ret;
5767 if(sisfb_off)
5768 return -ENXIO;
5770 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5771 if(!sis_fb_info)
5772 return -ENOMEM;
5774 ivideo = (struct sis_video_info *)sis_fb_info->par;
5775 ivideo->memyselfandi = sis_fb_info;
5777 ivideo->sisfb_id = SISFB_ID;
5779 if(card_list == NULL) {
5780 ivideo->cardnumber = 0;
5781 } else {
5782 struct sis_video_info *countvideo = card_list;
5783 ivideo->cardnumber = 1;
5784 while((countvideo = countvideo->next) != 0)
5785 ivideo->cardnumber++;
5788 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5790 ivideo->warncount = 0;
5791 ivideo->chip_id = pdev->device;
5792 ivideo->chip_vendor = pdev->vendor;
5793 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
5794 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5795 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
5796 ivideo->sisvga_enabled = reg16 & 0x01;
5797 ivideo->pcibus = pdev->bus->number;
5798 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5799 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5800 ivideo->subsysvendor = pdev->subsystem_vendor;
5801 ivideo->subsysdevice = pdev->subsystem_device;
5802 #ifdef SIS_OLD_CONFIG_COMPAT
5803 ivideo->ioctl32registered = 0;
5804 #endif
5806 #ifndef MODULE
5807 if(sisfb_mode_idx == -1) {
5808 sisfb_get_vga_mode_from_kernel();
5810 #endif
5812 ivideo->chip = chipinfo->chip;
5813 ivideo->sisvga_engine = chipinfo->vgaengine;
5814 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5815 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5816 ivideo->mni = chipinfo->mni;
5818 ivideo->detectedpdc = 0xff;
5819 ivideo->detectedpdca = 0xff;
5820 ivideo->detectedlcda = 0xff;
5822 ivideo->sisfb_thismonitor.datavalid = false;
5824 ivideo->current_base = 0;
5826 ivideo->engineok = 0;
5828 ivideo->sisfb_was_boot_device = 0;
5829 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5830 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5831 if(ivideo->sisvga_enabled)
5832 ivideo->sisfb_was_boot_device = 1;
5833 else {
5834 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5835 "but marked as boot video device ???\n");
5836 printk(KERN_DEBUG "sisfb: I will not accept this "
5837 "as the primary VGA device\n");
5840 #endif
5842 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5843 ivideo->sisfb_accel = sisfb_accel;
5844 ivideo->sisfb_ypan = sisfb_ypan;
5845 ivideo->sisfb_max = sisfb_max;
5846 ivideo->sisfb_userom = sisfb_userom;
5847 ivideo->sisfb_useoem = sisfb_useoem;
5848 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5849 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5850 ivideo->sisfb_crt1off = sisfb_crt1off;
5851 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5852 ivideo->sisfb_crt2type = sisfb_crt2type;
5853 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5854 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5855 ivideo->sisfb_dstn = sisfb_dstn;
5856 ivideo->sisfb_fstn = sisfb_fstn;
5857 ivideo->sisfb_tvplug = sisfb_tvplug;
5858 ivideo->sisfb_tvstd = sisfb_tvstd;
5859 ivideo->tvxpos = sisfb_tvxposoffset;
5860 ivideo->tvypos = sisfb_tvyposoffset;
5861 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5862 ivideo->refresh_rate = 0;
5863 if(ivideo->sisfb_parm_rate != -1) {
5864 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5867 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5868 ivideo->SiS_Pr.CenterScreen = -1;
5869 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5870 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5872 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5873 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5874 ivideo->SiS_Pr.SiS_ChSW = false;
5875 ivideo->SiS_Pr.SiS_UseLCDA = false;
5876 ivideo->SiS_Pr.HaveEMI = false;
5877 ivideo->SiS_Pr.HaveEMILCD = false;
5878 ivideo->SiS_Pr.OverruleEMI = false;
5879 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
5880 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5881 ivideo->SiS_Pr.PDC = -1;
5882 ivideo->SiS_Pr.PDCA = -1;
5883 ivideo->SiS_Pr.DDCPortMixup = false;
5884 #ifdef CONFIG_FB_SIS_315
5885 if(ivideo->chip >= SIS_330) {
5886 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5887 if(ivideo->chip >= SIS_661) {
5888 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
5891 #endif
5893 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5895 pci_set_drvdata(pdev, ivideo);
5897 /* Patch special cases */
5898 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5899 switch(ivideo->nbridge->device) {
5900 #ifdef CONFIG_FB_SIS_300
5901 case PCI_DEVICE_ID_SI_730:
5902 ivideo->chip = SIS_730;
5903 strcpy(ivideo->myid, "SiS 730");
5904 break;
5905 #endif
5906 #ifdef CONFIG_FB_SIS_315
5907 case PCI_DEVICE_ID_SI_651:
5908 /* ivideo->chip is ok */
5909 strcpy(ivideo->myid, "SiS 651");
5910 break;
5911 case PCI_DEVICE_ID_SI_740:
5912 ivideo->chip = SIS_740;
5913 strcpy(ivideo->myid, "SiS 740");
5914 break;
5915 case PCI_DEVICE_ID_SI_661:
5916 ivideo->chip = SIS_661;
5917 strcpy(ivideo->myid, "SiS 661");
5918 break;
5919 case PCI_DEVICE_ID_SI_741:
5920 ivideo->chip = SIS_741;
5921 strcpy(ivideo->myid, "SiS 741");
5922 break;
5923 case PCI_DEVICE_ID_SI_760:
5924 ivideo->chip = SIS_760;
5925 strcpy(ivideo->myid, "SiS 760");
5926 break;
5927 case PCI_DEVICE_ID_SI_761:
5928 ivideo->chip = SIS_761;
5929 strcpy(ivideo->myid, "SiS 761");
5930 break;
5931 #endif
5932 default:
5933 break;
5937 ivideo->SiS_Pr.ChipType = ivideo->chip;
5939 ivideo->SiS_Pr.ivideo = (void *)ivideo;
5941 #ifdef CONFIG_FB_SIS_315
5942 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5943 (ivideo->SiS_Pr.ChipType == SIS_315)) {
5944 ivideo->SiS_Pr.ChipType = SIS_315H;
5946 #endif
5948 if(!ivideo->sisvga_enabled) {
5949 if(pci_enable_device(pdev)) {
5950 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
5951 pci_set_drvdata(pdev, NULL);
5952 kfree(sis_fb_info);
5953 return -EIO;
5957 ivideo->video_base = pci_resource_start(pdev, 0);
5958 ivideo->mmio_base = pci_resource_start(pdev, 1);
5959 ivideo->mmio_size = pci_resource_len(pdev, 1);
5960 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
5961 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
5963 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
5965 #ifdef CONFIG_FB_SIS_300
5966 /* Find PCI systems for Chrontel/GPIO communication setup */
5967 if(ivideo->chip == SIS_630) {
5968 i = 0;
5969 do {
5970 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5971 mychswtable[i].subsysCard == ivideo->subsysdevice) {
5972 ivideo->SiS_Pr.SiS_ChSW = true;
5973 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5974 "requiring Chrontel/GPIO setup\n",
5975 mychswtable[i].vendorName,
5976 mychswtable[i].cardName);
5977 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
5978 break;
5980 i++;
5981 } while(mychswtable[i].subsysVendor != 0);
5983 #endif
5985 #ifdef CONFIG_FB_SIS_315
5986 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
5987 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
5989 #endif
5991 outSISIDXREG(SISSR, 0x05, 0x86);
5993 if( (!ivideo->sisvga_enabled)
5994 #if !defined(__i386__) && !defined(__x86_64__)
5995 || (sisfb_resetcard)
5996 #endif
5998 for(i = 0x30; i <= 0x3f; i++) {
5999 outSISIDXREG(SISCR, i, 0x00);
6003 /* Find out about current video mode */
6004 ivideo->modeprechange = 0x03;
6005 inSISIDXREG(SISCR, 0x34, reg);
6006 if(reg & 0x7f) {
6007 ivideo->modeprechange = reg & 0x7f;
6008 } else if(ivideo->sisvga_enabled) {
6009 #if defined(__i386__) || defined(__x86_64__)
6010 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
6011 if(tt) {
6012 ivideo->modeprechange = readb(tt + 0x49);
6013 iounmap(tt);
6015 #endif
6018 /* Search and copy ROM image */
6019 ivideo->bios_abase = NULL;
6020 ivideo->SiS_Pr.VirtualRomBase = NULL;
6021 ivideo->SiS_Pr.UseROM = false;
6022 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
6023 if(ivideo->sisfb_userom) {
6024 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6025 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6026 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
6027 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6028 ivideo->SiS_Pr.UseROM ? "" : "not ");
6029 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6030 ivideo->SiS_Pr.UseROM = false;
6031 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
6032 if( (ivideo->revision_id == 2) &&
6033 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6034 ivideo->SiS_Pr.DDCPortMixup = true;
6037 } else {
6038 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6041 /* Find systems for special custom timing */
6042 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6043 sisfb_detect_custom_timing(ivideo);
6046 /* POST card in case this has not been done by the BIOS */
6047 if( (!ivideo->sisvga_enabled)
6048 #if !defined(__i386__) && !defined(__x86_64__)
6049 || (sisfb_resetcard)
6050 #endif
6052 #ifdef CONFIG_FB_SIS_300
6053 if(ivideo->sisvga_engine == SIS_300_VGA) {
6054 if(ivideo->chip == SIS_300) {
6055 sisfb_post_sis300(pdev);
6056 ivideo->sisfb_can_post = 1;
6059 #endif
6061 #ifdef CONFIG_FB_SIS_315
6062 if(ivideo->sisvga_engine == SIS_315_VGA) {
6063 int result = 1;
6064 /* if((ivideo->chip == SIS_315H) ||
6065 (ivideo->chip == SIS_315) ||
6066 (ivideo->chip == SIS_315PRO) ||
6067 (ivideo->chip == SIS_330)) {
6068 sisfb_post_sis315330(pdev);
6069 } else */ if(ivideo->chip == XGI_20) {
6070 result = sisfb_post_xgi(pdev);
6071 ivideo->sisfb_can_post = 1;
6072 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6073 result = sisfb_post_xgi(pdev);
6074 ivideo->sisfb_can_post = 1;
6075 } else {
6076 printk(KERN_INFO "sisfb: Card is not "
6077 "POSTed and sisfb can't do this either.\n");
6079 if(!result) {
6080 printk(KERN_ERR "sisfb: Failed to POST card\n");
6081 ret = -ENODEV;
6082 goto error_3;
6085 #endif
6088 ivideo->sisfb_card_posted = 1;
6090 /* Find out about RAM size */
6091 if(sisfb_get_dram_size(ivideo)) {
6092 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6093 ret = -ENODEV;
6094 goto error_3;
6098 /* Enable PCI addressing and MMIO */
6099 if((ivideo->sisfb_mode_idx < 0) ||
6100 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6101 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6102 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6103 /* Enable 2D accelerator engine */
6104 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6107 if(sisfb_pdc != 0xff) {
6108 if(ivideo->sisvga_engine == SIS_300_VGA)
6109 sisfb_pdc &= 0x3c;
6110 else
6111 sisfb_pdc &= 0x1f;
6112 ivideo->SiS_Pr.PDC = sisfb_pdc;
6114 #ifdef CONFIG_FB_SIS_315
6115 if(ivideo->sisvga_engine == SIS_315_VGA) {
6116 if(sisfb_pdca != 0xff)
6117 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6119 #endif
6121 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6122 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6123 (int)(ivideo->video_size >> 20));
6124 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6125 ret = -ENODEV;
6126 goto error_3;
6129 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6130 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6131 ret = -ENODEV;
6132 goto error_2;
6135 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6136 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6137 if(!ivideo->video_vbase) {
6138 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6139 ret = -ENODEV;
6140 goto error_1;
6143 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6144 if(!ivideo->mmio_vbase) {
6145 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6146 ret = -ENODEV;
6147 error_0: iounmap(ivideo->video_vbase);
6148 error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6149 error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6150 error_3: vfree(ivideo->bios_abase);
6151 if(ivideo->lpcdev)
6152 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6153 if(ivideo->nbridge)
6154 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6155 pci_set_drvdata(pdev, NULL);
6156 if(!ivideo->sisvga_enabled)
6157 pci_disable_device(pdev);
6158 kfree(sis_fb_info);
6159 return ret;
6162 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6163 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6165 if(ivideo->video_offset) {
6166 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6167 ivideo->video_offset / 1024);
6170 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6171 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6174 /* Determine the size of the command queue */
6175 if(ivideo->sisvga_engine == SIS_300_VGA) {
6176 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6177 } else {
6178 if(ivideo->chip == XGI_20) {
6179 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6180 } else {
6181 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6185 /* Engines are no longer initialized here; this is
6186 * now done after the first mode-switch (if the
6187 * submitted var has its acceleration flags set).
6190 /* Calculate the base of the (unused) hw cursor */
6191 ivideo->hwcursor_vbase = ivideo->video_vbase
6192 + ivideo->video_size
6193 - ivideo->cmdQueueSize
6194 - ivideo->hwcursor_size;
6195 ivideo->caps |= HW_CURSOR_CAP;
6197 /* Initialize offscreen memory manager */
6198 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6199 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6202 /* Used for clearing the screen only, therefore respect our mem limit */
6203 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6204 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6206 ivideo->mtrr = -1;
6208 ivideo->vbflags = 0;
6209 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6210 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6211 ivideo->defmodeidx = DEFAULT_MODE;
6213 ivideo->newrom = 0;
6214 if(ivideo->chip < XGI_20) {
6215 if(ivideo->bios_abase) {
6216 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6220 if((ivideo->sisfb_mode_idx < 0) ||
6221 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6223 sisfb_sense_crt1(ivideo);
6225 sisfb_get_VB_type(ivideo);
6227 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6228 sisfb_detect_VB_connect(ivideo);
6231 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6233 /* Decide on which CRT2 device to use */
6234 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6235 if(ivideo->sisfb_crt2type != -1) {
6236 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6237 (ivideo->vbflags & CRT2_LCD)) {
6238 ivideo->currentvbflags |= CRT2_LCD;
6239 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6240 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6242 } else {
6243 /* Chrontel 700x TV detection often unreliable, therefore
6244 * use a different default order on such machines
6246 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6247 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6248 if(ivideo->vbflags & CRT2_LCD)
6249 ivideo->currentvbflags |= CRT2_LCD;
6250 else if(ivideo->vbflags & CRT2_TV)
6251 ivideo->currentvbflags |= CRT2_TV;
6252 else if(ivideo->vbflags & CRT2_VGA)
6253 ivideo->currentvbflags |= CRT2_VGA;
6254 } else {
6255 if(ivideo->vbflags & CRT2_TV)
6256 ivideo->currentvbflags |= CRT2_TV;
6257 else if(ivideo->vbflags & CRT2_LCD)
6258 ivideo->currentvbflags |= CRT2_LCD;
6259 else if(ivideo->vbflags & CRT2_VGA)
6260 ivideo->currentvbflags |= CRT2_VGA;
6265 if(ivideo->vbflags & CRT2_LCD) {
6266 sisfb_detect_lcd_type(ivideo);
6269 sisfb_save_pdc_emi(ivideo);
6271 if(!ivideo->sisfb_crt1off) {
6272 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6273 } else {
6274 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6275 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6276 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6280 if(ivideo->sisfb_mode_idx >= 0) {
6281 int bu = ivideo->sisfb_mode_idx;
6282 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6283 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6284 if(bu != ivideo->sisfb_mode_idx) {
6285 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6286 sisbios_mode[bu].xres,
6287 sisbios_mode[bu].yres,
6288 sisbios_mode[bu].bpp);
6292 if(ivideo->sisfb_mode_idx < 0) {
6293 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6294 case CRT2_LCD:
6295 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6296 break;
6297 case CRT2_TV:
6298 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6299 break;
6300 default:
6301 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6302 break;
6306 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6308 if(ivideo->refresh_rate != 0) {
6309 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6310 ivideo->sisfb_mode_idx);
6313 if(ivideo->rate_idx == 0) {
6314 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6315 ivideo->refresh_rate = 60;
6318 if(ivideo->sisfb_thismonitor.datavalid) {
6319 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6320 ivideo->sisfb_mode_idx,
6321 ivideo->rate_idx,
6322 ivideo->refresh_rate)) {
6323 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6324 "exceeds monitor specs!\n");
6328 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6329 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6330 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6332 sisfb_set_vparms(ivideo);
6334 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6336 /* ---------------- For 2.4: Now switch the mode ------------------ */
6338 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6339 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6340 ivideo->refresh_rate);
6342 /* Determine whether or not acceleration is to be
6343 * used. Need to know before pre/post_set_mode()
6345 ivideo->accel = 0;
6346 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6347 if(ivideo->sisfb_accel) {
6348 ivideo->accel = -1;
6349 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6352 /* Now switch the mode */
6353 sisfb_pre_setmode(ivideo);
6355 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
6356 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6357 ivideo->mode_no);
6358 ret = -EINVAL;
6359 iounmap(ivideo->mmio_vbase);
6360 goto error_0;
6363 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6365 sisfb_post_setmode(ivideo);
6367 /* Maximize regardless of sisfb_max at startup */
6368 ivideo->default_var.yres_virtual = 32767;
6370 /* Force reset of x virtual in crtc_to_var */
6371 ivideo->default_var.xres_virtual = 0;
6373 /* Copy mode timing to var */
6374 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6376 /* Find out about screen pitch */
6377 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6378 sisfb_set_pitch(ivideo);
6380 /* Init the accelerator (does nothing currently) */
6381 sisfb_initaccel(ivideo);
6383 /* Init some fbinfo entries */
6384 sis_fb_info->node = -1;
6385 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6386 sis_fb_info->fbops = &sisfb_ops;
6387 sis_fb_info->disp = &ivideo->sis_disp;
6388 sis_fb_info->blank = &sisfb_blank;
6389 sis_fb_info->switch_con = &sisfb_switch;
6390 sis_fb_info->updatevar = &sisfb_update_var;
6391 sis_fb_info->changevar = NULL;
6392 strcpy(sis_fb_info->fontname, sisfb_fontname);
6394 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6396 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6398 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6399 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6400 ivideo->refresh_rate);
6402 /* Set up the default var according to chosen default display mode */
6403 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6404 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6405 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6407 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6409 ivideo->default_var.pixclock = (u32) (1000000000 /
6410 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6412 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6413 ivideo->rate_idx, &ivideo->default_var)) {
6414 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6415 ivideo->default_var.pixclock <<= 1;
6419 if(ivideo->sisfb_ypan) {
6420 /* Maximize regardless of sisfb_max at startup */
6421 ivideo->default_var.yres_virtual =
6422 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6423 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6424 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6428 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6430 ivideo->accel = 0;
6431 if(ivideo->sisfb_accel) {
6432 ivideo->accel = -1;
6433 #ifdef STUPID_ACCELF_TEXT_SHIT
6434 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6435 #endif
6437 sisfb_initaccel(ivideo);
6439 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6440 sis_fb_info->flags = FBINFO_DEFAULT |
6441 FBINFO_HWACCEL_YPAN |
6442 FBINFO_HWACCEL_XPAN |
6443 FBINFO_HWACCEL_COPYAREA |
6444 FBINFO_HWACCEL_FILLRECT |
6445 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6446 #else
6447 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6448 #endif
6449 sis_fb_info->var = ivideo->default_var;
6450 sis_fb_info->fix = ivideo->sisfb_fix;
6451 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6452 sis_fb_info->fbops = &sisfb_ops;
6453 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6454 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6456 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6457 #endif /* 2.6 */
6459 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6461 #ifdef CONFIG_MTRR
6462 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6463 MTRR_TYPE_WRCOMB, 1);
6464 if(ivideo->mtrr < 0) {
6465 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6467 #endif
6469 if(register_framebuffer(sis_fb_info) < 0) {
6470 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6471 ret = -EINVAL;
6472 iounmap(ivideo->mmio_vbase);
6473 goto error_0;
6476 ivideo->registered = 1;
6478 /* Enlist us */
6479 ivideo->next = card_list;
6480 card_list = ivideo;
6482 #ifdef SIS_OLD_CONFIG_COMPAT
6484 int ret;
6485 /* Our ioctls are all "32/64bit compatible" */
6486 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6487 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6488 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6489 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6490 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6491 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6492 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6493 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6494 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6495 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6496 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6497 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6498 if(ret)
6499 printk(KERN_ERR
6500 "sisfb: Error registering ioctl32 translations\n");
6501 else
6502 ivideo->ioctl32registered = 1;
6504 #endif
6506 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6507 ivideo->sisfb_accel ? "enabled" : "disabled",
6508 ivideo->sisfb_ypan ?
6509 (ivideo->sisfb_max ? "enabled (auto-max)" :
6510 "enabled (no auto-max)") :
6511 "disabled");
6514 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6515 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6517 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6519 } /* if mode = "none" */
6521 return 0;
6524 /*****************************************************/
6525 /* PCI DEVICE HANDLING */
6526 /*****************************************************/
6528 static void __devexit sisfb_remove(struct pci_dev *pdev)
6530 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6531 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6532 int registered = ivideo->registered;
6533 int modechanged = ivideo->modechanged;
6535 #ifdef SIS_OLD_CONFIG_COMPAT
6536 if(ivideo->ioctl32registered) {
6537 int ret;
6538 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6539 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6540 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6541 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6542 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6543 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6544 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6545 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6546 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6547 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6548 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6549 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6550 if(ret)
6551 printk(KERN_ERR
6552 "sisfb: Error unregistering ioctl32 translations\n");
6554 #endif
6556 /* Unmap */
6557 iounmap(ivideo->mmio_vbase);
6558 iounmap(ivideo->video_vbase);
6560 /* Release mem regions */
6561 release_mem_region(ivideo->video_base, ivideo->video_size);
6562 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6564 vfree(ivideo->bios_abase);
6566 if(ivideo->lpcdev)
6567 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6569 if(ivideo->nbridge)
6570 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6572 #ifdef CONFIG_MTRR
6573 /* Release MTRR region */
6574 if(ivideo->mtrr >= 0)
6575 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6576 #endif
6578 pci_set_drvdata(pdev, NULL);
6580 /* If device was disabled when starting, disable
6581 * it when quitting.
6583 if(!ivideo->sisvga_enabled)
6584 pci_disable_device(pdev);
6586 /* Unregister the framebuffer */
6587 if(ivideo->registered) {
6588 unregister_framebuffer(sis_fb_info);
6589 framebuffer_release(sis_fb_info);
6592 /* OK, our ivideo is gone for good from here. */
6594 /* TODO: Restore the initial mode
6595 * This sounds easy but is as good as impossible
6596 * on many machines with SiS chip and video bridge
6597 * since text modes are always set up differently
6598 * from machine to machine. Depends on the type
6599 * of integration between chipset and bridge.
6601 if(registered && modechanged)
6602 printk(KERN_INFO
6603 "sisfb: Restoring of text mode not supported yet\n");
6606 static struct pci_driver sisfb_driver = {
6607 .name = "sisfb",
6608 .id_table = sisfb_pci_table,
6609 .probe = sisfb_probe,
6610 .remove = __devexit_p(sisfb_remove)
6613 SISINITSTATIC int __init sisfb_init(void)
6615 #ifndef MODULE
6616 char *options = NULL;
6618 if(fb_get_options("sisfb", &options))
6619 return -ENODEV;
6621 sisfb_setup(options);
6622 #endif
6623 return pci_register_driver(&sisfb_driver);
6626 #ifndef MODULE
6627 module_init(sisfb_init);
6628 #endif
6630 /*****************************************************/
6631 /* MODULE */
6632 /*****************************************************/
6634 #ifdef MODULE
6636 static char *mode = NULL;
6637 static int vesa = -1;
6638 static unsigned int rate = 0;
6639 static unsigned int crt1off = 1;
6640 static unsigned int mem = 0;
6641 static char *forcecrt2type = NULL;
6642 static int forcecrt1 = -1;
6643 static int pdc = -1;
6644 static int pdc1 = -1;
6645 static int noaccel = -1;
6646 static int noypan = -1;
6647 static int nomax = -1;
6648 static int userom = -1;
6649 static int useoem = -1;
6650 static char *tvstandard = NULL;
6651 static int nocrt2rate = 0;
6652 static int scalelcd = -1;
6653 static char *specialtiming = NULL;
6654 static int lvdshl = -1;
6655 static int tvxposoffset = 0, tvyposoffset = 0;
6656 #if !defined(__i386__) && !defined(__x86_64__)
6657 static int resetcard = 0;
6658 static int videoram = 0;
6659 #endif
6661 static int __init sisfb_init_module(void)
6663 sisfb_setdefaultparms();
6665 if(rate)
6666 sisfb_parm_rate = rate;
6668 if((scalelcd == 0) || (scalelcd == 1))
6669 sisfb_scalelcd = scalelcd ^ 1;
6671 /* Need to check crt2 type first for fstn/dstn */
6673 if(forcecrt2type)
6674 sisfb_search_crt2type(forcecrt2type);
6676 if(tvstandard)
6677 sisfb_search_tvstd(tvstandard);
6679 if(mode)
6680 sisfb_search_mode(mode, false);
6681 else if(vesa != -1)
6682 sisfb_search_vesamode(vesa, false);
6684 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6686 sisfb_forcecrt1 = forcecrt1;
6687 if(forcecrt1 == 1)
6688 sisfb_crt1off = 0;
6689 else if(forcecrt1 == 0)
6690 sisfb_crt1off = 1;
6692 if(noaccel == 1)
6693 sisfb_accel = 0;
6694 else if(noaccel == 0)
6695 sisfb_accel = 1;
6697 if(noypan == 1)
6698 sisfb_ypan = 0;
6699 else if(noypan == 0)
6700 sisfb_ypan = 1;
6702 if(nomax == 1)
6703 sisfb_max = 0;
6704 else if(nomax == 0)
6705 sisfb_max = 1;
6707 if(mem)
6708 sisfb_parm_mem = mem;
6710 if(userom != -1)
6711 sisfb_userom = userom;
6713 if(useoem != -1)
6714 sisfb_useoem = useoem;
6716 if(pdc != -1)
6717 sisfb_pdc = (pdc & 0x7f);
6719 if(pdc1 != -1)
6720 sisfb_pdca = (pdc1 & 0x1f);
6722 sisfb_nocrt2rate = nocrt2rate;
6724 if(specialtiming)
6725 sisfb_search_specialtiming(specialtiming);
6727 if((lvdshl >= 0) && (lvdshl <= 3))
6728 sisfb_lvdshl = lvdshl;
6730 sisfb_tvxposoffset = tvxposoffset;
6731 sisfb_tvyposoffset = tvyposoffset;
6733 #if !defined(__i386__) && !defined(__x86_64__)
6734 sisfb_resetcard = (resetcard) ? 1 : 0;
6735 if(videoram)
6736 sisfb_videoram = videoram;
6737 #endif
6739 return sisfb_init();
6742 static void __exit sisfb_remove_module(void)
6744 pci_unregister_driver(&sisfb_driver);
6745 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6748 module_init(sisfb_init_module);
6749 module_exit(sisfb_remove_module);
6751 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6752 MODULE_LICENSE("GPL");
6753 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6755 module_param(mem, int, 0);
6756 module_param(noaccel, int, 0);
6757 module_param(noypan, int, 0);
6758 module_param(nomax, int, 0);
6759 module_param(userom, int, 0);
6760 module_param(useoem, int, 0);
6761 module_param(mode, charp, 0);
6762 module_param(vesa, int, 0);
6763 module_param(rate, int, 0);
6764 module_param(forcecrt1, int, 0);
6765 module_param(forcecrt2type, charp, 0);
6766 module_param(scalelcd, int, 0);
6767 module_param(pdc, int, 0);
6768 module_param(pdc1, int, 0);
6769 module_param(specialtiming, charp, 0);
6770 module_param(lvdshl, int, 0);
6771 module_param(tvstandard, charp, 0);
6772 module_param(tvxposoffset, int, 0);
6773 module_param(tvyposoffset, int, 0);
6774 module_param(nocrt2rate, int, 0);
6775 #if !defined(__i386__) && !defined(__x86_64__)
6776 module_param(resetcard, int, 0);
6777 module_param(videoram, int, 0);
6778 #endif
6780 MODULE_PARM_DESC(mem,
6781 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6782 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6783 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6784 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6785 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6786 "The value is to be specified without 'KB'.\n");
6788 MODULE_PARM_DESC(noaccel,
6789 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6790 "(default: 0)\n");
6792 MODULE_PARM_DESC(noypan,
6793 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6794 "will be performed by redrawing the screen. (default: 0)\n");
6796 MODULE_PARM_DESC(nomax,
6797 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
6798 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6799 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6800 "enable the user to positively specify a virtual Y size of the screen using\n"
6801 "fbset. (default: 0)\n");
6803 MODULE_PARM_DESC(mode,
6804 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6805 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
6806 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6807 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6809 MODULE_PARM_DESC(vesa,
6810 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6811 "0x117 (default: 0x0103)\n");
6813 MODULE_PARM_DESC(rate,
6814 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6815 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6816 "will be ignored (default: 60)\n");
6818 MODULE_PARM_DESC(forcecrt1,
6819 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6820 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6821 "0=CRT1 OFF) (default: [autodetected])\n");
6823 MODULE_PARM_DESC(forcecrt2type,
6824 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6825 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6826 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6827 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6828 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6829 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6830 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6831 "depends on the very hardware in use. (default: [autodetected])\n");
6833 MODULE_PARM_DESC(scalelcd,
6834 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6835 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6836 "show black bars around the image, TMDS panels will probably do the scaling\n"
6837 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6839 MODULE_PARM_DESC(pdc,
6840 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
6841 "should detect this correctly in most cases; however, sometimes this is not\n"
6842 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
6843 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6844 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6845 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
6847 #ifdef CONFIG_FB_SIS_315
6848 MODULE_PARM_DESC(pdc1,
6849 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
6850 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6851 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6852 "implemented yet.\n");
6853 #endif
6855 MODULE_PARM_DESC(specialtiming,
6856 "\nPlease refer to documentation for more information on this option.\n");
6858 MODULE_PARM_DESC(lvdshl,
6859 "\nPlease refer to documentation for more information on this option.\n");
6861 MODULE_PARM_DESC(tvstandard,
6862 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6863 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6865 MODULE_PARM_DESC(tvxposoffset,
6866 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6867 "Default: 0\n");
6869 MODULE_PARM_DESC(tvyposoffset,
6870 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6871 "Default: 0\n");
6873 MODULE_PARM_DESC(nocrt2rate,
6874 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6875 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6877 #if !defined(__i386__) && !defined(__x86_64__)
6878 #ifdef CONFIG_FB_SIS_300
6879 MODULE_PARM_DESC(resetcard,
6880 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
6881 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6882 "currently). Default: 0\n");
6884 MODULE_PARM_DESC(videoram,
6885 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6886 "some non-x86 architectures where the memory auto detection fails. Only\n"
6887 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
6888 #endif
6889 #endif
6891 #endif /* /MODULE */
6893 /* _GPL only for new symbols. */
6894 EXPORT_SYMBOL(sis_malloc);
6895 EXPORT_SYMBOL(sis_free);
6896 EXPORT_SYMBOL_GPL(sis_malloc_new);
6897 EXPORT_SYMBOL_GPL(sis_free_new);