[PATCH] drivers/video/sis/init301.h: removal of old code
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / video / sis / sis_main.c
blob895ebda7d9e3547443785aa6e465589acd2457cf
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 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
39 #include <linux/moduleparam.h>
40 #endif
41 #include <linux/kernel.h>
42 #include <linux/smp_lock.h>
43 #include <linux/spinlock.h>
44 #include <linux/errno.h>
45 #include <linux/string.h>
46 #include <linux/mm.h>
48 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
49 #include <linux/tty.h>
50 #else
51 #include <linux/screen_info.h>
52 #endif
54 #include <linux/slab.h>
55 #include <linux/fb.h>
56 #include <linux/selection.h>
57 #include <linux/ioport.h>
58 #include <linux/init.h>
59 #include <linux/pci.h>
60 #include <linux/vmalloc.h>
61 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
62 #include <linux/vt_kern.h>
63 #endif
64 #include <linux/capability.h>
65 #include <linux/fs.h>
66 #include <linux/types.h>
67 #include <asm/uaccess.h>
68 #include <asm/io.h>
69 #ifdef CONFIG_MTRR
70 #include <asm/mtrr.h>
71 #endif
73 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
74 #include <video/fbcon.h>
75 #include <video/fbcon-cfb8.h>
76 #include <video/fbcon-cfb16.h>
77 #include <video/fbcon-cfb24.h>
78 #include <video/fbcon-cfb32.h>
79 #endif
81 #include "sis.h"
82 #include "sis_main.h"
84 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
85 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
86 #error "This version of sisfb requires at least 2.6.3"
87 #endif
88 #endif
90 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
91 #ifdef FBCON_HAS_CFB8
92 extern struct display_switch fbcon_sis8;
93 #endif
94 #ifdef FBCON_HAS_CFB16
95 extern struct display_switch fbcon_sis16;
96 #endif
97 #ifdef FBCON_HAS_CFB32
98 extern struct display_switch fbcon_sis32;
99 #endif
100 #endif
102 static void sisfb_handle_command(struct sis_video_info *ivideo,
103 struct sisfb_cmd *sisfb_command);
105 /* ------------------ Internal helper routines ----------------- */
107 static void __init
108 sisfb_setdefaultparms(void)
110 sisfb_off = 0;
111 sisfb_parm_mem = 0;
112 sisfb_accel = -1;
113 sisfb_ypan = -1;
114 sisfb_max = -1;
115 sisfb_userom = -1;
116 sisfb_useoem = -1;
117 #ifdef MODULE
118 /* Module: "None" for 2.4, default mode for 2.5+ */
119 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
120 sisfb_mode_idx = -1;
121 #else
122 sisfb_mode_idx = MODE_INDEX_NONE;
123 #endif
124 #else
125 /* Static: Default mode */
126 sisfb_mode_idx = -1;
127 #endif
128 sisfb_parm_rate = -1;
129 sisfb_crt1off = 0;
130 sisfb_forcecrt1 = -1;
131 sisfb_crt2type = -1;
132 sisfb_crt2flags = 0;
133 sisfb_pdc = 0xff;
134 sisfb_pdca = 0xff;
135 sisfb_scalelcd = -1;
136 sisfb_specialtiming = CUT_NONE;
137 sisfb_lvdshl = -1;
138 sisfb_dstn = 0;
139 sisfb_fstn = 0;
140 sisfb_tvplug = -1;
141 sisfb_tvstd = -1;
142 sisfb_tvxposoffset = 0;
143 sisfb_tvyposoffset = 0;
144 sisfb_nocrt2rate = 0;
145 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
146 sisfb_inverse = 0;
147 sisfb_fontname[0] = 0;
148 #endif
149 #if !defined(__i386__) && !defined(__x86_64__)
150 sisfb_resetcard = 0;
151 sisfb_videoram = 0;
152 #endif
155 /* ------------- Parameter parsing -------------- */
157 static void __devinit
158 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
160 int i = 0, j = 0;
162 /* We don't know the hardware specs yet and there is no ivideo */
164 if(vesamode == 0) {
165 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
166 sisfb_mode_idx = MODE_INDEX_NONE;
167 #else
168 if(!quiet)
169 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
171 sisfb_mode_idx = DEFAULT_MODE;
172 #endif
173 return;
176 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
178 while(sisbios_mode[i++].mode_no[0] != 0) {
179 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
180 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
181 if(sisfb_fstn) {
182 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
183 sisbios_mode[i-1].mode_no[1] == 0x56 ||
184 sisbios_mode[i-1].mode_no[1] == 0x53)
185 continue;
186 } else {
187 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
188 sisbios_mode[i-1].mode_no[1] == 0x5b)
189 continue;
191 sisfb_mode_idx = i - 1;
192 j = 1;
193 break;
196 if((!j) && !quiet)
197 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
200 static void __devinit
201 sisfb_search_mode(char *name, BOOLEAN quiet)
203 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
204 int i = 0;
205 char strbuf[16], strbuf1[20];
206 char *nameptr = name;
208 /* We don't know the hardware specs yet and there is no ivideo */
210 if(name == NULL) {
211 if(!quiet)
212 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
214 sisfb_mode_idx = DEFAULT_MODE;
215 return;
218 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
219 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
220 if(!quiet)
221 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
223 sisfb_mode_idx = DEFAULT_MODE;
224 return;
226 #endif
227 if(strlen(name) <= 19) {
228 strcpy(strbuf1, name);
229 for(i = 0; i < strlen(strbuf1); i++) {
230 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
233 /* This does some fuzzy mode naming detection */
234 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
235 if((rate <= 32) || (depth > 32)) {
236 j = rate; rate = depth; depth = j;
238 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
239 nameptr = strbuf;
240 sisfb_parm_rate = rate;
241 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
242 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
243 nameptr = strbuf;
244 } else {
245 xres = 0;
246 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
247 sprintf(strbuf, "%ux%ux8", xres, yres);
248 nameptr = strbuf;
249 } else {
250 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
251 return;
256 i = 0; j = 0;
257 while(sisbios_mode[i].mode_no[0] != 0) {
258 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
259 if(sisfb_fstn) {
260 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
261 sisbios_mode[i-1].mode_no[1] == 0x56 ||
262 sisbios_mode[i-1].mode_no[1] == 0x53)
263 continue;
264 } else {
265 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
266 sisbios_mode[i-1].mode_no[1] == 0x5b)
267 continue;
269 sisfb_mode_idx = i - 1;
270 j = 1;
271 break;
275 if((!j) && !quiet)
276 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
279 #ifndef MODULE
280 static void __devinit
281 sisfb_get_vga_mode_from_kernel(void)
283 #ifdef CONFIG_X86
284 char mymode[32];
285 int mydepth = screen_info.lfb_depth;
287 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
289 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
290 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
291 (mydepth >= 8) && (mydepth <= 32) ) {
293 if(mydepth == 24) mydepth = 32;
295 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
296 screen_info.lfb_height,
297 mydepth);
299 printk(KERN_DEBUG
300 "sisfb: Using vga mode %s pre-set by kernel as default\n",
301 mymode);
303 sisfb_search_mode(mymode, TRUE);
305 #endif
306 return;
308 #endif
310 static void __init
311 sisfb_search_crt2type(const char *name)
313 int i = 0;
315 /* We don't know the hardware specs yet and there is no ivideo */
317 if(name == NULL) return;
319 while(sis_crt2type[i].type_no != -1) {
320 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
321 sisfb_crt2type = sis_crt2type[i].type_no;
322 sisfb_tvplug = sis_crt2type[i].tvplug_no;
323 sisfb_crt2flags = sis_crt2type[i].flags;
324 break;
326 i++;
329 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
330 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
332 if(sisfb_crt2type < 0)
333 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
336 static void __init
337 sisfb_search_tvstd(const char *name)
339 int i = 0;
341 /* We don't know the hardware specs yet and there is no ivideo */
343 if(name == NULL)
344 return;
346 while(sis_tvtype[i].type_no != -1) {
347 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
348 sisfb_tvstd = sis_tvtype[i].type_no;
349 break;
351 i++;
355 static void __init
356 sisfb_search_specialtiming(const char *name)
358 int i = 0;
359 BOOLEAN found = FALSE;
361 /* We don't know the hardware specs yet and there is no ivideo */
363 if(name == NULL)
364 return;
366 if(!strnicmp(name, "none", 4)) {
367 sisfb_specialtiming = CUT_FORCENONE;
368 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
369 } else {
370 while(mycustomttable[i].chipID != 0) {
371 if(!strnicmp(name,mycustomttable[i].optionName,
372 strlen(mycustomttable[i].optionName))) {
373 sisfb_specialtiming = mycustomttable[i].SpecialID;
374 found = TRUE;
375 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
376 mycustomttable[i].vendorName,
377 mycustomttable[i].cardName,
378 mycustomttable[i].optionName);
379 break;
381 i++;
383 if(!found) {
384 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
385 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
386 i = 0;
387 while(mycustomttable[i].chipID != 0) {
388 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
389 mycustomttable[i].optionName,
390 mycustomttable[i].vendorName,
391 mycustomttable[i].cardName);
392 i++;
398 /* ----------- Various detection routines ----------- */
400 static void __devinit
401 sisfb_detect_custom_timing(struct sis_video_info *ivideo)
403 unsigned char *biosver = NULL;
404 unsigned char *biosdate = NULL;
405 BOOLEAN footprint;
406 u32 chksum = 0;
407 int i, j;
409 if(ivideo->SiS_Pr.UseROM) {
410 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
411 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
412 for(i = 0; i < 32768; i++)
413 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
416 i = 0;
417 do {
418 if( (mycustomttable[i].chipID == ivideo->chip) &&
419 ((!strlen(mycustomttable[i].biosversion)) ||
420 (ivideo->SiS_Pr.UseROM &&
421 (!strncmp(mycustomttable[i].biosversion, biosver,
422 strlen(mycustomttable[i].biosversion))))) &&
423 ((!strlen(mycustomttable[i].biosdate)) ||
424 (ivideo->SiS_Pr.UseROM &&
425 (!strncmp(mycustomttable[i].biosdate, biosdate,
426 strlen(mycustomttable[i].biosdate))))) &&
427 ((!mycustomttable[i].bioschksum) ||
428 (ivideo->SiS_Pr.UseROM &&
429 (mycustomttable[i].bioschksum == chksum))) &&
430 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
431 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
432 footprint = TRUE;
433 for(j = 0; j < 5; j++) {
434 if(mycustomttable[i].biosFootprintAddr[j]) {
435 if(ivideo->SiS_Pr.UseROM) {
436 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
437 mycustomttable[i].biosFootprintData[j]) {
438 footprint = FALSE;
440 } else
441 footprint = FALSE;
444 if(footprint) {
445 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
446 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
447 mycustomttable[i].vendorName,
448 mycustomttable[i].cardName);
449 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
450 mycustomttable[i].optionName);
451 break;
454 i++;
455 } while(mycustomttable[i].chipID);
458 static BOOLEAN __devinit
459 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
461 int i, j, xres, yres, refresh, index;
462 u32 emodes;
464 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
465 buffer[2] != 0xff || buffer[3] != 0xff ||
466 buffer[4] != 0xff || buffer[5] != 0xff ||
467 buffer[6] != 0xff || buffer[7] != 0x00) {
468 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
469 return FALSE;
472 if(buffer[0x12] != 0x01) {
473 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
474 buffer[0x12]);
475 return FALSE;
478 monitor->feature = buffer[0x18];
480 if(!buffer[0x14] & 0x80) {
481 if(!(buffer[0x14] & 0x08)) {
482 printk(KERN_INFO
483 "sisfb: WARNING: Monitor does not support separate syncs\n");
487 if(buffer[0x13] >= 0x01) {
488 /* EDID V1 rev 1 and 2: Search for monitor descriptor
489 * to extract ranges
491 j = 0x36;
492 for(i=0; i<4; i++) {
493 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
494 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
495 buffer[j + 4] == 0x00) {
496 monitor->hmin = buffer[j + 7];
497 monitor->hmax = buffer[j + 8];
498 monitor->vmin = buffer[j + 5];
499 monitor->vmax = buffer[j + 6];
500 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
501 monitor->datavalid = TRUE;
502 break;
504 j += 18;
508 if(!monitor->datavalid) {
509 /* Otherwise: Get a range from the list of supported
510 * Estabished Timings. This is not entirely accurate,
511 * because fixed frequency monitors are not supported
512 * that way.
514 monitor->hmin = 65535; monitor->hmax = 0;
515 monitor->vmin = 65535; monitor->vmax = 0;
516 monitor->dclockmax = 0;
517 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
518 for(i = 0; i < 13; i++) {
519 if(emodes & sisfb_ddcsmodes[i].mask) {
520 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
521 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
522 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
523 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
524 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
527 index = 0x26;
528 for(i = 0; i < 8; i++) {
529 xres = (buffer[index] + 31) * 8;
530 switch(buffer[index + 1] & 0xc0) {
531 case 0xc0: yres = (xres * 9) / 16; break;
532 case 0x80: yres = (xres * 4) / 5; break;
533 case 0x40: yres = (xres * 3) / 4; break;
534 default: yres = xres; break;
536 refresh = (buffer[index + 1] & 0x3f) + 60;
537 if((xres >= 640) && (yres >= 480)) {
538 for(j = 0; j < 8; j++) {
539 if((xres == sisfb_ddcfmodes[j].x) &&
540 (yres == sisfb_ddcfmodes[j].y) &&
541 (refresh == sisfb_ddcfmodes[j].v)) {
542 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
543 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
544 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
545 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
546 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
550 index += 2;
552 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
553 monitor->datavalid = TRUE;
557 return monitor->datavalid;
560 static void __devinit
561 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
563 unsigned short temp, i, realcrtno = crtno;
564 unsigned char buffer[256];
566 monitor->datavalid = FALSE;
568 if(crtno) {
569 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
570 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
571 else return;
574 if((ivideo->sisfb_crt1off) && (!crtno))
575 return;
577 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
578 realcrtno, 0, &buffer[0], ivideo->vbflags2);
579 if((!temp) || (temp == 0xffff)) {
580 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
581 return;
582 } else {
583 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
584 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
585 crtno + 1,
586 (temp & 0x1a) ? "" : "[none of the supported]",
587 (temp & 0x02) ? "2 " : "",
588 (temp & 0x08) ? "D&P" : "",
589 (temp & 0x10) ? "FPDI-2" : "");
590 if(temp & 0x02) {
591 i = 3; /* Number of retrys */
592 do {
593 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
594 realcrtno, 1, &buffer[0], ivideo->vbflags2);
595 } while((temp) && i--);
596 if(!temp) {
597 if(sisfb_interpret_edid(monitor, &buffer[0])) {
598 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
599 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
600 monitor->dclockmax / 1000);
601 } else {
602 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
604 } else {
605 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
607 } else {
608 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
613 /* -------------- Mode validation --------------- */
615 static BOOLEAN
616 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
617 int mode_idx, int rate_idx, int rate)
619 int htotal, vtotal;
620 unsigned int dclock, hsync;
622 if(!monitor->datavalid)
623 return TRUE;
625 if(mode_idx < 0)
626 return FALSE;
628 /* Skip for 320x200, 320x240, 640x400 */
629 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
630 case 0x59:
631 case 0x41:
632 case 0x4f:
633 case 0x50:
634 case 0x56:
635 case 0x53:
636 case 0x2f:
637 case 0x5d:
638 case 0x5e:
639 return TRUE;
640 #ifdef CONFIG_FB_SIS_315
641 case 0x5a:
642 case 0x5b:
643 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
644 #endif
647 if(rate < (monitor->vmin - 1))
648 return FALSE;
649 if(rate > (monitor->vmax + 1))
650 return FALSE;
652 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
653 sisbios_mode[mode_idx].mode_no[ivideo->mni],
654 &htotal, &vtotal, rate_idx)) {
655 dclock = (htotal * vtotal * rate) / 1000;
656 if(dclock > (monitor->dclockmax + 1000))
657 return FALSE;
658 hsync = dclock / htotal;
659 if(hsync < (monitor->hmin - 1))
660 return FALSE;
661 if(hsync > (monitor->hmax + 1))
662 return FALSE;
663 } else {
664 return FALSE;
666 return TRUE;
669 static int
670 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
672 u16 xres=0, yres, myres;
674 #ifdef CONFIG_FB_SIS_300
675 if(ivideo->sisvga_engine == SIS_300_VGA) {
676 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
677 return -1 ;
679 #endif
680 #ifdef CONFIG_FB_SIS_315
681 if(ivideo->sisvga_engine == SIS_315_VGA) {
682 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
683 return -1;
685 #endif
687 myres = sisbios_mode[myindex].yres;
689 switch(vbflags & VB_DISPTYPE_DISP2) {
691 case CRT2_LCD:
692 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
694 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
695 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
696 if(sisbios_mode[myindex].xres > xres)
697 return -1;
698 if(myres > yres)
699 return -1;
702 if(ivideo->sisfb_fstn) {
703 if(sisbios_mode[myindex].xres == 320) {
704 if(myres == 240) {
705 switch(sisbios_mode[myindex].mode_no[1]) {
706 case 0x50: myindex = MODE_FSTN_8; break;
707 case 0x56: myindex = MODE_FSTN_16; break;
708 case 0x53: return -1;
714 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
715 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
716 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
717 return -1;
719 break;
721 case CRT2_TV:
722 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
723 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
724 return -1;
726 break;
728 case CRT2_VGA:
729 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
730 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
731 return -1;
733 break;
736 return myindex;
739 static u8
740 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
742 int i = 0;
743 u16 xres = sisbios_mode[mode_idx].xres;
744 u16 yres = sisbios_mode[mode_idx].yres;
746 ivideo->rate_idx = 0;
747 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
748 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
749 if(sisfb_vrate[i].refresh == rate) {
750 ivideo->rate_idx = sisfb_vrate[i].idx;
751 break;
752 } else if(sisfb_vrate[i].refresh > rate) {
753 if((sisfb_vrate[i].refresh - rate) <= 3) {
754 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
755 rate, sisfb_vrate[i].refresh);
756 ivideo->rate_idx = sisfb_vrate[i].idx;
757 ivideo->refresh_rate = sisfb_vrate[i].refresh;
758 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
759 && (sisfb_vrate[i].idx != 1)) {
760 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
761 rate, sisfb_vrate[i-1].refresh);
762 ivideo->rate_idx = sisfb_vrate[i-1].idx;
763 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
765 break;
766 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
767 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
768 rate, sisfb_vrate[i].refresh);
769 ivideo->rate_idx = sisfb_vrate[i].idx;
770 break;
773 i++;
775 if(ivideo->rate_idx > 0) {
776 return ivideo->rate_idx;
777 } else {
778 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
779 rate, xres, yres);
780 return 0;
784 static BOOLEAN
785 sisfb_bridgeisslave(struct sis_video_info *ivideo)
787 unsigned char P1_00;
789 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
790 return FALSE;
792 inSISIDXREG(SISPART1,0x00,P1_00);
793 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
794 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
795 return TRUE;
796 } else {
797 return FALSE;
801 static BOOLEAN
802 sisfballowretracecrt1(struct sis_video_info *ivideo)
804 u8 temp;
806 inSISIDXREG(SISCR,0x17,temp);
807 if(!(temp & 0x80))
808 return FALSE;
810 inSISIDXREG(SISSR,0x1f,temp);
811 if(temp & 0xc0)
812 return FALSE;
814 return TRUE;
817 static BOOLEAN
818 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
820 if(!sisfballowretracecrt1(ivideo))
821 return FALSE;
823 if(inSISREG(SISINPSTAT) & 0x08)
824 return TRUE;
825 else
826 return FALSE;
829 static void
830 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
832 int watchdog;
834 if(!sisfballowretracecrt1(ivideo))
835 return;
837 watchdog = 65536;
838 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
839 watchdog = 65536;
840 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
843 static BOOLEAN
844 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
846 unsigned char temp, reg;
848 switch(ivideo->sisvga_engine) {
849 case SIS_300_VGA: reg = 0x25; break;
850 case SIS_315_VGA: reg = 0x30; break;
851 default: return FALSE;
854 inSISIDXREG(SISPART1, reg, temp);
855 if(temp & 0x02)
856 return TRUE;
857 else
858 return FALSE;
861 static BOOLEAN
862 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
864 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
865 if(!sisfb_bridgeisslave(ivideo)) {
866 return sisfbcheckvretracecrt2(ivideo);
869 return sisfbcheckvretracecrt1(ivideo);
872 static u32
873 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
875 u8 idx, reg1, reg2, reg3, reg4;
876 u32 ret = 0;
878 (*vcount) = (*hcount) = 0;
880 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
882 ret |= (FB_VBLANK_HAVE_VSYNC |
883 FB_VBLANK_HAVE_HBLANK |
884 FB_VBLANK_HAVE_VBLANK |
885 FB_VBLANK_HAVE_VCOUNT |
886 FB_VBLANK_HAVE_HCOUNT);
887 switch(ivideo->sisvga_engine) {
888 case SIS_300_VGA: idx = 0x25; break;
889 default:
890 case SIS_315_VGA: idx = 0x30; break;
892 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
893 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
894 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
895 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
896 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
897 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
898 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
899 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
900 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
902 } else if(sisfballowretracecrt1(ivideo)) {
904 ret |= (FB_VBLANK_HAVE_VSYNC |
905 FB_VBLANK_HAVE_VBLANK |
906 FB_VBLANK_HAVE_VCOUNT |
907 FB_VBLANK_HAVE_HCOUNT);
908 reg1 = inSISREG(SISINPSTAT);
909 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
910 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
911 inSISIDXREG(SISCR,0x20,reg1);
912 inSISIDXREG(SISCR,0x1b,reg1);
913 inSISIDXREG(SISCR,0x1c,reg2);
914 inSISIDXREG(SISCR,0x1d,reg3);
915 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
916 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
919 return ret;
922 static int
923 sisfb_myblank(struct sis_video_info *ivideo, int blank)
925 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
926 BOOLEAN backlight = TRUE;
928 switch(blank) {
929 case FB_BLANK_UNBLANK: /* on */
930 sr01 = 0x00;
931 sr11 = 0x00;
932 sr1f = 0x00;
933 cr63 = 0x00;
934 p2_0 = 0x20;
935 p1_13 = 0x00;
936 backlight = TRUE;
937 break;
938 case FB_BLANK_NORMAL: /* blank */
939 sr01 = 0x20;
940 sr11 = 0x00;
941 sr1f = 0x00;
942 cr63 = 0x00;
943 p2_0 = 0x20;
944 p1_13 = 0x00;
945 backlight = TRUE;
946 break;
947 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
948 sr01 = 0x20;
949 sr11 = 0x08;
950 sr1f = 0x80;
951 cr63 = 0x40;
952 p2_0 = 0x40;
953 p1_13 = 0x80;
954 backlight = FALSE;
955 break;
956 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
957 sr01 = 0x20;
958 sr11 = 0x08;
959 sr1f = 0x40;
960 cr63 = 0x40;
961 p2_0 = 0x80;
962 p1_13 = 0x40;
963 backlight = FALSE;
964 break;
965 case FB_BLANK_POWERDOWN: /* off */
966 sr01 = 0x20;
967 sr11 = 0x08;
968 sr1f = 0xc0;
969 cr63 = 0x40;
970 p2_0 = 0xc0;
971 p1_13 = 0xc0;
972 backlight = FALSE;
973 break;
974 default:
975 return 1;
978 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
980 if( (!ivideo->sisfb_thismonitor.datavalid) ||
981 ((ivideo->sisfb_thismonitor.datavalid) &&
982 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
984 if(ivideo->sisvga_engine == SIS_315_VGA) {
985 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
988 if(!(sisfb_bridgeisslave(ivideo))) {
989 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
990 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
996 if(ivideo->currentvbflags & CRT2_LCD) {
998 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
999 if(backlight) {
1000 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
1001 } else {
1002 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
1004 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1005 #ifdef CONFIG_FB_SIS_315
1006 if(ivideo->vbflags2 & VB2_CHRONTEL) {
1007 if(backlight) {
1008 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
1009 } else {
1010 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
1013 #endif
1016 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
1017 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
1018 ((ivideo->sisvga_engine == SIS_315_VGA) &&
1019 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
1020 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
1023 if(ivideo->sisvga_engine == SIS_300_VGA) {
1024 if((ivideo->vbflags2 & VB2_30xB) &&
1025 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1026 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
1028 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1029 if((ivideo->vbflags2 & VB2_30xB) &&
1030 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1031 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1035 } else if(ivideo->currentvbflags & CRT2_VGA) {
1037 if(ivideo->vbflags2 & VB2_30xB) {
1038 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1043 return 0;
1046 /* ------------- Callbacks from init.c/init301.c -------------- */
1048 #ifdef CONFIG_FB_SIS_300
1049 unsigned int
1050 sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1052 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1053 u32 val = 0;
1055 pci_read_config_dword(ivideo->nbridge, reg, &val);
1056 return (unsigned int)val;
1059 void
1060 sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1062 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1064 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1067 unsigned int
1068 sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1070 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1071 u32 val = 0;
1073 if(!ivideo->lpcdev) return 0;
1075 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1076 return (unsigned int)val;
1078 #endif
1080 #ifdef CONFIG_FB_SIS_315
1081 void
1082 sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1084 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1086 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1089 unsigned int
1090 sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1092 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1093 u16 val = 0;
1095 if(!ivideo->lpcdev) return 0;
1097 pci_read_config_word(ivideo->lpcdev, reg, &val);
1098 return (unsigned int)val;
1100 #endif
1102 /* ----------- FBDev related routines for all series ----------- */
1104 static int
1105 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1107 return (var->bits_per_pixel == 8) ? 256 : 16;
1110 static void
1111 sisfb_set_vparms(struct sis_video_info *ivideo)
1113 switch(ivideo->video_bpp) {
1114 case 8:
1115 ivideo->DstColor = 0x0000;
1116 ivideo->SiS310_AccelDepth = 0x00000000;
1117 ivideo->video_cmap_len = 256;
1118 break;
1119 case 16:
1120 ivideo->DstColor = 0x8000;
1121 ivideo->SiS310_AccelDepth = 0x00010000;
1122 ivideo->video_cmap_len = 16;
1123 break;
1124 case 32:
1125 ivideo->DstColor = 0xC000;
1126 ivideo->SiS310_AccelDepth = 0x00020000;
1127 ivideo->video_cmap_len = 16;
1128 break;
1129 default:
1130 ivideo->video_cmap_len = 16;
1131 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1132 ivideo->accel = 0;
1136 static int
1137 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1139 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1141 if(maxyres > 32767) maxyres = 32767;
1143 return maxyres;
1146 static void
1147 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1149 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1150 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1151 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1152 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1153 ivideo->scrnpitchCRT1 <<= 1;
1158 static void
1159 sisfb_set_pitch(struct sis_video_info *ivideo)
1161 BOOLEAN isslavemode = FALSE;
1162 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1163 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1165 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
1167 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1168 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1169 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1170 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1173 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1174 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1175 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1176 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1177 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1181 static void
1182 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1184 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1186 switch(var->bits_per_pixel) {
1187 case 8:
1188 var->red.offset = var->green.offset = var->blue.offset = 0;
1189 var->red.length = var->green.length = var->blue.length = 6;
1190 break;
1191 case 16:
1192 var->red.offset = 11;
1193 var->red.length = 5;
1194 var->green.offset = 5;
1195 var->green.length = 6;
1196 var->blue.offset = 0;
1197 var->blue.length = 5;
1198 var->transp.offset = 0;
1199 var->transp.length = 0;
1200 break;
1201 case 32:
1202 var->red.offset = 16;
1203 var->red.length = 8;
1204 var->green.offset = 8;
1205 var->green.length = 8;
1206 var->blue.offset = 0;
1207 var->blue.length = 8;
1208 var->transp.offset = 24;
1209 var->transp.length = 8;
1210 break;
1214 static int
1215 sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1217 unsigned short modeno = ivideo->mode_no;
1219 /* >=2.6.12's fbcon clears the screen anyway */
1220 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
1221 if(!clrscrn) modeno |= 0x80;
1222 #else
1223 modeno |= 0x80;
1224 #endif
1226 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1228 sisfb_pre_setmode(ivideo);
1230 if(SiSSetMode(&ivideo->SiS_Pr, modeno) == 0) {
1231 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1232 return -EINVAL;
1235 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1237 sisfb_post_setmode(ivideo);
1239 return 0;
1243 static int
1244 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1246 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1247 unsigned int htotal = 0, vtotal = 0;
1248 unsigned int drate = 0, hrate = 0;
1249 int found_mode = 0, ret;
1250 int old_mode;
1251 u32 pixclock;
1253 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1255 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1257 pixclock = var->pixclock;
1259 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1260 vtotal += var->yres;
1261 vtotal <<= 1;
1262 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1263 vtotal += var->yres;
1264 vtotal <<= 2;
1265 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1266 vtotal += var->yres;
1267 vtotal <<= 1;
1268 } else vtotal += var->yres;
1270 if(!(htotal) || !(vtotal)) {
1271 DPRINTK("sisfb: Invalid 'var' information\n");
1272 return -EINVAL;
1275 if(pixclock && htotal && vtotal) {
1276 drate = 1000000000 / pixclock;
1277 hrate = (drate * 1000) / htotal;
1278 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1279 } else {
1280 ivideo->refresh_rate = 60;
1283 old_mode = ivideo->sisfb_mode_idx;
1284 ivideo->sisfb_mode_idx = 0;
1286 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1287 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1288 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1289 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1290 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1291 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1292 found_mode = 1;
1293 break;
1295 ivideo->sisfb_mode_idx++;
1298 if(found_mode) {
1299 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1300 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1301 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1302 } else {
1303 ivideo->sisfb_mode_idx = -1;
1306 if(ivideo->sisfb_mode_idx < 0) {
1307 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1308 var->yres, var->bits_per_pixel);
1309 ivideo->sisfb_mode_idx = old_mode;
1310 return -EINVAL;
1313 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1314 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1315 ivideo->refresh_rate = 60;
1318 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1319 if(ivideo->sisfb_thismonitor.datavalid) {
1320 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
1321 ivideo->rate_idx, ivideo->refresh_rate)) {
1322 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1325 #endif
1327 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1328 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1329 #else
1330 if(isactive) {
1331 #endif
1332 /* If acceleration to be used? Need to know
1333 * before pre/post_set_mode()
1335 ivideo->accel = 0;
1336 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1337 #ifdef STUPID_ACCELF_TEXT_SHIT
1338 if(var->accel_flags & FB_ACCELF_TEXT) {
1339 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1340 } else {
1341 info->flags |= FBINFO_HWACCEL_DISABLED;
1343 #endif
1344 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1345 #else
1346 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1347 #endif
1349 if((ret = sisfb_set_mode(ivideo, 1))) {
1350 return ret;
1353 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1354 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1355 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1357 sisfb_calc_pitch(ivideo, var);
1358 sisfb_set_pitch(ivideo);
1360 sisfb_set_vparms(ivideo);
1362 ivideo->current_width = ivideo->video_width;
1363 ivideo->current_height = ivideo->video_height;
1364 ivideo->current_bpp = ivideo->video_bpp;
1365 ivideo->current_htotal = htotal;
1366 ivideo->current_vtotal = vtotal;
1367 ivideo->current_linelength = ivideo->video_linelength;
1368 ivideo->current_pixclock = var->pixclock;
1369 ivideo->current_refresh_rate = ivideo->refresh_rate;
1370 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1371 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1372 #endif
1375 return 0;
1378 static void
1379 sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1381 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1383 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1384 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1385 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1386 if(ivideo->sisvga_engine == SIS_315_VGA) {
1387 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1391 static void
1392 sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1394 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1395 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1396 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1397 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1398 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1399 if(ivideo->sisvga_engine == SIS_315_VGA) {
1400 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1405 static int
1406 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1408 if(var->xoffset > (var->xres_virtual - var->xres)) {
1409 return -EINVAL;
1411 if(var->yoffset > (var->yres_virtual - var->yres)) {
1412 return -EINVAL;
1415 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
1417 /* calculate base bpp dep. */
1418 switch(var->bits_per_pixel) {
1419 case 32:
1420 break;
1421 case 16:
1422 ivideo->current_base >>= 1;
1423 break;
1424 case 8:
1425 default:
1426 ivideo->current_base >>= 2;
1427 break;
1430 ivideo->current_base += (ivideo->video_offset >> 2);
1432 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1433 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1435 return 0;
1438 /* ------------ FBDev related routines for 2.4 series ----------- */
1440 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1442 #include "sisfb_fbdev_2_4.h"
1444 #endif
1446 /* ------------ FBDev related routines for 2.6 series ----------- */
1448 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1450 static int
1451 sisfb_open(struct fb_info *info, int user)
1453 return 0;
1456 static int
1457 sisfb_release(struct fb_info *info, int user)
1459 return 0;
1462 static int
1463 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1464 unsigned transp, struct fb_info *info)
1466 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1468 if(regno >= sisfb_get_cmap_len(&info->var))
1469 return 1;
1471 switch(info->var.bits_per_pixel) {
1472 case 8:
1473 outSISREG(SISDACA, regno);
1474 outSISREG(SISDACD, (red >> 10));
1475 outSISREG(SISDACD, (green >> 10));
1476 outSISREG(SISDACD, (blue >> 10));
1477 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1478 outSISREG(SISDAC2A, regno);
1479 outSISREG(SISDAC2D, (red >> 8));
1480 outSISREG(SISDAC2D, (green >> 8));
1481 outSISREG(SISDAC2D, (blue >> 8));
1483 break;
1484 case 16:
1485 ((u32 *)(info->pseudo_palette))[regno] =
1486 (red & 0xf800) |
1487 ((green & 0xfc00) >> 5) |
1488 ((blue & 0xf800) >> 11);
1489 break;
1490 case 32:
1491 red >>= 8;
1492 green >>= 8;
1493 blue >>= 8;
1494 ((u32 *)(info->pseudo_palette))[regno] =
1495 (red << 16) | (green << 8) | (blue);
1496 break;
1498 return 0;
1501 static int
1502 sisfb_set_par(struct fb_info *info)
1504 int err;
1506 if((err = sisfb_do_set_var(&info->var, 1, info)))
1507 return err;
1509 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1510 sisfb_get_fix(&info->fix, info->currcon, info);
1511 #else
1512 sisfb_get_fix(&info->fix, -1, info);
1513 #endif
1514 return 0;
1517 static int
1518 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1520 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1521 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1522 unsigned int drate = 0, hrate = 0, maxyres;
1523 int found_mode = 0;
1524 int refresh_rate, search_idx, tidx;
1525 BOOLEAN recalc_clock = FALSE;
1526 u32 pixclock;
1528 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1530 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1532 pixclock = var->pixclock;
1534 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1535 vtotal += var->yres;
1536 vtotal <<= 1;
1537 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1538 vtotal += var->yres;
1539 vtotal <<= 2;
1540 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1541 vtotal += var->yres;
1542 vtotal <<= 1;
1543 } else
1544 vtotal += var->yres;
1546 if(!(htotal) || !(vtotal)) {
1547 SISFAIL("sisfb: no valid timing data");
1550 search_idx = 0;
1551 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1552 (sisbios_mode[search_idx].xres <= var->xres) ) {
1553 if( (sisbios_mode[search_idx].xres == var->xres) &&
1554 (sisbios_mode[search_idx].yres == var->yres) &&
1555 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1556 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1557 ivideo->currentvbflags)) > 0) {
1558 found_mode = 1;
1559 search_idx = tidx;
1560 break;
1563 search_idx++;
1566 if(!found_mode) {
1567 search_idx = 0;
1568 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1569 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1570 (var->yres <= sisbios_mode[search_idx].yres) &&
1571 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1572 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1573 ivideo->currentvbflags)) > 0) {
1574 found_mode = 1;
1575 search_idx = tidx;
1576 break;
1579 search_idx++;
1581 if(found_mode) {
1582 printk(KERN_DEBUG
1583 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1584 var->xres, var->yres, var->bits_per_pixel,
1585 sisbios_mode[search_idx].xres,
1586 sisbios_mode[search_idx].yres,
1587 var->bits_per_pixel);
1588 var->xres = sisbios_mode[search_idx].xres;
1589 var->yres = sisbios_mode[search_idx].yres;
1590 } else {
1591 printk(KERN_ERR
1592 "sisfb: Failed to find supported mode near %dx%dx%d\n",
1593 var->xres, var->yres, var->bits_per_pixel);
1594 return -EINVAL;
1598 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1599 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1600 (var->bits_per_pixel == 8) ) {
1601 /* Slave modes on LVDS and 301B-DH */
1602 refresh_rate = 60;
1603 recalc_clock = TRUE;
1604 } else if( (ivideo->current_htotal == htotal) &&
1605 (ivideo->current_vtotal == vtotal) &&
1606 (ivideo->current_pixclock == pixclock) ) {
1607 /* x=x & y=y & c=c -> assume depth change */
1608 drate = 1000000000 / pixclock;
1609 hrate = (drate * 1000) / htotal;
1610 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1611 } else if( ( (ivideo->current_htotal != htotal) ||
1612 (ivideo->current_vtotal != vtotal) ) &&
1613 (ivideo->current_pixclock == var->pixclock) ) {
1614 /* x!=x | y!=y & c=c -> invalid pixclock */
1615 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1616 refresh_rate =
1617 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1618 } else if(ivideo->sisfb_parm_rate != -1) {
1619 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1620 refresh_rate = ivideo->sisfb_parm_rate;
1621 } else {
1622 refresh_rate = 60;
1624 recalc_clock = TRUE;
1625 } else if((pixclock) && (htotal) && (vtotal)) {
1626 drate = 1000000000 / pixclock;
1627 hrate = (drate * 1000) / htotal;
1628 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1629 } else if(ivideo->current_refresh_rate) {
1630 refresh_rate = ivideo->current_refresh_rate;
1631 recalc_clock = TRUE;
1632 } else {
1633 refresh_rate = 60;
1634 recalc_clock = TRUE;
1637 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1639 /* Eventually recalculate timing and clock */
1640 if(recalc_clock) {
1641 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1642 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1643 sisbios_mode[search_idx].mode_no[ivideo->mni],
1644 myrateindex));
1645 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1646 sisbios_mode[search_idx].mode_no[ivideo->mni],
1647 myrateindex, var);
1648 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1649 var->pixclock <<= 1;
1653 if(ivideo->sisfb_thismonitor.datavalid) {
1654 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1655 myrateindex, refresh_rate)) {
1656 printk(KERN_INFO
1657 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1661 /* Adapt RGB settings */
1662 sisfb_bpp_to_var(ivideo, var);
1664 /* Sanity check for offsets */
1665 if(var->xoffset < 0) var->xoffset = 0;
1666 if(var->yoffset < 0) var->yoffset = 0;
1668 if(var->xres > var->xres_virtual)
1669 var->xres_virtual = var->xres;
1671 if(ivideo->sisfb_ypan) {
1672 maxyres = sisfb_calc_maxyres(ivideo, var);
1673 if(ivideo->sisfb_max) {
1674 var->yres_virtual = maxyres;
1675 } else {
1676 if(var->yres_virtual > maxyres) {
1677 var->yres_virtual = maxyres;
1680 if(var->yres_virtual <= var->yres) {
1681 var->yres_virtual = var->yres;
1683 } else {
1684 if(var->yres != var->yres_virtual) {
1685 var->yres_virtual = var->yres;
1687 var->xoffset = 0;
1688 var->yoffset = 0;
1691 /* Truncate offsets to maximum if too high */
1692 if(var->xoffset > var->xres_virtual - var->xres) {
1693 var->xoffset = var->xres_virtual - var->xres - 1;
1696 if(var->yoffset > var->yres_virtual - var->yres) {
1697 var->yoffset = var->yres_virtual - var->yres - 1;
1700 /* Set everything else to 0 */
1701 var->red.msb_right =
1702 var->green.msb_right =
1703 var->blue.msb_right =
1704 var->transp.offset =
1705 var->transp.length =
1706 var->transp.msb_right = 0;
1708 return 0;
1711 static int
1712 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1714 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1715 int err;
1717 if(var->xoffset > (var->xres_virtual - var->xres))
1718 return -EINVAL;
1720 if(var->yoffset > (var->yres_virtual - var->yres))
1721 return -EINVAL;
1723 if(var->vmode & FB_VMODE_YWRAP)
1724 return -EINVAL;
1726 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
1727 var->yoffset + info->var.yres > info->var.yres_virtual)
1728 return -EINVAL;
1730 if((err = sisfb_pan_var(ivideo, var)) < 0)
1731 return err;
1733 info->var.xoffset = var->xoffset;
1734 info->var.yoffset = var->yoffset;
1736 return 0;
1739 static int
1740 sisfb_blank(int blank, struct fb_info *info)
1742 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1744 return sisfb_myblank(ivideo, blank);
1747 #endif
1749 /* ----------- FBDev related routines for all series ---------- */
1751 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1752 static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1753 unsigned long arg)
1754 #else
1755 static int sisfb_ioctl(struct inode *inode, struct file *file,
1756 unsigned int cmd, unsigned long arg,
1757 struct fb_info *info)
1758 #endif
1760 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1761 struct sis_memreq sismemreq;
1762 struct fb_vblank sisvbblank;
1763 u32 gpu32 = 0;
1764 #ifndef __user
1765 #define __user
1766 #endif
1767 u32 __user *argp = (u32 __user *)arg;
1769 switch(cmd) {
1770 case FBIO_ALLOC:
1771 if(!capable(CAP_SYS_RAWIO))
1772 return -EPERM;
1774 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1775 return -EFAULT;
1777 sis_malloc(&sismemreq);
1779 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1780 sis_free((u32)sismemreq.offset);
1781 return -EFAULT;
1783 break;
1785 case FBIO_FREE:
1786 if(!capable(CAP_SYS_RAWIO))
1787 return -EPERM;
1789 if(get_user(gpu32, argp))
1790 return -EFAULT;
1792 sis_free(gpu32);
1793 break;
1795 case FBIOGET_VBLANK:
1796 sisvbblank.count = 0;
1797 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1799 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1800 return -EFAULT;
1802 break;
1804 case SISFB_GET_INFO_SIZE:
1805 return put_user(sizeof(struct sisfb_info), argp);
1807 case SISFB_GET_INFO_OLD:
1808 if(ivideo->warncount++ < 10)
1809 printk(KERN_INFO
1810 "sisfb: Deprecated ioctl call received - update your application!\n");
1811 case SISFB_GET_INFO: /* For communication with X driver */
1812 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1813 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1814 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1815 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1816 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1817 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1818 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1819 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1820 if(ivideo->modechanged) {
1821 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1822 } else {
1823 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1825 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1826 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1827 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1828 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1829 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1830 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1831 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1832 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1833 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1834 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1835 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1836 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1837 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1838 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1839 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1840 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1841 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1842 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1843 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1844 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1845 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1846 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1847 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1848 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1849 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1850 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1851 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1852 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1854 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1855 sizeof(ivideo->sisfb_infoblock)))
1856 return -EFAULT;
1858 break;
1860 case SISFB_GET_VBRSTATUS_OLD:
1861 if(ivideo->warncount++ < 10)
1862 printk(KERN_INFO
1863 "sisfb: Deprecated ioctl call received - update your application!\n");
1864 case SISFB_GET_VBRSTATUS:
1865 if(sisfb_CheckVBRetrace(ivideo))
1866 return put_user((u32)1, argp);
1867 else
1868 return put_user((u32)0, argp);
1870 case SISFB_GET_AUTOMAXIMIZE_OLD:
1871 if(ivideo->warncount++ < 10)
1872 printk(KERN_INFO
1873 "sisfb: Deprecated ioctl call received - update your application!\n");
1874 case SISFB_GET_AUTOMAXIMIZE:
1875 if(ivideo->sisfb_max)
1876 return put_user((u32)1, argp);
1877 else
1878 return put_user((u32)0, argp);
1880 case SISFB_SET_AUTOMAXIMIZE_OLD:
1881 if(ivideo->warncount++ < 10)
1882 printk(KERN_INFO
1883 "sisfb: Deprecated ioctl call received - update your application!\n");
1884 case SISFB_SET_AUTOMAXIMIZE:
1885 if(get_user(gpu32, argp))
1886 return -EFAULT;
1888 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1889 break;
1891 case SISFB_SET_TVPOSOFFSET:
1892 if(get_user(gpu32, argp))
1893 return -EFAULT;
1895 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1896 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1897 break;
1899 case SISFB_GET_TVPOSOFFSET:
1900 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1901 argp);
1903 case SISFB_COMMAND:
1904 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1905 sizeof(struct sisfb_cmd)))
1906 return -EFAULT;
1908 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1910 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1911 sizeof(struct sisfb_cmd)))
1912 return -EFAULT;
1914 break;
1916 case SISFB_SET_LOCK:
1917 if(get_user(gpu32, argp))
1918 return -EFAULT;
1920 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1921 break;
1923 default:
1924 #ifdef SIS_NEW_CONFIG_COMPAT
1925 return -ENOIOCTLCMD;
1926 #else
1927 return -EINVAL;
1928 #endif
1930 return 0;
1933 static int
1934 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1936 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1938 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1940 strcpy(fix->id, ivideo->myid);
1942 fix->smem_start = ivideo->video_base + ivideo->video_offset;
1943 fix->smem_len = ivideo->sisfb_mem;
1944 fix->type = FB_TYPE_PACKED_PIXELS;
1945 fix->type_aux = 0;
1946 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1947 fix->xpanstep = 1;
1948 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1949 fix->ywrapstep = 0;
1950 fix->line_length = ivideo->video_linelength;
1951 fix->mmio_start = ivideo->mmio_base;
1952 fix->mmio_len = ivideo->mmio_size;
1953 if(ivideo->sisvga_engine == SIS_300_VGA) {
1954 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1955 } else if((ivideo->chip == SIS_330) ||
1956 (ivideo->chip == SIS_760) ||
1957 (ivideo->chip == SIS_761)) {
1958 fix->accel = FB_ACCEL_SIS_XABRE;
1959 } else if(ivideo->chip == XGI_20) {
1960 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1961 } else if(ivideo->chip >= XGI_40) {
1962 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1963 } else {
1964 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1967 return 0;
1970 /* ---------------- fb_ops structures ----------------- */
1972 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1973 static struct fb_ops sisfb_ops = {
1974 .owner = THIS_MODULE,
1975 .fb_get_fix = sisfb_get_fix,
1976 .fb_get_var = sisfb_get_var,
1977 .fb_set_var = sisfb_set_var,
1978 .fb_get_cmap = sisfb_get_cmap,
1979 .fb_set_cmap = sisfb_set_cmap,
1980 .fb_pan_display = sisfb_pan_display,
1981 .fb_ioctl = sisfb_ioctl
1983 #endif
1985 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1986 static struct fb_ops sisfb_ops = {
1987 .owner = THIS_MODULE,
1988 .fb_open = sisfb_open,
1989 .fb_release = sisfb_release,
1990 .fb_check_var = sisfb_check_var,
1991 .fb_set_par = sisfb_set_par,
1992 .fb_setcolreg = sisfb_setcolreg,
1993 .fb_pan_display = sisfb_pan_display,
1994 .fb_blank = sisfb_blank,
1995 .fb_fillrect = fbcon_sis_fillrect,
1996 .fb_copyarea = fbcon_sis_copyarea,
1997 .fb_imageblit = cfb_imageblit,
1998 #ifdef CONFIG_FB_SOFT_CURSOR
1999 .fb_cursor = soft_cursor,
2000 #endif
2001 .fb_sync = fbcon_sis_sync,
2002 #ifdef SIS_NEW_CONFIG_COMPAT
2003 .fb_compat_ioctl= sisfb_ioctl,
2004 #endif
2005 .fb_ioctl = sisfb_ioctl
2007 #endif
2009 /* ---------------- Chip generation dependent routines ---------------- */
2011 static struct pci_dev * __devinit
2012 sisfb_get_northbridge(int basechipid)
2014 struct pci_dev *pdev = NULL;
2015 int nbridgenum, nbridgeidx, i;
2016 static const unsigned short nbridgeids[] = {
2017 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2018 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2019 PCI_DEVICE_ID_SI_730,
2020 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2021 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2022 PCI_DEVICE_ID_SI_651,
2023 PCI_DEVICE_ID_SI_740,
2024 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
2025 PCI_DEVICE_ID_SI_741,
2026 PCI_DEVICE_ID_SI_660,
2027 PCI_DEVICE_ID_SI_760,
2028 PCI_DEVICE_ID_SI_761
2031 switch(basechipid) {
2032 #ifdef CONFIG_FB_SIS_300
2033 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2034 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2035 #endif
2036 #ifdef CONFIG_FB_SIS_315
2037 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2038 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
2039 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
2040 #endif
2041 default: return NULL;
2043 for(i = 0; i < nbridgenum; i++) {
2044 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2045 nbridgeids[nbridgeidx+i], NULL)))
2046 break;
2048 return pdev;
2051 static int __devinit
2052 sisfb_get_dram_size(struct sis_video_info *ivideo)
2054 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2055 u8 reg;
2056 #endif
2058 ivideo->video_size = 0;
2059 ivideo->UMAsize = ivideo->LFBsize = 0;
2061 switch(ivideo->chip) {
2062 #ifdef CONFIG_FB_SIS_300
2063 case SIS_300:
2064 inSISIDXREG(SISSR, 0x14, reg);
2065 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2066 break;
2067 case SIS_540:
2068 case SIS_630:
2069 case SIS_730:
2070 if(!ivideo->nbridge)
2071 return -1;
2072 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
2073 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2074 break;
2075 #endif
2076 #ifdef CONFIG_FB_SIS_315
2077 case SIS_315H:
2078 case SIS_315PRO:
2079 case SIS_315:
2080 inSISIDXREG(SISSR, 0x14, reg);
2081 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2082 switch((reg >> 2) & 0x03) {
2083 case 0x01:
2084 case 0x03:
2085 ivideo->video_size <<= 1;
2086 break;
2087 case 0x02:
2088 ivideo->video_size += (ivideo->video_size/2);
2090 break;
2091 case SIS_330:
2092 inSISIDXREG(SISSR, 0x14, reg);
2093 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2094 if(reg & 0x0c) ivideo->video_size <<= 1;
2095 break;
2096 case SIS_550:
2097 case SIS_650:
2098 case SIS_740:
2099 inSISIDXREG(SISSR, 0x14, reg);
2100 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2101 break;
2102 case SIS_661:
2103 case SIS_741:
2104 inSISIDXREG(SISCR, 0x79, reg);
2105 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2106 break;
2107 case SIS_660:
2108 case SIS_760:
2109 case SIS_761:
2110 inSISIDXREG(SISCR, 0x79, reg);
2111 reg = (reg & 0xf0) >> 4;
2112 if(reg) {
2113 ivideo->video_size = (1 << reg) << 20;
2114 ivideo->UMAsize = ivideo->video_size;
2116 inSISIDXREG(SISCR, 0x78, reg);
2117 reg &= 0x30;
2118 if(reg) {
2119 if(reg == 0x10) {
2120 ivideo->LFBsize = (32 << 20);
2121 } else {
2122 ivideo->LFBsize = (64 << 20);
2124 ivideo->video_size += ivideo->LFBsize;
2126 break;
2127 case SIS_340:
2128 case XGI_20:
2129 case XGI_40:
2130 inSISIDXREG(SISSR, 0x14, reg);
2131 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2132 if(ivideo->chip != XGI_20) {
2133 reg = (reg & 0x0c) >> 2;
2134 if(ivideo->revision_id == 2) {
2135 if(reg & 0x01) reg = 0x02;
2136 else reg = 0x00;
2138 if(reg == 0x02) ivideo->video_size <<= 1;
2139 else if(reg == 0x03) ivideo->video_size <<= 2;
2141 break;
2142 #endif
2143 default:
2144 return -1;
2146 return 0;
2149 /* -------------- video bridge device detection --------------- */
2151 static void __devinit
2152 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2154 u8 cr32, temp;
2156 /* No CRT2 on XGI Z7 */
2157 if(ivideo->chip == XGI_20) {
2158 ivideo->sisfb_crt1off = 0;
2159 return;
2162 #ifdef CONFIG_FB_SIS_300
2163 if(ivideo->sisvga_engine == SIS_300_VGA) {
2164 inSISIDXREG(SISSR, 0x17, temp);
2165 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2166 /* PAL/NTSC is stored on SR16 on such machines */
2167 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2168 inSISIDXREG(SISSR, 0x16, temp);
2169 if(temp & 0x20)
2170 ivideo->vbflags |= TV_PAL;
2171 else
2172 ivideo->vbflags |= TV_NTSC;
2176 #endif
2178 inSISIDXREG(SISCR, 0x32, cr32);
2180 if(cr32 & SIS_CRT1) {
2181 ivideo->sisfb_crt1off = 0;
2182 } else {
2183 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2186 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2188 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2189 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2190 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2192 /* Check given parms for hardware compatibility.
2193 * (Cannot do this in the search_xx routines since we don't
2194 * know what hardware we are running on then)
2197 if(ivideo->chip != SIS_550) {
2198 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2201 if(ivideo->sisfb_tvplug != -1) {
2202 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2203 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2204 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2205 ivideo->sisfb_tvplug = -1;
2206 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2210 if(ivideo->sisfb_tvplug != -1) {
2211 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2212 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2213 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2214 ivideo->sisfb_tvplug = -1;
2215 printk(KERN_ERR "sisfb: HiVision not supported\n");
2219 if(ivideo->sisfb_tvstd != -1) {
2220 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2221 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2222 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2223 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2224 ivideo->sisfb_tvstd = -1;
2225 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2230 /* Detect/set TV plug & type */
2231 if(ivideo->sisfb_tvplug != -1) {
2232 ivideo->vbflags |= ivideo->sisfb_tvplug;
2233 } else {
2234 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2235 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2236 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2237 else {
2238 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2239 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2243 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2244 if(ivideo->sisfb_tvstd != -1) {
2245 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2246 ivideo->vbflags |= ivideo->sisfb_tvstd;
2248 if(ivideo->vbflags & TV_SCART) {
2249 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2250 ivideo->vbflags |= TV_PAL;
2252 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2253 if(ivideo->sisvga_engine == SIS_300_VGA) {
2254 inSISIDXREG(SISSR, 0x38, temp);
2255 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2256 else ivideo->vbflags |= TV_NTSC;
2257 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2258 inSISIDXREG(SISSR, 0x38, temp);
2259 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2260 else ivideo->vbflags |= TV_NTSC;
2261 } else {
2262 inSISIDXREG(SISCR, 0x79, temp);
2263 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2264 else ivideo->vbflags |= TV_NTSC;
2269 /* Copy forceCRT1 option to CRT1off if option is given */
2270 if(ivideo->sisfb_forcecrt1 != -1) {
2271 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2275 /* ------------------ Sensing routines ------------------ */
2277 static BOOLEAN __devinit
2278 sisfb_test_DDC1(struct sis_video_info *ivideo)
2280 unsigned short old;
2281 int count = 48;
2283 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2284 do {
2285 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2286 } while(count--);
2287 return (count == -1) ? FALSE : TRUE;
2290 static void __devinit
2291 sisfb_sense_crt1(struct sis_video_info *ivideo)
2293 BOOLEAN mustwait = FALSE;
2294 u8 sr1F, cr17;
2295 #ifdef CONFIG_FB_SIS_315
2296 u8 cr63=0;
2297 #endif
2298 u16 temp = 0xffff;
2299 int i;
2301 inSISIDXREG(SISSR,0x1F,sr1F);
2302 orSISIDXREG(SISSR,0x1F,0x04);
2303 andSISIDXREG(SISSR,0x1F,0x3F);
2304 if(sr1F & 0xc0) mustwait = TRUE;
2306 #ifdef CONFIG_FB_SIS_315
2307 if(ivideo->sisvga_engine == SIS_315_VGA) {
2308 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2309 cr63 &= 0x40;
2310 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2312 #endif
2314 inSISIDXREG(SISCR,0x17,cr17);
2315 cr17 &= 0x80;
2316 if(!cr17) {
2317 orSISIDXREG(SISCR,0x17,0x80);
2318 mustwait = TRUE;
2319 outSISIDXREG(SISSR, 0x00, 0x01);
2320 outSISIDXREG(SISSR, 0x00, 0x03);
2323 if(mustwait) {
2324 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2327 #ifdef CONFIG_FB_SIS_315
2328 if(ivideo->chip >= SIS_330) {
2329 andSISIDXREG(SISCR,0x32,~0x20);
2330 if(ivideo->chip >= SIS_340) {
2331 outSISIDXREG(SISCR, 0x57, 0x4a);
2332 } else {
2333 outSISIDXREG(SISCR, 0x57, 0x5f);
2335 orSISIDXREG(SISCR, 0x53, 0x02);
2336 while((inSISREG(SISINPSTAT)) & 0x01) break;
2337 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2338 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2339 andSISIDXREG(SISCR, 0x53, 0xfd);
2340 andSISIDXREG(SISCR, 0x57, 0x00);
2342 #endif
2344 if(temp == 0xffff) {
2345 i = 3;
2346 do {
2347 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2348 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2349 } while(((temp == 0) || (temp == 0xffff)) && i--);
2351 if((temp == 0) || (temp == 0xffff)) {
2352 if(sisfb_test_DDC1(ivideo)) temp = 1;
2356 if((temp) && (temp != 0xffff)) {
2357 orSISIDXREG(SISCR,0x32,0x20);
2360 #ifdef CONFIG_FB_SIS_315
2361 if(ivideo->sisvga_engine == SIS_315_VGA) {
2362 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2364 #endif
2366 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2368 outSISIDXREG(SISSR,0x1F,sr1F);
2371 /* Determine and detect attached devices on SiS30x */
2372 static void __devinit
2373 SiS_SenseLCD(struct sis_video_info *ivideo)
2375 unsigned char buffer[256];
2376 unsigned short temp, realcrtno, i;
2377 u8 reg, cr37 = 0, paneltype = 0;
2378 u16 xres, yres;
2380 ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2382 /* LCD detection only for TMDS bridges */
2383 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2384 return;
2385 if(ivideo->vbflags2 & VB2_30xBDH)
2386 return;
2388 /* If LCD already set up by BIOS, skip it */
2389 inSISIDXREG(SISCR, 0x32, reg);
2390 if(reg & 0x08)
2391 return;
2393 realcrtno = 1;
2394 if(ivideo->SiS_Pr.DDCPortMixup)
2395 realcrtno = 0;
2397 /* Check DDC capabilities */
2398 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2399 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2401 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2402 return;
2404 /* Read DDC data */
2405 i = 3; /* Number of retrys */
2406 do {
2407 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2408 ivideo->sisvga_engine, realcrtno, 1,
2409 &buffer[0], ivideo->vbflags2);
2410 } while((temp) && i--);
2412 if(temp)
2413 return;
2415 /* No digital device */
2416 if(!(buffer[0x14] & 0x80))
2417 return;
2419 /* First detailed timing preferred timing? */
2420 if(!(buffer[0x18] & 0x02))
2421 return;
2423 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2424 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2426 switch(xres) {
2427 case 1024:
2428 if(yres == 768)
2429 paneltype = 0x02;
2430 break;
2431 case 1280:
2432 if(yres == 1024)
2433 paneltype = 0x03;
2434 break;
2435 case 1600:
2436 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2437 paneltype = 0x0b;
2438 break;
2441 if(!paneltype)
2442 return;
2444 if(buffer[0x23])
2445 cr37 |= 0x10;
2447 if((buffer[0x47] & 0x18) == 0x18)
2448 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2449 else
2450 cr37 |= 0xc0;
2452 outSISIDXREG(SISCR, 0x36, paneltype);
2453 cr37 &= 0xf1;
2454 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2455 orSISIDXREG(SISCR, 0x32, 0x08);
2457 ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2460 static int __devinit
2461 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2463 int temp, mytest, result, i, j;
2465 for(j = 0; j < 10; j++) {
2466 result = 0;
2467 for(i = 0; i < 3; i++) {
2468 mytest = test;
2469 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2470 temp = (type >> 8) | (mytest & 0x00ff);
2471 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2472 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2473 mytest >>= 8;
2474 mytest &= 0x7f;
2475 inSISIDXREG(SISPART4,0x03,temp);
2476 temp ^= 0x0e;
2477 temp &= mytest;
2478 if(temp == mytest) result++;
2479 #if 1
2480 outSISIDXREG(SISPART4,0x11,0x00);
2481 andSISIDXREG(SISPART4,0x10,0xe0);
2482 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2483 #endif
2485 if((result == 0) || (result >= 2)) break;
2487 return result;
2490 static void __devinit
2491 SiS_Sense30x(struct sis_video_info *ivideo)
2493 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2494 u16 svhs=0, svhs_c=0;
2495 u16 cvbs=0, cvbs_c=0;
2496 u16 vga2=0, vga2_c=0;
2497 int myflag, result;
2498 char stdstr[] = "sisfb: Detected";
2499 char tvstr[] = "TV connected to";
2501 if(ivideo->vbflags2 & VB2_301) {
2502 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2503 inSISIDXREG(SISPART4,0x01,myflag);
2504 if(myflag & 0x04) {
2505 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2507 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2508 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2509 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2510 svhs = 0x0200; cvbs = 0x0100;
2511 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2512 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2513 } else
2514 return;
2516 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2517 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2518 svhs_c = 0x0408; cvbs_c = 0x0808;
2521 biosflag = 2;
2522 if(ivideo->haveXGIROM) {
2523 biosflag = ivideo->bios_abase[0x58] & 0x03;
2524 } else if(ivideo->newrom) {
2525 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2526 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2527 if(ivideo->bios_abase) {
2528 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2532 if(ivideo->chip == SIS_300) {
2533 inSISIDXREG(SISSR,0x3b,myflag);
2534 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2537 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2538 vga2 = vga2_c = 0;
2541 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2542 orSISIDXREG(SISSR,0x1e,0x20);
2544 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2545 if(ivideo->vbflags2 & VB2_30xC) {
2546 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2547 } else {
2548 orSISIDXREG(SISPART4,0x0d,0x04);
2550 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2552 inSISIDXREG(SISPART2,0x00,backupP2_00);
2553 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2555 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2556 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2557 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2560 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2561 SISDoSense(ivideo, 0, 0);
2564 andSISIDXREG(SISCR, 0x32, ~0x14);
2566 if(vga2_c || vga2) {
2567 if(SISDoSense(ivideo, vga2, vga2_c)) {
2568 if(biosflag & 0x01) {
2569 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2570 orSISIDXREG(SISCR, 0x32, 0x04);
2571 } else {
2572 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2573 orSISIDXREG(SISCR, 0x32, 0x10);
2578 andSISIDXREG(SISCR, 0x32, 0x3f);
2580 if(ivideo->vbflags2 & VB2_30xCLV) {
2581 orSISIDXREG(SISPART4,0x0d,0x04);
2584 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2585 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2586 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2587 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2588 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2589 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2590 orSISIDXREG(SISCR,0x32,0x80);
2593 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2596 andSISIDXREG(SISCR, 0x32, ~0x03);
2598 if(!(ivideo->vbflags & TV_YPBPR)) {
2599 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2600 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2601 orSISIDXREG(SISCR, 0x32, 0x02);
2603 if((biosflag & 0x02) || (!result)) {
2604 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2605 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2606 orSISIDXREG(SISCR, 0x32, 0x01);
2611 SISDoSense(ivideo, 0, 0);
2613 outSISIDXREG(SISPART2,0x00,backupP2_00);
2614 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2615 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2617 if(ivideo->vbflags2 & VB2_30xCLV) {
2618 inSISIDXREG(SISPART2,0x00,biosflag);
2619 if(biosflag & 0x20) {
2620 for(myflag = 2; myflag > 0; myflag--) {
2621 biosflag ^= 0x20;
2622 outSISIDXREG(SISPART2,0x00,biosflag);
2627 outSISIDXREG(SISPART2,0x00,backupP2_00);
2630 /* Determine and detect attached TV's on Chrontel */
2631 static void __devinit
2632 SiS_SenseCh(struct sis_video_info *ivideo)
2634 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2635 u8 temp1, temp2;
2636 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2637 #endif
2638 #ifdef CONFIG_FB_SIS_300
2639 unsigned char test[3];
2640 int i;
2641 #endif
2643 if(ivideo->chip < SIS_315H) {
2645 #ifdef CONFIG_FB_SIS_300
2646 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2647 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2648 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2649 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2650 /* See Chrontel TB31 for explanation */
2651 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2652 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2653 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2654 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2656 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2657 if(temp2 != temp1) temp1 = temp2;
2659 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2660 /* Read power status */
2661 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2662 if((temp1 & 0x03) != 0x03) {
2663 /* Power all outputs */
2664 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2665 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2667 /* Sense connected TV devices */
2668 for(i = 0; i < 3; i++) {
2669 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2670 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2671 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2672 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2673 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2674 if(!(temp1 & 0x08)) test[i] = 0x02;
2675 else if(!(temp1 & 0x02)) test[i] = 0x01;
2676 else test[i] = 0;
2677 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2680 if(test[0] == test[1]) temp1 = test[0];
2681 else if(test[0] == test[2]) temp1 = test[0];
2682 else if(test[1] == test[2]) temp1 = test[1];
2683 else {
2684 printk(KERN_INFO
2685 "sisfb: TV detection unreliable - test results varied\n");
2686 temp1 = test[2];
2688 if(temp1 == 0x02) {
2689 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2690 ivideo->vbflags |= TV_SVIDEO;
2691 orSISIDXREG(SISCR, 0x32, 0x02);
2692 andSISIDXREG(SISCR, 0x32, ~0x05);
2693 } else if (temp1 == 0x01) {
2694 printk(KERN_INFO "%s CVBS output\n", stdstr);
2695 ivideo->vbflags |= TV_AVIDEO;
2696 orSISIDXREG(SISCR, 0x32, 0x01);
2697 andSISIDXREG(SISCR, 0x32, ~0x06);
2698 } else {
2699 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2700 andSISIDXREG(SISCR, 0x32, ~0x07);
2702 } else if(temp1 == 0) {
2703 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2704 andSISIDXREG(SISCR, 0x32, ~0x07);
2706 /* Set general purpose IO for Chrontel communication */
2707 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2708 #endif
2710 } else {
2712 #ifdef CONFIG_FB_SIS_315
2713 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2714 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2715 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2716 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2717 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2718 temp2 |= 0x01;
2719 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2720 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2721 temp2 ^= 0x01;
2722 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2723 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2724 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2725 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2726 temp1 = 0;
2727 if(temp2 & 0x02) temp1 |= 0x01;
2728 if(temp2 & 0x10) temp1 |= 0x01;
2729 if(temp2 & 0x04) temp1 |= 0x02;
2730 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2731 switch(temp1) {
2732 case 0x01:
2733 printk(KERN_INFO "%s CVBS output\n", stdstr);
2734 ivideo->vbflags |= TV_AVIDEO;
2735 orSISIDXREG(SISCR, 0x32, 0x01);
2736 andSISIDXREG(SISCR, 0x32, ~0x06);
2737 break;
2738 case 0x02:
2739 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2740 ivideo->vbflags |= TV_SVIDEO;
2741 orSISIDXREG(SISCR, 0x32, 0x02);
2742 andSISIDXREG(SISCR, 0x32, ~0x05);
2743 break;
2744 case 0x04:
2745 printk(KERN_INFO "%s SCART output\n", stdstr);
2746 orSISIDXREG(SISCR, 0x32, 0x04);
2747 andSISIDXREG(SISCR, 0x32, ~0x03);
2748 break;
2749 default:
2750 andSISIDXREG(SISCR, 0x32, ~0x07);
2752 #endif
2756 static void __devinit
2757 sisfb_get_VB_type(struct sis_video_info *ivideo)
2759 char stdstr[] = "sisfb: Detected";
2760 char bridgestr[] = "video bridge";
2761 u8 vb_chipid;
2762 u8 reg;
2764 /* No CRT2 on XGI Z7 */
2765 if(ivideo->chip == XGI_20)
2766 return;
2768 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2769 switch(vb_chipid) {
2770 case 0x01:
2771 inSISIDXREG(SISPART4, 0x01, reg);
2772 if(reg < 0xb0) {
2773 ivideo->vbflags |= VB_301; /* Deprecated */
2774 ivideo->vbflags2 |= VB2_301;
2775 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2776 } else if(reg < 0xc0) {
2777 ivideo->vbflags |= VB_301B; /* Deprecated */
2778 ivideo->vbflags2 |= VB2_301B;
2779 inSISIDXREG(SISPART4,0x23,reg);
2780 if(!(reg & 0x02)) {
2781 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2782 ivideo->vbflags2 |= VB2_30xBDH;
2783 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2784 } else {
2785 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2787 } else if(reg < 0xd0) {
2788 ivideo->vbflags |= VB_301C; /* Deprecated */
2789 ivideo->vbflags2 |= VB2_301C;
2790 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2791 } else if(reg < 0xe0) {
2792 ivideo->vbflags |= VB_301LV; /* Deprecated */
2793 ivideo->vbflags2 |= VB2_301LV;
2794 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2795 } else if(reg <= 0xe1) {
2796 inSISIDXREG(SISPART4,0x39,reg);
2797 if(reg == 0xff) {
2798 ivideo->vbflags |= VB_302LV; /* Deprecated */
2799 ivideo->vbflags2 |= VB2_302LV;
2800 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2801 } else {
2802 ivideo->vbflags |= VB_301C; /* Deprecated */
2803 ivideo->vbflags2 |= VB2_301C;
2804 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2805 #if 0
2806 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2807 ivideo->vbflags2 |= VB2_302ELV;
2808 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2809 #endif
2812 break;
2813 case 0x02:
2814 ivideo->vbflags |= VB_302B; /* Deprecated */
2815 ivideo->vbflags2 |= VB2_302B;
2816 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2817 break;
2820 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2821 inSISIDXREG(SISCR, 0x37, reg);
2822 reg &= SIS_EXTERNAL_CHIP_MASK;
2823 reg >>= 1;
2824 if(ivideo->sisvga_engine == SIS_300_VGA) {
2825 #ifdef CONFIG_FB_SIS_300
2826 switch(reg) {
2827 case SIS_EXTERNAL_CHIP_LVDS:
2828 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2829 ivideo->vbflags2 |= VB2_LVDS;
2830 break;
2831 case SIS_EXTERNAL_CHIP_TRUMPION:
2832 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2833 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2834 break;
2835 case SIS_EXTERNAL_CHIP_CHRONTEL:
2836 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2837 ivideo->vbflags2 |= VB2_CHRONTEL;
2838 break;
2839 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2840 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2841 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2842 break;
2844 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2845 #endif
2846 } else if(ivideo->chip < SIS_661) {
2847 #ifdef CONFIG_FB_SIS_315
2848 switch (reg) {
2849 case SIS310_EXTERNAL_CHIP_LVDS:
2850 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2851 ivideo->vbflags2 |= VB2_LVDS;
2852 break;
2853 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2854 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2855 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2856 break;
2858 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2859 #endif
2860 } else if(ivideo->chip >= SIS_661) {
2861 #ifdef CONFIG_FB_SIS_315
2862 inSISIDXREG(SISCR, 0x38, reg);
2863 reg >>= 5;
2864 switch(reg) {
2865 case 0x02:
2866 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2867 ivideo->vbflags2 |= VB2_LVDS;
2868 break;
2869 case 0x03:
2870 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2871 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2872 break;
2873 case 0x04:
2874 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2875 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2876 break;
2878 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2879 #endif
2881 if(ivideo->vbflags2 & VB2_LVDS) {
2882 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2884 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2885 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2887 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2888 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2890 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2891 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2895 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2896 SiS_SenseLCD(ivideo);
2897 SiS_Sense30x(ivideo);
2898 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2899 SiS_SenseCh(ivideo);
2903 /* ---------- Engine initialization routines ------------ */
2905 static void
2906 sisfb_engine_init(struct sis_video_info *ivideo)
2909 /* Initialize command queue (we use MMIO only) */
2911 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2913 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2914 MMIO_CMD_QUEUE_CAP |
2915 VM_CMD_QUEUE_CAP |
2916 AGP_CMD_QUEUE_CAP);
2918 #ifdef CONFIG_FB_SIS_300
2919 if(ivideo->sisvga_engine == SIS_300_VGA) {
2920 u32 tqueue_pos;
2921 u8 tq_state;
2923 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2925 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2926 tq_state |= 0xf0;
2927 tq_state &= 0xfc;
2928 tq_state |= (u8)(tqueue_pos >> 8);
2929 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2931 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2933 ivideo->caps |= TURBO_QUEUE_CAP;
2935 #endif
2937 #ifdef CONFIG_FB_SIS_315
2938 if(ivideo->sisvga_engine == SIS_315_VGA) {
2939 u32 tempq = 0, templ;
2940 u8 temp;
2942 if(ivideo->chip == XGI_20) {
2943 switch(ivideo->cmdQueueSize) {
2944 case (64 * 1024):
2945 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2946 break;
2947 case (128 * 1024):
2948 default:
2949 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2951 } else {
2952 switch(ivideo->cmdQueueSize) {
2953 case (4 * 1024 * 1024):
2954 temp = SIS_CMD_QUEUE_SIZE_4M;
2955 break;
2956 case (2 * 1024 * 1024):
2957 temp = SIS_CMD_QUEUE_SIZE_2M;
2958 break;
2959 case (1 * 1024 * 1024):
2960 temp = SIS_CMD_QUEUE_SIZE_1M;
2961 break;
2962 default:
2963 case (512 * 1024):
2964 temp = SIS_CMD_QUEUE_SIZE_512k;
2968 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2969 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2971 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2972 /* Must disable dual pipe on XGI_40. Can't do
2973 * this in MMIO mode, because it requires
2974 * setting/clearing a bit in the MMIO fire trigger
2975 * register.
2977 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2979 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2981 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2983 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2984 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2986 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2987 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2989 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2990 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2991 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2992 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2994 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2996 sisfb_syncaccel(ivideo);
2998 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3003 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3004 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3006 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3007 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3009 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3010 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3012 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3014 #endif
3016 ivideo->engineok = 1;
3019 static void __devinit
3020 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3022 u8 reg;
3023 int i;
3025 inSISIDXREG(SISCR, 0x36, reg);
3026 reg &= 0x0f;
3027 if(ivideo->sisvga_engine == SIS_300_VGA) {
3028 ivideo->CRT2LCDType = sis300paneltype[reg];
3029 } else if(ivideo->chip >= SIS_661) {
3030 ivideo->CRT2LCDType = sis661paneltype[reg];
3031 } else {
3032 ivideo->CRT2LCDType = sis310paneltype[reg];
3033 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3034 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3035 (ivideo->CRT2LCDType != LCD_320x240_3)) {
3036 ivideo->CRT2LCDType = LCD_320x240;
3041 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3042 /* For broken BIOSes: Assume 1024x768, RGB18 */
3043 ivideo->CRT2LCDType = LCD_1024x768;
3044 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3045 setSISIDXREG(SISCR,0x37,0xee,0x01);
3046 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3049 for(i = 0; i < SIS_LCD_NUMBER; i++) {
3050 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3051 ivideo->lcdxres = sis_lcd_data[i].xres;
3052 ivideo->lcdyres = sis_lcd_data[i].yres;
3053 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3054 break;
3058 #ifdef CONFIG_FB_SIS_300
3059 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3060 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3061 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3062 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3063 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
3064 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3065 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3066 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
3067 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3069 #endif
3071 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3072 ivideo->lcdxres, ivideo->lcdyres);
3075 static void __devinit
3076 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3078 #ifdef CONFIG_FB_SIS_300
3079 /* Save the current PanelDelayCompensation if the LCD is currently used */
3080 if(ivideo->sisvga_engine == SIS_300_VGA) {
3081 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3082 int tmp;
3083 inSISIDXREG(SISCR,0x30,tmp);
3084 if(tmp & 0x20) {
3085 /* Currently on LCD? If yes, read current pdc */
3086 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3087 ivideo->detectedpdc &= 0x3c;
3088 if(ivideo->SiS_Pr.PDC == -1) {
3089 /* Let option override detection */
3090 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3092 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3093 ivideo->detectedpdc);
3095 if((ivideo->SiS_Pr.PDC != -1) &&
3096 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3097 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3098 ivideo->SiS_Pr.PDC);
3102 #endif
3104 #ifdef CONFIG_FB_SIS_315
3105 if(ivideo->sisvga_engine == SIS_315_VGA) {
3107 /* Try to find about LCDA */
3108 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3109 int tmp;
3110 inSISIDXREG(SISPART1,0x13,tmp);
3111 if(tmp & 0x04) {
3112 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3113 ivideo->detectedlcda = 0x03;
3117 /* Save PDC */
3118 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3119 int tmp;
3120 inSISIDXREG(SISCR,0x30,tmp);
3121 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3122 /* Currently on LCD? If yes, read current pdc */
3123 u8 pdc;
3124 inSISIDXREG(SISPART1,0x2D,pdc);
3125 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3126 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3127 inSISIDXREG(SISPART1,0x35,pdc);
3128 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3129 inSISIDXREG(SISPART1,0x20,pdc);
3130 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3131 if(ivideo->newrom) {
3132 /* New ROM invalidates other PDC resp. */
3133 if(ivideo->detectedlcda != 0xff) {
3134 ivideo->detectedpdc = 0xff;
3135 } else {
3136 ivideo->detectedpdca = 0xff;
3139 if(ivideo->SiS_Pr.PDC == -1) {
3140 if(ivideo->detectedpdc != 0xff) {
3141 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3144 if(ivideo->SiS_Pr.PDCA == -1) {
3145 if(ivideo->detectedpdca != 0xff) {
3146 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3149 if(ivideo->detectedpdc != 0xff) {
3150 printk(KERN_INFO
3151 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3152 ivideo->detectedpdc);
3154 if(ivideo->detectedpdca != 0xff) {
3155 printk(KERN_INFO
3156 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3157 ivideo->detectedpdca);
3161 /* Save EMI */
3162 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3163 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3164 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3165 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3166 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3167 ivideo->SiS_Pr.HaveEMI = TRUE;
3168 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3169 ivideo->SiS_Pr.HaveEMILCD = TRUE;
3174 /* Let user override detected PDCs (all bridges) */
3175 if(ivideo->vbflags2 & VB2_30xBLV) {
3176 if((ivideo->SiS_Pr.PDC != -1) &&
3177 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3178 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3179 ivideo->SiS_Pr.PDC);
3181 if((ivideo->SiS_Pr.PDCA != -1) &&
3182 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3183 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3184 ivideo->SiS_Pr.PDCA);
3189 #endif
3192 /* -------------------- Memory manager routines ---------------------- */
3194 static u32 __devinit
3195 sisfb_getheapstart(struct sis_video_info *ivideo)
3197 u32 ret = ivideo->sisfb_parm_mem * 1024;
3198 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3199 u32 def;
3201 /* Calculate heap start = end of memory for console
3203 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3204 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3206 * On 76x in UMA+LFB mode, the layout is as follows:
3207 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3208 * where the heap is the entire UMA area, eventually
3209 * into the LFB area if the given mem parameter is
3210 * higher than the size of the UMA memory.
3212 * Basically given by "mem" parameter
3214 * maximum = videosize - cmd_queue - hwcursor
3215 * (results in a heap of size 0)
3216 * default = SiS 300: depends on videosize
3217 * SiS 315/330/340/XGI: 32k below max
3220 if(ivideo->sisvga_engine == SIS_300_VGA) {
3221 if(ivideo->video_size > 0x1000000) {
3222 def = 0xc00000;
3223 } else if(ivideo->video_size > 0x800000) {
3224 def = 0x800000;
3225 } else {
3226 def = 0x400000;
3228 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3229 ret = def = 0;
3230 } else {
3231 def = maxoffs - 0x8000;
3234 /* Use default for secondary card for now (FIXME) */
3235 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3236 ret = def;
3238 return ret;
3241 static u32 __devinit
3242 sisfb_getheapsize(struct sis_video_info *ivideo)
3244 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3245 u32 ret = 0;
3247 if(ivideo->UMAsize && ivideo->LFBsize) {
3248 if( (!ivideo->sisfb_parm_mem) ||
3249 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3250 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3251 ret = ivideo->UMAsize;
3252 max -= ivideo->UMAsize;
3253 } else {
3254 ret = max - (ivideo->sisfb_parm_mem * 1024);
3255 max = ivideo->sisfb_parm_mem * 1024;
3257 ivideo->video_offset = ret;
3258 ivideo->sisfb_mem = max;
3259 } else {
3260 ret = max - ivideo->heapstart;
3261 ivideo->sisfb_mem = ivideo->heapstart;
3264 return ret;
3267 static int __devinit
3268 sisfb_heap_init(struct sis_video_info *ivideo)
3270 struct SIS_OH *poh;
3272 ivideo->video_offset = 0;
3273 if(ivideo->sisfb_parm_mem) {
3274 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3275 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3276 ivideo->sisfb_parm_mem = 0;
3280 ivideo->heapstart = sisfb_getheapstart(ivideo);
3281 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3283 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3284 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3286 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3287 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3289 ivideo->sisfb_heap.vinfo = ivideo;
3291 ivideo->sisfb_heap.poha_chain = NULL;
3292 ivideo->sisfb_heap.poh_freelist = NULL;
3294 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3295 if(poh == NULL)
3296 return 1;
3298 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3299 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3300 poh->size = ivideo->sisfb_heap_size;
3301 poh->offset = ivideo->heapstart;
3303 ivideo->sisfb_heap.oh_free.poh_next = poh;
3304 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3305 ivideo->sisfb_heap.oh_free.size = 0;
3306 ivideo->sisfb_heap.max_freesize = poh->size;
3308 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3309 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3310 ivideo->sisfb_heap.oh_used.size = SENTINEL;
3312 if(ivideo->cardnumber == 0) {
3313 /* For the first card, make this heap the "global" one
3314 * for old DRM (which could handle only one card)
3316 sisfb_heap = &ivideo->sisfb_heap;
3319 return 0;
3322 static struct SIS_OH *
3323 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3325 struct SIS_OHALLOC *poha;
3326 struct SIS_OH *poh;
3327 unsigned long cOhs;
3328 int i;
3330 if(memheap->poh_freelist == NULL) {
3331 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3332 if(!poha)
3333 return NULL;
3335 poha->poha_next = memheap->poha_chain;
3336 memheap->poha_chain = poha;
3338 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3340 poh = &poha->aoh[0];
3341 for(i = cOhs - 1; i != 0; i--) {
3342 poh->poh_next = poh + 1;
3343 poh = poh + 1;
3346 poh->poh_next = NULL;
3347 memheap->poh_freelist = &poha->aoh[0];
3350 poh = memheap->poh_freelist;
3351 memheap->poh_freelist = poh->poh_next;
3353 return poh;
3356 static struct SIS_OH *
3357 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3359 struct SIS_OH *pohThis;
3360 struct SIS_OH *pohRoot;
3361 int bAllocated = 0;
3363 if(size > memheap->max_freesize) {
3364 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3365 (unsigned int) size / 1024);
3366 return NULL;
3369 pohThis = memheap->oh_free.poh_next;
3371 while(pohThis != &memheap->oh_free) {
3372 if(size <= pohThis->size) {
3373 bAllocated = 1;
3374 break;
3376 pohThis = pohThis->poh_next;
3379 if(!bAllocated) {
3380 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3381 (unsigned int) size / 1024);
3382 return NULL;
3385 if(size == pohThis->size) {
3386 pohRoot = pohThis;
3387 sisfb_delete_node(pohThis);
3388 } else {
3389 pohRoot = sisfb_poh_new_node(memheap);
3390 if(pohRoot == NULL)
3391 return NULL;
3393 pohRoot->offset = pohThis->offset;
3394 pohRoot->size = size;
3396 pohThis->offset += size;
3397 pohThis->size -= size;
3400 memheap->max_freesize -= size;
3402 pohThis = &memheap->oh_used;
3403 sisfb_insert_node(pohThis, pohRoot);
3405 return pohRoot;
3408 static void
3409 sisfb_delete_node(struct SIS_OH *poh)
3411 poh->poh_prev->poh_next = poh->poh_next;
3412 poh->poh_next->poh_prev = poh->poh_prev;
3415 static void
3416 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3418 struct SIS_OH *pohTemp = pohList->poh_next;
3420 pohList->poh_next = poh;
3421 pohTemp->poh_prev = poh;
3423 poh->poh_prev = pohList;
3424 poh->poh_next = pohTemp;
3427 static struct SIS_OH *
3428 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3430 struct SIS_OH *pohThis;
3431 struct SIS_OH *poh_freed;
3432 struct SIS_OH *poh_prev;
3433 struct SIS_OH *poh_next;
3434 u32 ulUpper;
3435 u32 ulLower;
3436 int foundNode = 0;
3438 poh_freed = memheap->oh_used.poh_next;
3440 while(poh_freed != &memheap->oh_used) {
3441 if(poh_freed->offset == base) {
3442 foundNode = 1;
3443 break;
3446 poh_freed = poh_freed->poh_next;
3449 if(!foundNode)
3450 return NULL;
3452 memheap->max_freesize += poh_freed->size;
3454 poh_prev = poh_next = NULL;
3455 ulUpper = poh_freed->offset + poh_freed->size;
3456 ulLower = poh_freed->offset;
3458 pohThis = memheap->oh_free.poh_next;
3460 while(pohThis != &memheap->oh_free) {
3461 if(pohThis->offset == ulUpper) {
3462 poh_next = pohThis;
3463 } else if((pohThis->offset + pohThis->size) == ulLower) {
3464 poh_prev = pohThis;
3466 pohThis = pohThis->poh_next;
3469 sisfb_delete_node(poh_freed);
3471 if(poh_prev && poh_next) {
3472 poh_prev->size += (poh_freed->size + poh_next->size);
3473 sisfb_delete_node(poh_next);
3474 sisfb_free_node(memheap, poh_freed);
3475 sisfb_free_node(memheap, poh_next);
3476 return poh_prev;
3479 if(poh_prev) {
3480 poh_prev->size += poh_freed->size;
3481 sisfb_free_node(memheap, poh_freed);
3482 return poh_prev;
3485 if(poh_next) {
3486 poh_next->size += poh_freed->size;
3487 poh_next->offset = poh_freed->offset;
3488 sisfb_free_node(memheap, poh_freed);
3489 return poh_next;
3492 sisfb_insert_node(&memheap->oh_free, poh_freed);
3494 return poh_freed;
3497 static void
3498 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3500 if(poh == NULL)
3501 return;
3503 poh->poh_next = memheap->poh_freelist;
3504 memheap->poh_freelist = poh;
3507 static void
3508 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3510 struct SIS_OH *poh = NULL;
3512 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3513 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3515 if(poh == NULL) {
3516 req->offset = req->size = 0;
3517 DPRINTK("sisfb: Video RAM allocation failed\n");
3518 } else {
3519 req->offset = poh->offset;
3520 req->size = poh->size;
3521 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3522 (poh->offset + ivideo->video_vbase));
3526 void
3527 sis_malloc(struct sis_memreq *req)
3529 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3531 if(&ivideo->sisfb_heap == sisfb_heap)
3532 sis_int_malloc(ivideo, req);
3533 else
3534 req->offset = req->size = 0;
3537 void
3538 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3540 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3542 sis_int_malloc(ivideo, req);
3545 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3547 static void
3548 sis_int_free(struct sis_video_info *ivideo, u32 base)
3550 struct SIS_OH *poh;
3552 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3553 return;
3555 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3557 if(poh == NULL) {
3558 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3559 (unsigned int) base);
3563 void
3564 sis_free(u32 base)
3566 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3568 sis_int_free(ivideo, base);
3571 void
3572 sis_free_new(struct pci_dev *pdev, u32 base)
3574 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3576 sis_int_free(ivideo, base);
3579 /* --------------------- SetMode routines ------------------------- */
3581 static void
3582 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3584 u8 cr30, cr31;
3586 /* Check if MMIO and engines are enabled,
3587 * and sync in case they are. Can't use
3588 * ivideo->accel here, as this might have
3589 * been changed before this is called.
3591 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3592 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3593 /* MMIO and 2D/3D engine enabled? */
3594 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3595 #ifdef CONFIG_FB_SIS_300
3596 if(ivideo->sisvga_engine == SIS_300_VGA) {
3597 /* Don't care about TurboQueue. It's
3598 * enough to know that the engines
3599 * are enabled
3601 sisfb_syncaccel(ivideo);
3603 #endif
3604 #ifdef CONFIG_FB_SIS_315
3605 if(ivideo->sisvga_engine == SIS_315_VGA) {
3606 /* Check that any queue mode is
3607 * enabled, and that the queue
3608 * is not in the state of "reset"
3610 inSISIDXREG(SISSR, 0x26, cr30);
3611 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3612 sisfb_syncaccel(ivideo);
3615 #endif
3619 static void
3620 sisfb_pre_setmode(struct sis_video_info *ivideo)
3622 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3623 int tvregnum = 0;
3625 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3627 outSISIDXREG(SISSR, 0x05, 0x86);
3629 inSISIDXREG(SISCR, 0x31, cr31);
3630 cr31 &= ~0x60;
3631 cr31 |= 0x04;
3633 cr33 = ivideo->rate_idx & 0x0F;
3635 #ifdef CONFIG_FB_SIS_315
3636 if(ivideo->sisvga_engine == SIS_315_VGA) {
3637 if(ivideo->chip >= SIS_661) {
3638 inSISIDXREG(SISCR, 0x38, cr38);
3639 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3640 } else {
3641 tvregnum = 0x38;
3642 inSISIDXREG(SISCR, tvregnum, cr38);
3643 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3646 #endif
3647 #ifdef CONFIG_FB_SIS_300
3648 if(ivideo->sisvga_engine == SIS_300_VGA) {
3649 tvregnum = 0x35;
3650 inSISIDXREG(SISCR, tvregnum, cr38);
3652 #endif
3654 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3655 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3656 ivideo->curFSTN = ivideo->curDSTN = 0;
3658 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3660 case CRT2_TV:
3661 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3662 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3663 #ifdef CONFIG_FB_SIS_315
3664 if(ivideo->chip >= SIS_661) {
3665 cr38 |= 0x04;
3666 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3667 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3668 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3669 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3670 cr35 &= ~0x01;
3671 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3672 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3673 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3674 cr38 |= 0x08;
3675 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3676 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3677 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3678 cr31 &= ~0x01;
3679 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3681 #endif
3682 } else if((ivideo->vbflags & TV_HIVISION) &&
3683 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3684 if(ivideo->chip >= SIS_661) {
3685 cr38 |= 0x04;
3686 cr35 |= 0x60;
3687 } else {
3688 cr30 |= 0x80;
3690 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3691 cr31 |= 0x01;
3692 cr35 |= 0x01;
3693 ivideo->currentvbflags |= TV_HIVISION;
3694 } else if(ivideo->vbflags & TV_SCART) {
3695 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3696 cr31 |= 0x01;
3697 cr35 |= 0x01;
3698 ivideo->currentvbflags |= TV_SCART;
3699 } else {
3700 if(ivideo->vbflags & TV_SVIDEO) {
3701 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3702 ivideo->currentvbflags |= TV_SVIDEO;
3704 if(ivideo->vbflags & TV_AVIDEO) {
3705 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3706 ivideo->currentvbflags |= TV_AVIDEO;
3709 cr31 |= SIS_DRIVER_MODE;
3711 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3712 if(ivideo->vbflags & TV_PAL) {
3713 cr31 |= 0x01; cr35 |= 0x01;
3714 ivideo->currentvbflags |= TV_PAL;
3715 if(ivideo->vbflags & TV_PALM) {
3716 cr38 |= 0x40; cr35 |= 0x04;
3717 ivideo->currentvbflags |= TV_PALM;
3718 } else if(ivideo->vbflags & TV_PALN) {
3719 cr38 |= 0x80; cr35 |= 0x08;
3720 ivideo->currentvbflags |= TV_PALN;
3722 } else {
3723 cr31 &= ~0x01; cr35 &= ~0x01;
3724 ivideo->currentvbflags |= TV_NTSC;
3725 if(ivideo->vbflags & TV_NTSCJ) {
3726 cr38 |= 0x40; cr35 |= 0x02;
3727 ivideo->currentvbflags |= TV_NTSCJ;
3731 break;
3733 case CRT2_LCD:
3734 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3735 cr31 |= SIS_DRIVER_MODE;
3736 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3737 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3738 ivideo->curFSTN = ivideo->sisfb_fstn;
3739 ivideo->curDSTN = ivideo->sisfb_dstn;
3740 break;
3742 case CRT2_VGA:
3743 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3744 cr31 |= SIS_DRIVER_MODE;
3745 if(ivideo->sisfb_nocrt2rate) {
3746 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3747 } else {
3748 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3750 break;
3752 default: /* disable CRT2 */
3753 cr30 = 0x00;
3754 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3757 outSISIDXREG(SISCR, 0x30, cr30);
3758 outSISIDXREG(SISCR, 0x33, cr33);
3760 if(ivideo->chip >= SIS_661) {
3761 #ifdef CONFIG_FB_SIS_315
3762 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3763 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3764 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3765 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3766 #endif
3767 } else if(ivideo->chip != SIS_300) {
3768 outSISIDXREG(SISCR, tvregnum, cr38);
3770 outSISIDXREG(SISCR, 0x31, cr31);
3772 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3774 sisfb_check_engine_and_sync(ivideo);
3777 /* Fix SR11 for 661 and later */
3778 #ifdef CONFIG_FB_SIS_315
3779 static void
3780 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3782 u8 tmpreg;
3784 if(ivideo->chip >= SIS_661) {
3785 inSISIDXREG(SISSR,0x11,tmpreg);
3786 if(tmpreg & 0x20) {
3787 inSISIDXREG(SISSR,0x3e,tmpreg);
3788 tmpreg = (tmpreg + 1) & 0xff;
3789 outSISIDXREG(SISSR,0x3e,tmpreg);
3790 inSISIDXREG(SISSR,0x11,tmpreg);
3792 if(tmpreg & 0xf0) {
3793 andSISIDXREG(SISSR,0x11,0x0f);
3797 #endif
3799 static void
3800 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3802 if(val > 32) val = 32;
3803 if(val < -32) val = -32;
3804 ivideo->tvxpos = val;
3806 if(ivideo->sisfblocked) return;
3807 if(!ivideo->modechanged) return;
3809 if(ivideo->currentvbflags & CRT2_TV) {
3811 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3813 int x = ivideo->tvx;
3815 switch(ivideo->chronteltype) {
3816 case 1:
3817 x += val;
3818 if(x < 0) x = 0;
3819 outSISIDXREG(SISSR,0x05,0x86);
3820 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3821 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3822 break;
3823 case 2:
3824 /* Not supported by hardware */
3825 break;
3828 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3830 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3831 unsigned short temp;
3833 p2_1f = ivideo->p2_1f;
3834 p2_20 = ivideo->p2_20;
3835 p2_2b = ivideo->p2_2b;
3836 p2_42 = ivideo->p2_42;
3837 p2_43 = ivideo->p2_43;
3839 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3840 temp += (val * 2);
3841 p2_1f = temp & 0xff;
3842 p2_20 = (temp & 0xf00) >> 4;
3843 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3844 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3845 temp += (val * 2);
3846 p2_43 = temp & 0xff;
3847 p2_42 = (temp & 0xf00) >> 4;
3848 outSISIDXREG(SISPART2,0x1f,p2_1f);
3849 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3850 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3851 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3852 outSISIDXREG(SISPART2,0x43,p2_43);
3857 static void
3858 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3860 if(val > 32) val = 32;
3861 if(val < -32) val = -32;
3862 ivideo->tvypos = val;
3864 if(ivideo->sisfblocked) return;
3865 if(!ivideo->modechanged) return;
3867 if(ivideo->currentvbflags & CRT2_TV) {
3869 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3871 int y = ivideo->tvy;
3873 switch(ivideo->chronteltype) {
3874 case 1:
3875 y -= val;
3876 if(y < 0) y = 0;
3877 outSISIDXREG(SISSR,0x05,0x86);
3878 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3879 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3880 break;
3881 case 2:
3882 /* Not supported by hardware */
3883 break;
3886 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3888 char p2_01, p2_02;
3889 val /= 2;
3890 p2_01 = ivideo->p2_01;
3891 p2_02 = ivideo->p2_02;
3893 p2_01 += val;
3894 p2_02 += val;
3895 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3896 while((p2_01 <= 0) || (p2_02 <= 0)) {
3897 p2_01 += 2;
3898 p2_02 += 2;
3901 outSISIDXREG(SISPART2,0x01,p2_01);
3902 outSISIDXREG(SISPART2,0x02,p2_02);
3907 static void
3908 sisfb_post_setmode(struct sis_video_info *ivideo)
3910 BOOLEAN crt1isoff = FALSE;
3911 BOOLEAN doit = TRUE;
3912 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3913 u8 reg;
3914 #endif
3915 #ifdef CONFIG_FB_SIS_315
3916 u8 reg1;
3917 #endif
3919 outSISIDXREG(SISSR, 0x05, 0x86);
3921 #ifdef CONFIG_FB_SIS_315
3922 sisfb_fixup_SR11(ivideo);
3923 #endif
3925 /* Now we actually HAVE changed the display mode */
3926 ivideo->modechanged = 1;
3928 /* We can't switch off CRT1 if bridge is in slave mode */
3929 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3930 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3931 } else
3932 ivideo->sisfb_crt1off = 0;
3934 #ifdef CONFIG_FB_SIS_300
3935 if(ivideo->sisvga_engine == SIS_300_VGA) {
3936 if((ivideo->sisfb_crt1off) && (doit)) {
3937 crt1isoff = TRUE;
3938 reg = 0x00;
3939 } else {
3940 crt1isoff = FALSE;
3941 reg = 0x80;
3943 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3945 #endif
3946 #ifdef CONFIG_FB_SIS_315
3947 if(ivideo->sisvga_engine == SIS_315_VGA) {
3948 if((ivideo->sisfb_crt1off) && (doit)) {
3949 crt1isoff = TRUE;
3950 reg = 0x40;
3951 reg1 = 0xc0;
3952 } else {
3953 crt1isoff = FALSE;
3954 reg = 0x00;
3955 reg1 = 0x00;
3957 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3958 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3960 #endif
3962 if(crt1isoff) {
3963 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3964 ivideo->currentvbflags |= VB_SINGLE_MODE;
3965 } else {
3966 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3967 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3968 ivideo->currentvbflags |= VB_MIRROR_MODE;
3969 } else {
3970 ivideo->currentvbflags |= VB_SINGLE_MODE;
3974 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3976 if(ivideo->currentvbflags & CRT2_TV) {
3977 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3978 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3979 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3980 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3981 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3982 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3983 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3984 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3985 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3986 if(ivideo->chronteltype == 1) {
3987 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3988 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3989 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3990 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3995 if(ivideo->tvxpos) {
3996 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3998 if(ivideo->tvypos) {
3999 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
4002 /* Eventually sync engines */
4003 sisfb_check_engine_and_sync(ivideo);
4005 /* (Re-)Initialize chip engines */
4006 if(ivideo->accel) {
4007 sisfb_engine_init(ivideo);
4008 } else {
4009 ivideo->engineok = 0;
4013 static int
4014 sisfb_reset_mode(struct sis_video_info *ivideo)
4016 if(sisfb_set_mode(ivideo, 0))
4017 return 1;
4019 sisfb_set_pitch(ivideo);
4020 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4021 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
4023 return 0;
4026 static void
4027 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4029 int mycrt1off;
4031 switch(sisfb_command->sisfb_cmd) {
4032 case SISFB_CMD_GETVBFLAGS:
4033 if(!ivideo->modechanged) {
4034 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4035 } else {
4036 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4037 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4038 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
4040 break;
4041 case SISFB_CMD_SWITCHCRT1:
4042 /* arg[0]: 0 = off, 1 = on, 99 = query */
4043 if(!ivideo->modechanged) {
4044 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4045 } else if(sisfb_command->sisfb_arg[0] == 99) {
4046 /* Query */
4047 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4048 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4049 } else if(ivideo->sisfblocked) {
4050 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4051 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4052 (sisfb_command->sisfb_arg[0] == 0)) {
4053 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4054 } else {
4055 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4056 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4057 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4058 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4059 ivideo->sisfb_crt1off = mycrt1off;
4060 if(sisfb_reset_mode(ivideo)) {
4061 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
4064 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4066 break;
4067 /* more to come */
4068 default:
4069 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4070 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4071 sisfb_command->sisfb_cmd);
4075 #ifndef MODULE
4076 SISINITSTATIC int __init
4077 sisfb_setup(char *options)
4079 char *this_opt;
4081 sisfb_setdefaultparms();
4083 if(!options || !(*options))
4084 return 0;
4086 while((this_opt = strsep(&options, ",")) != NULL) {
4088 if(!(*this_opt)) continue;
4090 if(!strnicmp(this_opt, "off", 3)) {
4091 sisfb_off = 1;
4092 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4093 /* Need to check crt2 type first for fstn/dstn */
4094 sisfb_search_crt2type(this_opt + 14);
4095 } else if(!strnicmp(this_opt, "tvmode:",7)) {
4096 sisfb_search_tvstd(this_opt + 7);
4097 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4098 sisfb_search_tvstd(this_opt + 11);
4099 } else if(!strnicmp(this_opt, "mode:", 5)) {
4100 sisfb_search_mode(this_opt + 5, FALSE);
4101 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4102 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4103 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4104 } else if(!strnicmp(this_opt, "inverse", 7)) {
4105 sisfb_inverse = 1;
4106 /* fb_invert_cmaps(); */
4107 } else if(!strnicmp(this_opt, "font:", 5)) {
4108 if(strlen(this_opt + 5) < 40) {
4109 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4110 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4112 #endif
4113 } else if(!strnicmp(this_opt, "rate:", 5)) {
4114 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4115 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4116 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4117 } else if(!strnicmp(this_opt, "mem:",4)) {
4118 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4119 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4120 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4121 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4122 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4123 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4124 sisfb_accel = 0;
4125 } else if(!strnicmp(this_opt, "accel", 5)) {
4126 sisfb_accel = -1;
4127 } else if(!strnicmp(this_opt, "noypan", 6)) {
4128 sisfb_ypan = 0;
4129 } else if(!strnicmp(this_opt, "ypan", 4)) {
4130 sisfb_ypan = -1;
4131 } else if(!strnicmp(this_opt, "nomax", 5)) {
4132 sisfb_max = 0;
4133 } else if(!strnicmp(this_opt, "max", 3)) {
4134 sisfb_max = -1;
4135 } else if(!strnicmp(this_opt, "userom:", 7)) {
4136 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4137 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4138 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4139 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4140 sisfb_nocrt2rate = 1;
4141 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4142 unsigned long temp = 2;
4143 temp = simple_strtoul(this_opt + 9, NULL, 0);
4144 if((temp == 0) || (temp == 1)) {
4145 sisfb_scalelcd = temp ^ 1;
4147 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4148 int temp = 0;
4149 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4150 if((temp >= -32) && (temp <= 32)) {
4151 sisfb_tvxposoffset = temp;
4153 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4154 int temp = 0;
4155 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4156 if((temp >= -32) && (temp <= 32)) {
4157 sisfb_tvyposoffset = temp;
4159 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4160 sisfb_search_specialtiming(this_opt + 14);
4161 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4162 int temp = 4;
4163 temp = simple_strtoul(this_opt + 7, NULL, 0);
4164 if((temp >= 0) && (temp <= 3)) {
4165 sisfb_lvdshl = temp;
4167 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4168 sisfb_search_mode(this_opt, TRUE);
4169 #if !defined(__i386__) && !defined(__x86_64__)
4170 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4171 sisfb_resetcard = 1;
4172 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4173 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4174 #endif
4175 } else {
4176 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4181 return 0;
4183 #endif
4185 static int __devinit
4186 sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4188 SIS_IOTYPE1 *rom;
4189 int romptr;
4191 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4192 return 0;
4194 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4195 if(romptr > (0x10000 - 8))
4196 return 0;
4198 rom = rom_base + romptr;
4200 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4201 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4202 return 0;
4204 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4205 return 0;
4207 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4208 return 0;
4210 return 1;
4213 static unsigned char * __devinit
4214 sisfb_find_rom(struct pci_dev *pdev)
4216 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4217 SIS_IOTYPE1 *rom_base;
4218 unsigned char *myrombase = NULL;
4219 u32 temp;
4220 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4221 size_t romsize;
4223 /* First, try the official pci ROM functions (except
4224 * on integrated chipsets which have no ROM).
4227 if(!ivideo->nbridge) {
4229 if((rom_base = pci_map_rom(pdev, &romsize))) {
4231 if(sisfb_check_rom(rom_base, ivideo)) {
4233 if((myrombase = vmalloc(65536))) {
4235 /* Work around bug in pci/rom.c: Folks forgot to check
4236 * whether the size retrieved from the BIOS image eventually
4237 * is larger than the mapped size
4239 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4240 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4242 memcpy_fromio(myrombase, rom_base,
4243 (romsize > 65536) ? 65536 : romsize);
4246 pci_unmap_rom(pdev, rom_base);
4250 if(myrombase) return myrombase;
4251 #endif
4253 /* Otherwise do it the conventional way. */
4255 #if defined(__i386__) || defined(__x86_64__)
4257 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4259 rom_base = ioremap(temp, 65536);
4260 if(!rom_base)
4261 continue;
4263 if(!sisfb_check_rom(rom_base, ivideo)) {
4264 iounmap(rom_base);
4265 continue;
4268 if((myrombase = vmalloc(65536)))
4269 memcpy_fromio(myrombase, rom_base, 65536);
4271 iounmap(rom_base);
4272 break;
4276 #else
4278 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4279 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4280 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4282 rom_base = ioremap(ivideo->video_base, 65536);
4283 if(rom_base) {
4284 if(sisfb_check_rom(rom_base, ivideo)) {
4285 if((myrombase = vmalloc(65536)))
4286 memcpy_fromio(myrombase, rom_base, 65536);
4288 iounmap(rom_base);
4291 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4293 #endif
4295 return myrombase;
4298 static void __devinit
4299 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4300 unsigned int min)
4302 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4304 if(!ivideo->video_vbase) {
4305 printk(KERN_ERR
4306 "sisfb: Unable to map maximum video RAM for size detection\n");
4307 (*mapsize) >>= 1;
4308 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4309 (*mapsize) >>= 1;
4310 if((*mapsize) < (min << 20))
4311 break;
4313 if(ivideo->video_vbase) {
4314 printk(KERN_ERR
4315 "sisfb: Video RAM size detection limited to %dMB\n",
4316 (int)((*mapsize) >> 20));
4321 #ifdef CONFIG_FB_SIS_300
4322 static int __devinit
4323 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4325 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4326 unsigned short temp;
4327 unsigned char reg;
4328 int i, j;
4330 andSISIDXREG(SISSR, 0x15, 0xFB);
4331 orSISIDXREG(SISSR, 0x15, 0x04);
4332 outSISIDXREG(SISSR, 0x13, 0x00);
4333 outSISIDXREG(SISSR, 0x14, 0xBF);
4335 for(i = 0; i < 2; i++) {
4336 temp = 0x1234;
4337 for(j = 0; j < 4; j++) {
4338 writew(temp, FBAddress);
4339 if(readw(FBAddress) == temp)
4340 break;
4341 orSISIDXREG(SISSR, 0x3c, 0x01);
4342 inSISIDXREG(SISSR, 0x05, reg);
4343 inSISIDXREG(SISSR, 0x05, reg);
4344 andSISIDXREG(SISSR, 0x3c, 0xfe);
4345 inSISIDXREG(SISSR, 0x05, reg);
4346 inSISIDXREG(SISSR, 0x05, reg);
4347 temp++;
4351 writel(0x01234567L, FBAddress);
4352 writel(0x456789ABL, (FBAddress + 4));
4353 writel(0x89ABCDEFL, (FBAddress + 8));
4354 writel(0xCDEF0123L, (FBAddress + 12));
4356 inSISIDXREG(SISSR, 0x3b, reg);
4357 if(reg & 0x01) {
4358 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4359 return 4; /* Channel A 128bit */
4362 if(readl((FBAddress + 4)) == 0x456789ABL)
4363 return 2; /* Channel B 64bit */
4365 return 1; /* 32bit */
4368 static int __devinit
4369 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4370 int PseudoRankCapacity, int PseudoAdrPinCount,
4371 unsigned int mapsize)
4373 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4374 unsigned short sr14;
4375 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4376 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4377 static const unsigned short SiS_DRAMType[17][5] = {
4378 {0x0C,0x0A,0x02,0x40,0x39},
4379 {0x0D,0x0A,0x01,0x40,0x48},
4380 {0x0C,0x09,0x02,0x20,0x35},
4381 {0x0D,0x09,0x01,0x20,0x44},
4382 {0x0C,0x08,0x02,0x10,0x31},
4383 {0x0D,0x08,0x01,0x10,0x40},
4384 {0x0C,0x0A,0x01,0x20,0x34},
4385 {0x0C,0x09,0x01,0x08,0x32},
4386 {0x0B,0x08,0x02,0x08,0x21},
4387 {0x0C,0x08,0x01,0x08,0x30},
4388 {0x0A,0x08,0x02,0x04,0x11},
4389 {0x0B,0x0A,0x01,0x10,0x28},
4390 {0x09,0x08,0x02,0x02,0x01},
4391 {0x0B,0x09,0x01,0x08,0x24},
4392 {0x0B,0x08,0x01,0x04,0x20},
4393 {0x0A,0x08,0x01,0x02,0x10},
4394 {0x09,0x08,0x01,0x01,0x00}
4397 for(k = 0; k <= 16; k++) {
4399 RankCapacity = buswidth * SiS_DRAMType[k][3];
4401 if(RankCapacity != PseudoRankCapacity)
4402 continue;
4404 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4405 continue;
4407 BankNumHigh = RankCapacity * 16 * iteration - 1;
4408 if(iteration == 3) { /* Rank No */
4409 BankNumMid = RankCapacity * 16 - 1;
4410 } else {
4411 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4414 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4415 PhysicalAdrHigh = BankNumHigh;
4416 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4417 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4419 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4420 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4421 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4422 if(buswidth == 4) sr14 |= 0x80;
4423 else if(buswidth == 2) sr14 |= 0x40;
4424 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4425 outSISIDXREG(SISSR, 0x14, sr14);
4427 BankNumHigh <<= 16;
4428 BankNumMid <<= 16;
4430 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4431 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4432 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4433 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4434 continue;
4436 /* Write data */
4437 writew(((unsigned short)PhysicalAdrHigh),
4438 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4439 writew(((unsigned short)BankNumMid),
4440 (FBAddr + BankNumMid + PhysicalAdrHigh));
4441 writew(((unsigned short)PhysicalAdrHalfPage),
4442 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4443 writew(((unsigned short)PhysicalAdrOtherPage),
4444 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4446 /* Read data */
4447 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4448 return 1;
4451 return 0;
4454 static void __devinit
4455 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4457 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4458 int i, j, buswidth;
4459 int PseudoRankCapacity, PseudoAdrPinCount;
4461 buswidth = sisfb_post_300_buswidth(ivideo);
4463 for(i = 6; i >= 0; i--) {
4464 PseudoRankCapacity = 1 << i;
4465 for(j = 4; j >= 1; j--) {
4466 PseudoAdrPinCount = 15 - j;
4467 if((PseudoRankCapacity * j) <= 64) {
4468 if(sisfb_post_300_rwtest(ivideo,
4470 buswidth,
4471 PseudoRankCapacity,
4472 PseudoAdrPinCount,
4473 mapsize))
4474 return;
4480 static void __devinit
4481 sisfb_post_sis300(struct pci_dev *pdev)
4483 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4484 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4485 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4486 u16 index, rindex, memtype = 0;
4487 unsigned int mapsize;
4489 if(!ivideo->SiS_Pr.UseROM)
4490 bios = NULL;
4492 outSISIDXREG(SISSR, 0x05, 0x86);
4494 if(bios) {
4495 if(bios[0x52] & 0x80) {
4496 memtype = bios[0x52];
4497 } else {
4498 inSISIDXREG(SISSR, 0x3a, memtype);
4500 memtype &= 0x07;
4503 v3 = 0x80; v6 = 0x80;
4504 if(ivideo->revision_id <= 0x13) {
4505 v1 = 0x44; v2 = 0x42;
4506 v4 = 0x44; v5 = 0x42;
4507 } else {
4508 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4509 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4510 if(bios) {
4511 index = memtype * 5;
4512 rindex = index + 0x54;
4513 v1 = bios[rindex++];
4514 v2 = bios[rindex++];
4515 v3 = bios[rindex++];
4516 rindex = index + 0x7c;
4517 v4 = bios[rindex++];
4518 v5 = bios[rindex++];
4519 v6 = bios[rindex++];
4522 outSISIDXREG(SISSR, 0x28, v1);
4523 outSISIDXREG(SISSR, 0x29, v2);
4524 outSISIDXREG(SISSR, 0x2a, v3);
4525 outSISIDXREG(SISSR, 0x2e, v4);
4526 outSISIDXREG(SISSR, 0x2f, v5);
4527 outSISIDXREG(SISSR, 0x30, v6);
4529 v1 = 0x10;
4530 if(bios)
4531 v1 = bios[0xa4];
4532 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4534 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4536 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4537 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4538 if(bios) {
4539 memtype += 0xa5;
4540 v1 = bios[memtype];
4541 v2 = bios[memtype + 8];
4542 v3 = bios[memtype + 16];
4543 v4 = bios[memtype + 24];
4544 v5 = bios[memtype + 32];
4545 v6 = bios[memtype + 40];
4546 v7 = bios[memtype + 48];
4547 v8 = bios[memtype + 56];
4549 if(ivideo->revision_id >= 0x80)
4550 v3 &= 0xfd;
4551 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4552 outSISIDXREG(SISSR, 0x16, v2);
4553 outSISIDXREG(SISSR, 0x17, v3);
4554 outSISIDXREG(SISSR, 0x18, v4);
4555 outSISIDXREG(SISSR, 0x19, v5);
4556 outSISIDXREG(SISSR, 0x1a, v6);
4557 outSISIDXREG(SISSR, 0x1b, v7);
4558 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4559 andSISIDXREG(SISSR, 0x15 ,0xfb);
4560 orSISIDXREG(SISSR, 0x15, 0x04);
4561 if(bios) {
4562 if(bios[0x53] & 0x02) {
4563 orSISIDXREG(SISSR, 0x19, 0x20);
4566 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4567 if(ivideo->revision_id >= 0x80)
4568 v1 |= 0x01;
4569 outSISIDXREG(SISSR, 0x1f, v1);
4570 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4571 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4572 if(bios) {
4573 v1 = bios[0xe8];
4574 v2 = bios[0xe9];
4575 v3 = bios[0xea];
4577 outSISIDXREG(SISSR, 0x23, v1);
4578 outSISIDXREG(SISSR, 0x24, v2);
4579 outSISIDXREG(SISSR, 0x25, v3);
4580 outSISIDXREG(SISSR, 0x21, 0x84);
4581 outSISIDXREG(SISSR, 0x22, 0x00);
4582 outSISIDXREG(SISCR, 0x37, 0x00);
4583 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4584 outSISIDXREG(SISPART1, 0x00, 0x00);
4585 v1 = 0x40; v2 = 0x11;
4586 if(bios) {
4587 v1 = bios[0xec];
4588 v2 = bios[0xeb];
4590 outSISIDXREG(SISPART1, 0x02, v1);
4592 if(ivideo->revision_id >= 0x80)
4593 v2 &= ~0x01;
4595 inSISIDXREG(SISPART4, 0x00, reg);
4596 if((reg == 1) || (reg == 2)) {
4597 outSISIDXREG(SISCR, 0x37, 0x02);
4598 outSISIDXREG(SISPART2, 0x00, 0x1c);
4599 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4600 if(ivideo->SiS_Pr.UseROM) {
4601 v4 = bios[0xf5];
4602 v5 = bios[0xf6];
4603 v6 = bios[0xf7];
4605 outSISIDXREG(SISPART4, 0x0d, v4);
4606 outSISIDXREG(SISPART4, 0x0e, v5);
4607 outSISIDXREG(SISPART4, 0x10, v6);
4608 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4609 inSISIDXREG(SISPART4, 0x01, reg);
4610 if(reg >= 0xb0) {
4611 inSISIDXREG(SISPART4, 0x23, reg);
4612 reg &= 0x20;
4613 reg <<= 1;
4614 outSISIDXREG(SISPART4, 0x23, reg);
4616 } else {
4617 v2 &= ~0x10;
4619 outSISIDXREG(SISSR, 0x32, v2);
4621 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4623 inSISIDXREG(SISSR, 0x16, reg);
4624 reg &= 0xc3;
4625 outSISIDXREG(SISCR, 0x35, reg);
4626 outSISIDXREG(SISCR, 0x83, 0x00);
4627 #if !defined(__i386__) && !defined(__x86_64__)
4628 if(sisfb_videoram) {
4629 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4630 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4631 outSISIDXREG(SISSR, 0x14, reg);
4632 } else {
4633 #endif
4634 /* Need to map max FB size for finding out about RAM size */
4635 mapsize = 64 << 20;
4636 sisfb_post_map_vram(ivideo, &mapsize, 4);
4638 if(ivideo->video_vbase) {
4639 sisfb_post_300_ramsize(pdev, mapsize);
4640 iounmap(ivideo->video_vbase);
4641 } else {
4642 printk(KERN_DEBUG
4643 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4644 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4645 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4647 #if !defined(__i386__) && !defined(__x86_64__)
4649 #endif
4650 if(bios) {
4651 v1 = bios[0xe6];
4652 v2 = bios[0xe7];
4653 } else {
4654 inSISIDXREG(SISSR, 0x3a, reg);
4655 if((reg & 0x30) == 0x30) {
4656 v1 = 0x04; /* PCI */
4657 v2 = 0x92;
4658 } else {
4659 v1 = 0x14; /* AGP */
4660 v2 = 0xb2;
4663 outSISIDXREG(SISSR, 0x21, v1);
4664 outSISIDXREG(SISSR, 0x22, v2);
4666 /* Sense CRT1 */
4667 sisfb_sense_crt1(ivideo);
4669 /* Set default mode, don't clear screen */
4670 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4671 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4672 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4673 ivideo->curFSTN = ivideo->curDSTN = 0;
4674 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4675 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4677 outSISIDXREG(SISSR, 0x05, 0x86);
4679 /* Display off */
4680 orSISIDXREG(SISSR, 0x01, 0x20);
4682 /* Save mode number in CR34 */
4683 outSISIDXREG(SISCR, 0x34, 0x2e);
4685 /* Let everyone know what the current mode is */
4686 ivideo->modeprechange = 0x2e;
4688 #endif
4690 #ifdef CONFIG_FB_SIS_315
4691 #if 0
4692 static void __devinit
4693 sisfb_post_sis315330(struct pci_dev *pdev)
4695 /* TODO */
4697 #endif
4699 static void __devinit
4700 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4702 unsigned int i;
4703 u8 reg;
4705 for(i = 0; i <= (delay * 10 * 36); i++) {
4706 inSISIDXREG(SISSR, 0x05, reg);
4707 reg++;
4711 static int __devinit
4712 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4713 unsigned short pcivendor)
4715 struct pci_dev *pdev = NULL;
4716 unsigned short temp;
4717 int ret = 0;
4719 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4720 temp = pdev->vendor;
4721 SIS_PCI_PUT_DEVICE(pdev);
4722 if(temp == pcivendor) {
4723 ret = 1;
4724 break;
4728 return ret;
4731 static int __devinit
4732 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4733 unsigned int enda, unsigned int mapsize)
4735 unsigned int pos;
4736 int i;
4738 writel(0, ivideo->video_vbase);
4740 for(i = starta; i <= enda; i++) {
4741 pos = 1 << i;
4742 if(pos < mapsize)
4743 writel(pos, ivideo->video_vbase + pos);
4746 sisfb_post_xgi_delay(ivideo, 150);
4748 if(readl(ivideo->video_vbase) != 0)
4749 return 0;
4751 for(i = starta; i <= enda; i++) {
4752 pos = 1 << i;
4753 if(pos < mapsize) {
4754 if(readl(ivideo->video_vbase + pos) != pos)
4755 return 0;
4756 } else
4757 return 0;
4760 return 1;
4763 static void __devinit
4764 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4766 unsigned int buswidth, ranksize, channelab, mapsize;
4767 int i, j, k, l;
4768 u8 reg, sr14;
4769 static const u8 dramsr13[12 * 5] = {
4770 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4771 0x02, 0x0e, 0x0a, 0x40, 0x59,
4772 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4773 0x02, 0x0e, 0x09, 0x20, 0x55,
4774 0x02, 0x0d, 0x0a, 0x20, 0x49,
4775 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4776 0x02, 0x0e, 0x08, 0x10, 0x51,
4777 0x02, 0x0d, 0x09, 0x10, 0x45,
4778 0x02, 0x0c, 0x0a, 0x10, 0x39,
4779 0x02, 0x0d, 0x08, 0x08, 0x41,
4780 0x02, 0x0c, 0x09, 0x08, 0x35,
4781 0x02, 0x0c, 0x08, 0x04, 0x31
4783 static const u8 dramsr13_4[4 * 5] = {
4784 0x02, 0x0d, 0x09, 0x40, 0x45,
4785 0x02, 0x0c, 0x09, 0x20, 0x35,
4786 0x02, 0x0c, 0x08, 0x10, 0x31,
4787 0x02, 0x0b, 0x08, 0x08, 0x21
4790 /* Enable linear mode, disable 0xa0000 address decoding */
4791 /* We disable a0000 address decoding, because
4792 * - if running on x86, if the card is disabled, it means
4793 * that another card is in the system. We don't want
4794 * to interphere with that primary card's textmode.
4795 * - if running on non-x86, there usually is no VGA window
4796 * at a0000.
4798 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4800 /* Need to map max FB size for finding out about RAM size */
4801 mapsize = 256 << 20;
4802 sisfb_post_map_vram(ivideo, &mapsize, 32);
4804 if(!ivideo->video_vbase) {
4805 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4806 outSISIDXREG(SISSR, 0x13, 0x35);
4807 outSISIDXREG(SISSR, 0x14, 0x41);
4808 /* TODO */
4809 return;
4812 /* Non-interleaving */
4813 outSISIDXREG(SISSR, 0x15, 0x00);
4814 /* No tiling */
4815 outSISIDXREG(SISSR, 0x1c, 0x00);
4817 if(ivideo->chip == XGI_20) {
4819 channelab = 1;
4820 inSISIDXREG(SISCR, 0x97, reg);
4821 if(!(reg & 0x01)) { /* Single 32/16 */
4822 buswidth = 32;
4823 outSISIDXREG(SISSR, 0x13, 0xb1);
4824 outSISIDXREG(SISSR, 0x14, 0x52);
4825 sisfb_post_xgi_delay(ivideo, 1);
4826 sr14 = 0x02;
4827 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4828 goto bail_out;
4830 outSISIDXREG(SISSR, 0x13, 0x31);
4831 outSISIDXREG(SISSR, 0x14, 0x42);
4832 sisfb_post_xgi_delay(ivideo, 1);
4833 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4834 goto bail_out;
4836 buswidth = 16;
4837 outSISIDXREG(SISSR, 0x13, 0xb1);
4838 outSISIDXREG(SISSR, 0x14, 0x41);
4839 sisfb_post_xgi_delay(ivideo, 1);
4840 sr14 = 0x01;
4841 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4842 goto bail_out;
4843 else
4844 outSISIDXREG(SISSR, 0x13, 0x31);
4845 } else { /* Dual 16/8 */
4846 buswidth = 16;
4847 outSISIDXREG(SISSR, 0x13, 0xb1);
4848 outSISIDXREG(SISSR, 0x14, 0x41);
4849 sisfb_post_xgi_delay(ivideo, 1);
4850 sr14 = 0x01;
4851 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4852 goto bail_out;
4854 outSISIDXREG(SISSR, 0x13, 0x31);
4855 outSISIDXREG(SISSR, 0x14, 0x31);
4856 sisfb_post_xgi_delay(ivideo, 1);
4857 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4858 goto bail_out;
4860 buswidth = 8;
4861 outSISIDXREG(SISSR, 0x13, 0xb1);
4862 outSISIDXREG(SISSR, 0x14, 0x30);
4863 sisfb_post_xgi_delay(ivideo, 1);
4864 sr14 = 0x00;
4865 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4866 goto bail_out;
4867 else
4868 outSISIDXREG(SISSR, 0x13, 0x31);
4871 } else { /* XGI_40 */
4873 inSISIDXREG(SISCR, 0x97, reg);
4874 if(!(reg & 0x10)) {
4875 inSISIDXREG(SISSR, 0x39, reg);
4876 reg >>= 1;
4879 if(reg & 0x01) { /* DDRII */
4880 buswidth = 32;
4881 if(ivideo->revision_id == 2) {
4882 channelab = 2;
4883 outSISIDXREG(SISSR, 0x13, 0xa1);
4884 outSISIDXREG(SISSR, 0x14, 0x44);
4885 sr14 = 0x04;
4886 sisfb_post_xgi_delay(ivideo, 1);
4887 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4888 goto bail_out;
4890 outSISIDXREG(SISSR, 0x13, 0x21);
4891 outSISIDXREG(SISSR, 0x14, 0x34);
4892 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4893 goto bail_out;
4895 channelab = 1;
4896 outSISIDXREG(SISSR, 0x13, 0xa1);
4897 outSISIDXREG(SISSR, 0x14, 0x40);
4898 sr14 = 0x00;
4899 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4900 goto bail_out;
4902 outSISIDXREG(SISSR, 0x13, 0x21);
4903 outSISIDXREG(SISSR, 0x14, 0x30);
4904 } else {
4905 channelab = 3;
4906 outSISIDXREG(SISSR, 0x13, 0xa1);
4907 outSISIDXREG(SISSR, 0x14, 0x4c);
4908 sr14 = 0x0c;
4909 sisfb_post_xgi_delay(ivideo, 1);
4910 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4911 goto bail_out;
4913 channelab = 2;
4914 outSISIDXREG(SISSR, 0x14, 0x48);
4915 sisfb_post_xgi_delay(ivideo, 1);
4916 sr14 = 0x08;
4917 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4918 goto bail_out;
4920 outSISIDXREG(SISSR, 0x13, 0x21);
4921 outSISIDXREG(SISSR, 0x14, 0x3c);
4922 sr14 = 0x0c;
4924 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4925 channelab = 3;
4926 } else {
4927 channelab = 2;
4928 outSISIDXREG(SISSR, 0x14, 0x38);
4929 sr14 = 0x08;
4932 sisfb_post_xgi_delay(ivideo, 1);
4934 } else { /* DDR */
4936 buswidth = 64;
4937 if(ivideo->revision_id == 2) {
4938 channelab = 1;
4939 outSISIDXREG(SISSR, 0x13, 0xa1);
4940 outSISIDXREG(SISSR, 0x14, 0x52);
4941 sisfb_post_xgi_delay(ivideo, 1);
4942 sr14 = 0x02;
4943 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4944 goto bail_out;
4946 outSISIDXREG(SISSR, 0x13, 0x21);
4947 outSISIDXREG(SISSR, 0x14, 0x42);
4948 } else {
4949 channelab = 2;
4950 outSISIDXREG(SISSR, 0x13, 0xa1);
4951 outSISIDXREG(SISSR, 0x14, 0x5a);
4952 sisfb_post_xgi_delay(ivideo, 1);
4953 sr14 = 0x0a;
4954 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4955 goto bail_out;
4957 outSISIDXREG(SISSR, 0x13, 0x21);
4958 outSISIDXREG(SISSR, 0x14, 0x4a);
4960 sisfb_post_xgi_delay(ivideo, 1);
4965 bail_out:
4966 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4967 sisfb_post_xgi_delay(ivideo, 1);
4969 j = (ivideo->chip == XGI_20) ? 5 : 9;
4970 k = (ivideo->chip == XGI_20) ? 12 : 4;
4972 for(i = 0; i < k; i++) {
4974 reg = (ivideo->chip == XGI_20) ?
4975 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4976 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4977 sisfb_post_xgi_delay(ivideo, 50);
4979 ranksize = (ivideo->chip == XGI_20) ?
4980 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4982 inSISIDXREG(SISSR, 0x13, reg);
4983 if(reg & 0x80) ranksize <<= 1;
4985 if(ivideo->chip == XGI_20) {
4986 if(buswidth == 16) ranksize <<= 1;
4987 else if(buswidth == 32) ranksize <<= 2;
4988 } else {
4989 if(buswidth == 64) ranksize <<= 1;
4992 reg = 0;
4993 l = channelab;
4994 if(l == 3) l = 4;
4995 if((ranksize * l) <= 256) {
4996 while((ranksize >>= 1)) reg += 0x10;
4999 if(!reg) continue;
5001 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
5002 sisfb_post_xgi_delay(ivideo, 1);
5004 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5005 break;
5008 iounmap(ivideo->video_vbase);
5011 static void __devinit
5012 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5014 u8 v1, v2, v3;
5015 int index;
5016 static const u8 cs90[8 * 3] = {
5017 0x16, 0x01, 0x01,
5018 0x3e, 0x03, 0x01,
5019 0x7c, 0x08, 0x01,
5020 0x79, 0x06, 0x01,
5021 0x29, 0x01, 0x81,
5022 0x5c, 0x23, 0x01,
5023 0x5c, 0x23, 0x01,
5024 0x5c, 0x23, 0x01
5026 static const u8 csb8[8 * 3] = {
5027 0x5c, 0x23, 0x01,
5028 0x29, 0x01, 0x01,
5029 0x7c, 0x08, 0x01,
5030 0x79, 0x06, 0x01,
5031 0x29, 0x01, 0x81,
5032 0x5c, 0x23, 0x01,
5033 0x5c, 0x23, 0x01,
5034 0x5c, 0x23, 0x01
5037 regb = 0; /* ! */
5039 index = regb * 3;
5040 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5041 if(ivideo->haveXGIROM) {
5042 v1 = ivideo->bios_abase[0x90 + index];
5043 v2 = ivideo->bios_abase[0x90 + index + 1];
5044 v3 = ivideo->bios_abase[0x90 + index + 2];
5046 outSISIDXREG(SISSR, 0x28, v1);
5047 outSISIDXREG(SISSR, 0x29, v2);
5048 outSISIDXREG(SISSR, 0x2a, v3);
5049 sisfb_post_xgi_delay(ivideo, 0x43);
5050 sisfb_post_xgi_delay(ivideo, 0x43);
5051 sisfb_post_xgi_delay(ivideo, 0x43);
5052 index = regb * 3;
5053 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5054 if(ivideo->haveXGIROM) {
5055 v1 = ivideo->bios_abase[0xb8 + index];
5056 v2 = ivideo->bios_abase[0xb8 + index + 1];
5057 v3 = ivideo->bios_abase[0xb8 + index + 2];
5059 outSISIDXREG(SISSR, 0x2e, v1);
5060 outSISIDXREG(SISSR, 0x2f, v2);
5061 outSISIDXREG(SISSR, 0x30, v3);
5062 sisfb_post_xgi_delay(ivideo, 0x43);
5063 sisfb_post_xgi_delay(ivideo, 0x43);
5064 sisfb_post_xgi_delay(ivideo, 0x43);
5067 static int __devinit
5068 sisfb_post_xgi(struct pci_dev *pdev)
5070 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5071 unsigned char *bios = ivideo->bios_abase;
5072 struct pci_dev *mypdev = NULL;
5073 const u8 *ptr, *ptr2;
5074 u8 v1, v2, v3, v4, v5, reg, ramtype;
5075 u32 rega, regb, regd;
5076 int i, j, k, index;
5077 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5078 static const u8 cs76[2] = { 0xa3, 0xfb };
5079 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5080 static const u8 cs158[8] = {
5081 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5083 static const u8 cs160[8] = {
5084 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5086 static const u8 cs168[8] = {
5087 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5089 static const u8 cs128[3 * 8] = {
5090 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5091 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5092 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5094 static const u8 cs148[2 * 8] = {
5095 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5096 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5098 static const u8 cs31a[8 * 4] = {
5099 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5100 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5104 static const u8 cs33a[8 * 4] = {
5105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5110 static const u8 cs45a[8 * 2] = {
5111 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5114 static const u8 cs170[7 * 8] = {
5115 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5116 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5117 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5118 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5119 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5120 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5121 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5123 static const u8 cs1a8[3 * 8] = {
5124 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5125 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5128 static const u8 cs100[2 * 8] = {
5129 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5130 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5133 /* VGA enable */
5134 reg = inSISREG(SISVGAENABLE) | 0x01;
5135 outSISREG(SISVGAENABLE, reg);
5137 /* Misc */
5138 reg = inSISREG(SISMISCR) | 0x01;
5139 outSISREG(SISMISCW, reg);
5141 /* Unlock SR */
5142 outSISIDXREG(SISSR, 0x05, 0x86);
5143 inSISIDXREG(SISSR, 0x05, reg);
5144 if(reg != 0xa1)
5145 return 0;
5147 /* Clear some regs */
5148 for(i = 0; i < 0x22; i++) {
5149 if(0x06 + i == 0x20) continue;
5150 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5152 for(i = 0; i < 0x0b; i++) {
5153 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5155 for(i = 0; i < 0x10; i++) {
5156 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5159 ptr = cs78;
5160 if(ivideo->haveXGIROM) {
5161 ptr = (const u8 *)&bios[0x78];
5163 for(i = 0; i < 3; i++) {
5164 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5167 ptr = cs76;
5168 if(ivideo->haveXGIROM) {
5169 ptr = (const u8 *)&bios[0x76];
5171 for(i = 0; i < 2; i++) {
5172 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5175 v1 = 0x18; v2 = 0x00;
5176 if(ivideo->haveXGIROM) {
5177 v1 = bios[0x74];
5178 v2 = bios[0x75];
5180 outSISIDXREG(SISSR, 0x07, v1);
5181 outSISIDXREG(SISSR, 0x11, 0x0f);
5182 outSISIDXREG(SISSR, 0x1f, v2);
5183 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5184 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5185 outSISIDXREG(SISSR, 0x27, 0x74);
5187 ptr = cs7b;
5188 if(ivideo->haveXGIROM) {
5189 ptr = (const u8 *)&bios[0x7b];
5191 for(i = 0; i < 3; i++) {
5192 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5195 if(ivideo->chip == XGI_40) {
5196 if(ivideo->revision_id == 2) {
5197 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5199 outSISIDXREG(SISCR, 0x7d, 0xfe);
5200 outSISIDXREG(SISCR, 0x7e, 0x0f);
5202 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5203 andSISIDXREG(SISCR, 0x58, 0xd7);
5204 inSISIDXREG(SISCR, 0xcb, reg);
5205 if(reg & 0x20) {
5206 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5210 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5211 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5213 if(ivideo->chip == XGI_20) {
5214 outSISIDXREG(SISSR, 0x36, 0x70);
5215 } else {
5216 outSISIDXREG(SISVID, 0x00, 0x86);
5217 outSISIDXREG(SISVID, 0x32, 0x00);
5218 outSISIDXREG(SISVID, 0x30, 0x00);
5219 outSISIDXREG(SISVID, 0x32, 0x01);
5220 outSISIDXREG(SISVID, 0x30, 0x00);
5221 andSISIDXREG(SISVID, 0x2f, 0xdf);
5222 andSISIDXREG(SISCAP, 0x00, 0x3f);
5224 outSISIDXREG(SISPART1, 0x2f, 0x01);
5225 outSISIDXREG(SISPART1, 0x00, 0x00);
5226 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5227 outSISIDXREG(SISPART1, 0x2e, 0x08);
5228 andSISIDXREG(SISPART1, 0x35, 0x7f);
5229 andSISIDXREG(SISPART1, 0x50, 0xfe);
5231 inSISIDXREG(SISPART4, 0x00, reg);
5232 if(reg == 1 || reg == 2) {
5233 outSISIDXREG(SISPART2, 0x00, 0x1c);
5234 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5235 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5236 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5237 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5239 inSISIDXREG(SISPART4, 0x01, reg);
5240 if((reg & 0xf0) >= 0xb0) {
5241 inSISIDXREG(SISPART4, 0x23, reg);
5242 if(reg & 0x20) reg |= 0x40;
5243 outSISIDXREG(SISPART4, 0x23, reg);
5244 reg = (reg & 0x20) ? 0x02 : 0x00;
5245 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5249 v1 = bios[0x77];
5251 inSISIDXREG(SISSR, 0x3b, reg);
5252 if(reg & 0x02) {
5253 inSISIDXREG(SISSR, 0x3a, reg);
5254 v2 = (reg & 0x30) >> 3;
5255 if(!(v2 & 0x04)) v2 ^= 0x02;
5256 inSISIDXREG(SISSR, 0x39, reg);
5257 if(reg & 0x80) v2 |= 0x80;
5258 v2 |= 0x01;
5260 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5261 SIS_PCI_PUT_DEVICE(mypdev);
5262 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5263 v2 &= 0xf9;
5264 v2 |= 0x08;
5265 v1 &= 0xfe;
5266 } else {
5267 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5268 if(!mypdev)
5269 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5270 if(!mypdev)
5271 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5272 if(mypdev) {
5273 pci_read_config_dword(mypdev, 0x94, &regd);
5274 regd &= 0xfffffeff;
5275 pci_write_config_dword(mypdev, 0x94, regd);
5276 v1 &= 0xfe;
5277 SIS_PCI_PUT_DEVICE(mypdev);
5278 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5279 v1 &= 0xfe;
5280 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5281 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5282 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5283 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5284 if((v2 & 0x06) == 4)
5285 v2 ^= 0x06;
5286 v2 |= 0x08;
5289 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5291 outSISIDXREG(SISSR, 0x22, v1);
5293 if(ivideo->revision_id == 2) {
5294 inSISIDXREG(SISSR, 0x3b, v1);
5295 inSISIDXREG(SISSR, 0x3a, v2);
5296 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5297 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5298 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5300 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5301 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5302 * of nforce 2 ROM
5304 if(0)
5305 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5306 SIS_PCI_PUT_DEVICE(mypdev);
5310 v1 = 0x30;
5311 inSISIDXREG(SISSR, 0x3b, reg);
5312 inSISIDXREG(SISCR, 0x5f, v2);
5313 if((!(reg & 0x02)) && (v2 & 0x0e))
5314 v1 |= 0x08;
5315 outSISIDXREG(SISSR, 0x27, v1);
5317 if(bios[0x64] & 0x01) {
5318 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5321 v1 = bios[0x4f7];
5322 pci_read_config_dword(pdev, 0x50, &regd);
5323 regd = (regd >> 20) & 0x0f;
5324 if(regd == 1) {
5325 v1 &= 0xfc;
5326 orSISIDXREG(SISCR, 0x5f, 0x08);
5328 outSISIDXREG(SISCR, 0x48, v1);
5330 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5331 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5332 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5333 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5334 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5335 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5336 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5337 outSISIDXREG(SISCR, 0x74, 0xd0);
5338 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5339 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5340 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5341 v1 = bios[0x501];
5342 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5343 v1 = 0xf0;
5344 SIS_PCI_PUT_DEVICE(mypdev);
5346 outSISIDXREG(SISCR, 0x77, v1);
5349 /* RAM type */
5351 regb = 0; /* ! */
5353 v1 = 0xff;
5354 if(ivideo->haveXGIROM) {
5355 v1 = bios[0x140 + regb];
5357 outSISIDXREG(SISCR, 0x6d, v1);
5359 ptr = cs128;
5360 if(ivideo->haveXGIROM) {
5361 ptr = (const u8 *)&bios[0x128];
5363 for(i = 0, j = 0; i < 3; i++, j += 8) {
5364 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5367 ptr = cs31a;
5368 ptr2 = cs33a;
5369 if(ivideo->haveXGIROM) {
5370 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5371 ptr = (const u8 *)&bios[index];
5372 ptr2 = (const u8 *)&bios[index + 0x20];
5374 for(i = 0; i < 2; i++) {
5375 if(i == 0) {
5376 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5377 rega = 0x6b;
5378 } else {
5379 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5380 rega = 0x6e;
5382 reg = 0x00;
5383 for(j = 0; j < 16; j++) {
5384 reg &= 0xf3;
5385 if(regd & 0x01) reg |= 0x04;
5386 if(regd & 0x02) reg |= 0x08;
5387 regd >>= 2;
5388 outSISIDXREG(SISCR, rega, reg);
5389 inSISIDXREG(SISCR, rega, reg);
5390 inSISIDXREG(SISCR, rega, reg);
5391 reg += 0x10;
5395 andSISIDXREG(SISCR, 0x6e, 0xfc);
5397 ptr = NULL;
5398 if(ivideo->haveXGIROM) {
5399 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5400 ptr = (const u8 *)&bios[index];
5402 for(i = 0; i < 4; i++) {
5403 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5404 reg = 0x00;
5405 for(j = 0; j < 2; j++) {
5406 regd = 0;
5407 if(ptr) {
5408 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5409 ptr += 4;
5411 /* reg = 0x00; */
5412 for(k = 0; k < 16; k++) {
5413 reg &= 0xfc;
5414 if(regd & 0x01) reg |= 0x01;
5415 if(regd & 0x02) reg |= 0x02;
5416 regd >>= 2;
5417 outSISIDXREG(SISCR, 0x6f, reg);
5418 inSISIDXREG(SISCR, 0x6f, reg);
5419 inSISIDXREG(SISCR, 0x6f, reg);
5420 reg += 0x08;
5425 ptr = cs148;
5426 if(ivideo->haveXGIROM) {
5427 ptr = (const u8 *)&bios[0x148];
5429 for(i = 0, j = 0; i < 2; i++, j += 8) {
5430 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5433 andSISIDXREG(SISCR, 0x89, 0x8f);
5435 ptr = cs45a;
5436 if(ivideo->haveXGIROM) {
5437 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5438 ptr = (const u8 *)&bios[index];
5440 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5441 reg = 0x80;
5442 for(i = 0; i < 5; i++) {
5443 reg &= 0xfc;
5444 if(regd & 0x01) reg |= 0x01;
5445 if(regd & 0x02) reg |= 0x02;
5446 regd >>= 2;
5447 outSISIDXREG(SISCR, 0x89, reg);
5448 inSISIDXREG(SISCR, 0x89, reg);
5449 inSISIDXREG(SISCR, 0x89, reg);
5450 reg += 0x10;
5453 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5454 if(ivideo->haveXGIROM) {
5455 v1 = bios[0x118 + regb];
5456 v2 = bios[0xf8 + regb];
5457 v3 = bios[0x120 + regb];
5458 v4 = bios[0x1ca];
5460 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5461 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5462 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5463 outSISIDXREG(SISCR, 0x41, v2);
5465 ptr = cs170;
5466 if(ivideo->haveXGIROM) {
5467 ptr = (const u8 *)&bios[0x170];
5469 for(i = 0, j = 0; i < 7; i++, j += 8) {
5470 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5473 outSISIDXREG(SISCR, 0x59, v3);
5475 ptr = cs1a8;
5476 if(ivideo->haveXGIROM) {
5477 ptr = (const u8 *)&bios[0x1a8];
5479 for(i = 0, j = 0; i < 3; i++, j += 8) {
5480 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5483 ptr = cs100;
5484 if(ivideo->haveXGIROM) {
5485 ptr = (const u8 *)&bios[0x100];
5487 for(i = 0, j = 0; i < 2; i++, j += 8) {
5488 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5491 outSISIDXREG(SISCR, 0xcf, v4);
5493 outSISIDXREG(SISCR, 0x83, 0x09);
5494 outSISIDXREG(SISCR, 0x87, 0x00);
5496 if(ivideo->chip == XGI_40) {
5497 if( (ivideo->revision_id == 1) ||
5498 (ivideo->revision_id == 2) ) {
5499 outSISIDXREG(SISCR, 0x8c, 0x87);
5503 outSISIDXREG(SISSR, 0x17, 0x00);
5504 outSISIDXREG(SISSR, 0x1a, 0x87);
5506 if(ivideo->chip == XGI_20) {
5507 outSISIDXREG(SISSR, 0x15, 0x00);
5508 outSISIDXREG(SISSR, 0x1c, 0x00);
5511 ramtype = 0x00; v1 = 0x10;
5512 if(ivideo->haveXGIROM) {
5513 ramtype = bios[0x62];
5514 v1 = bios[0x1d2];
5516 if(!(ramtype & 0x80)) {
5517 if(ivideo->chip == XGI_20) {
5518 outSISIDXREG(SISCR, 0x97, v1);
5519 inSISIDXREG(SISCR, 0x97, reg);
5520 if(reg & 0x10) {
5521 ramtype = (reg & 0x01) << 1;
5523 } else {
5524 inSISIDXREG(SISSR, 0x39, reg);
5525 ramtype = reg & 0x02;
5526 if(!(ramtype)) {
5527 inSISIDXREG(SISSR, 0x3a, reg);
5528 ramtype = (reg >> 1) & 0x01;
5532 ramtype &= 0x07;
5534 regb = 0; /* ! */
5536 switch(ramtype) {
5537 case 0:
5538 sisfb_post_xgi_setclocks(ivideo, regb);
5539 if((ivideo->chip == XGI_20) ||
5540 (ivideo->revision_id == 1) ||
5541 (ivideo->revision_id == 2)) {
5542 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5543 if(ivideo->haveXGIROM) {
5544 v1 = bios[regb + 0x158];
5545 v2 = bios[regb + 0x160];
5546 v3 = bios[regb + 0x168];
5548 outSISIDXREG(SISCR, 0x82, v1);
5549 outSISIDXREG(SISCR, 0x85, v2);
5550 outSISIDXREG(SISCR, 0x86, v3);
5551 } else {
5552 outSISIDXREG(SISCR, 0x82, 0x88);
5553 outSISIDXREG(SISCR, 0x86, 0x00);
5554 inSISIDXREG(SISCR, 0x86, reg);
5555 outSISIDXREG(SISCR, 0x86, 0x88);
5556 inSISIDXREG(SISCR, 0x86, reg);
5557 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5558 outSISIDXREG(SISCR, 0x82, 0x77);
5559 outSISIDXREG(SISCR, 0x85, 0x00);
5560 inSISIDXREG(SISCR, 0x85, reg);
5561 outSISIDXREG(SISCR, 0x85, 0x88);
5562 inSISIDXREG(SISCR, 0x85, reg);
5563 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5564 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5566 if(ivideo->chip == XGI_40) {
5567 outSISIDXREG(SISCR, 0x97, 0x00);
5569 outSISIDXREG(SISCR, 0x98, 0x01);
5570 outSISIDXREG(SISCR, 0x9a, 0x02);
5572 outSISIDXREG(SISSR, 0x18, 0x01);
5573 if((ivideo->chip == XGI_20) ||
5574 (ivideo->revision_id == 2)) {
5575 outSISIDXREG(SISSR, 0x19, 0x40);
5576 } else {
5577 outSISIDXREG(SISSR, 0x19, 0x20);
5579 outSISIDXREG(SISSR, 0x16, 0x00);
5580 outSISIDXREG(SISSR, 0x16, 0x80);
5581 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5582 sisfb_post_xgi_delay(ivideo, 0x43);
5583 sisfb_post_xgi_delay(ivideo, 0x43);
5584 sisfb_post_xgi_delay(ivideo, 0x43);
5585 outSISIDXREG(SISSR, 0x18, 0x00);
5586 if((ivideo->chip == XGI_20) ||
5587 (ivideo->revision_id == 2)) {
5588 outSISIDXREG(SISSR, 0x19, 0x40);
5589 } else {
5590 outSISIDXREG(SISSR, 0x19, 0x20);
5592 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5593 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5595 outSISIDXREG(SISSR, 0x16, 0x00);
5596 outSISIDXREG(SISSR, 0x16, 0x80);
5597 sisfb_post_xgi_delay(ivideo, 4);
5598 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5599 if(ivideo->haveXGIROM) {
5600 v1 = bios[0xf0];
5601 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5602 v2 = bios[index];
5603 v3 = bios[index + 1];
5604 v4 = bios[index + 2];
5605 v5 = bios[index + 3];
5607 outSISIDXREG(SISSR, 0x18, v1);
5608 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5609 outSISIDXREG(SISSR, 0x16, v2);
5610 outSISIDXREG(SISSR, 0x16, v3);
5611 sisfb_post_xgi_delay(ivideo, 0x43);
5612 outSISIDXREG(SISSR, 0x1b, 0x03);
5613 sisfb_post_xgi_delay(ivideo, 0x22);
5614 outSISIDXREG(SISSR, 0x18, v1);
5615 outSISIDXREG(SISSR, 0x19, 0x00);
5616 outSISIDXREG(SISSR, 0x16, v4);
5617 outSISIDXREG(SISSR, 0x16, v5);
5618 outSISIDXREG(SISSR, 0x1b, 0x00);
5619 break;
5620 case 1:
5621 outSISIDXREG(SISCR, 0x82, 0x77);
5622 outSISIDXREG(SISCR, 0x86, 0x00);
5623 inSISIDXREG(SISCR, 0x86, reg);
5624 outSISIDXREG(SISCR, 0x86, 0x88);
5625 inSISIDXREG(SISCR, 0x86, reg);
5626 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5627 if(ivideo->haveXGIROM) {
5628 v1 = bios[regb + 0x168];
5629 v2 = bios[regb + 0x160];
5630 v3 = bios[regb + 0x158];
5632 outSISIDXREG(SISCR, 0x86, v1);
5633 outSISIDXREG(SISCR, 0x82, 0x77);
5634 outSISIDXREG(SISCR, 0x85, 0x00);
5635 inSISIDXREG(SISCR, 0x85, reg);
5636 outSISIDXREG(SISCR, 0x85, 0x88);
5637 inSISIDXREG(SISCR, 0x85, reg);
5638 outSISIDXREG(SISCR, 0x85, v2);
5639 outSISIDXREG(SISCR, 0x82, v3);
5640 outSISIDXREG(SISCR, 0x98, 0x01);
5641 outSISIDXREG(SISCR, 0x9a, 0x02);
5643 outSISIDXREG(SISSR, 0x28, 0x64);
5644 outSISIDXREG(SISSR, 0x29, 0x63);
5645 sisfb_post_xgi_delay(ivideo, 15);
5646 outSISIDXREG(SISSR, 0x18, 0x00);
5647 outSISIDXREG(SISSR, 0x19, 0x20);
5648 outSISIDXREG(SISSR, 0x16, 0x00);
5649 outSISIDXREG(SISSR, 0x16, 0x80);
5650 outSISIDXREG(SISSR, 0x18, 0xc5);
5651 outSISIDXREG(SISSR, 0x19, 0x23);
5652 outSISIDXREG(SISSR, 0x16, 0x00);
5653 outSISIDXREG(SISSR, 0x16, 0x80);
5654 sisfb_post_xgi_delay(ivideo, 1);
5655 outSISIDXREG(SISCR, 0x97,0x11);
5656 sisfb_post_xgi_setclocks(ivideo, regb);
5657 sisfb_post_xgi_delay(ivideo, 0x46);
5658 outSISIDXREG(SISSR, 0x18, 0xc5);
5659 outSISIDXREG(SISSR, 0x19, 0x23);
5660 outSISIDXREG(SISSR, 0x16, 0x00);
5661 outSISIDXREG(SISSR, 0x16, 0x80);
5662 sisfb_post_xgi_delay(ivideo, 1);
5663 outSISIDXREG(SISSR, 0x1b, 0x04);
5664 sisfb_post_xgi_delay(ivideo, 1);
5665 outSISIDXREG(SISSR, 0x1b, 0x00);
5666 sisfb_post_xgi_delay(ivideo, 1);
5667 v1 = 0x31;
5668 if(ivideo->haveXGIROM) {
5669 v1 = bios[0xf0];
5671 outSISIDXREG(SISSR, 0x18, v1);
5672 outSISIDXREG(SISSR, 0x19, 0x06);
5673 outSISIDXREG(SISSR, 0x16, 0x04);
5674 outSISIDXREG(SISSR, 0x16, 0x84);
5675 sisfb_post_xgi_delay(ivideo, 1);
5676 break;
5677 default:
5678 sisfb_post_xgi_setclocks(ivideo, regb);
5679 if((ivideo->chip == XGI_40) &&
5680 ((ivideo->revision_id == 1) ||
5681 (ivideo->revision_id == 2))) {
5682 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5683 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5684 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5685 } else {
5686 outSISIDXREG(SISCR, 0x82, 0x88);
5687 outSISIDXREG(SISCR, 0x86, 0x00);
5688 inSISIDXREG(SISCR, 0x86, reg);
5689 outSISIDXREG(SISCR, 0x86, 0x88);
5690 outSISIDXREG(SISCR, 0x82, 0x77);
5691 outSISIDXREG(SISCR, 0x85, 0x00);
5692 inSISIDXREG(SISCR, 0x85, reg);
5693 outSISIDXREG(SISCR, 0x85, 0x88);
5694 inSISIDXREG(SISCR, 0x85, reg);
5695 v1 = cs160[regb]; v2 = cs158[regb];
5696 if(ivideo->haveXGIROM) {
5697 v1 = bios[regb + 0x160];
5698 v2 = bios[regb + 0x158];
5700 outSISIDXREG(SISCR, 0x85, v1);
5701 outSISIDXREG(SISCR, 0x82, v2);
5703 if(ivideo->chip == XGI_40) {
5704 outSISIDXREG(SISCR, 0x97, 0x11);
5706 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5707 outSISIDXREG(SISCR, 0x98, 0x01);
5708 } else {
5709 outSISIDXREG(SISCR, 0x98, 0x03);
5711 outSISIDXREG(SISCR, 0x9a, 0x02);
5713 if(ivideo->chip == XGI_40) {
5714 outSISIDXREG(SISSR, 0x18, 0x01);
5715 } else {
5716 outSISIDXREG(SISSR, 0x18, 0x00);
5718 outSISIDXREG(SISSR, 0x19, 0x40);
5719 outSISIDXREG(SISSR, 0x16, 0x00);
5720 outSISIDXREG(SISSR, 0x16, 0x80);
5721 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5722 sisfb_post_xgi_delay(ivideo, 0x43);
5723 sisfb_post_xgi_delay(ivideo, 0x43);
5724 sisfb_post_xgi_delay(ivideo, 0x43);
5725 outSISIDXREG(SISSR, 0x18, 0x00);
5726 outSISIDXREG(SISSR, 0x19, 0x40);
5727 outSISIDXREG(SISSR, 0x16, 0x00);
5728 outSISIDXREG(SISSR, 0x16, 0x80);
5730 sisfb_post_xgi_delay(ivideo, 4);
5731 v1 = 0x31;
5732 if(ivideo->haveXGIROM) {
5733 v1 = bios[0xf0];
5735 outSISIDXREG(SISSR, 0x18, v1);
5736 outSISIDXREG(SISSR, 0x19, 0x01);
5737 if(ivideo->chip == XGI_40) {
5738 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5739 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5740 } else {
5741 outSISIDXREG(SISSR, 0x16, 0x05);
5742 outSISIDXREG(SISSR, 0x16, 0x85);
5744 sisfb_post_xgi_delay(ivideo, 0x43);
5745 if(ivideo->chip == XGI_40) {
5746 outSISIDXREG(SISSR, 0x1b, 0x01);
5747 } else {
5748 outSISIDXREG(SISSR, 0x1b, 0x03);
5750 sisfb_post_xgi_delay(ivideo, 0x22);
5751 outSISIDXREG(SISSR, 0x18, v1);
5752 outSISIDXREG(SISSR, 0x19, 0x00);
5753 if(ivideo->chip == XGI_40) {
5754 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5755 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5756 } else {
5757 outSISIDXREG(SISSR, 0x16, 0x05);
5758 outSISIDXREG(SISSR, 0x16, 0x85);
5760 outSISIDXREG(SISSR, 0x1b, 0x00);
5763 regb = 0; /* ! */
5764 v1 = 0x03;
5765 if(ivideo->haveXGIROM) {
5766 v1 = bios[0x110 + regb];
5768 outSISIDXREG(SISSR, 0x1b, v1);
5770 /* RAM size */
5771 v1 = 0x00; v2 = 0x00;
5772 if(ivideo->haveXGIROM) {
5773 v1 = bios[0x62];
5774 v2 = bios[0x63];
5776 regb = 0; /* ! */
5777 regd = 1 << regb;
5778 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5780 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5781 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5783 } else {
5785 /* Set default mode, don't clear screen */
5786 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5787 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5788 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5789 ivideo->curFSTN = ivideo->curDSTN = 0;
5790 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5791 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5793 outSISIDXREG(SISSR, 0x05, 0x86);
5795 /* Disable read-cache */
5796 andSISIDXREG(SISSR, 0x21, 0xdf);
5797 sisfb_post_xgi_ramsize(ivideo);
5798 /* Enable read-cache */
5799 orSISIDXREG(SISSR, 0x21, 0x20);
5803 #if 0
5804 printk(KERN_DEBUG "-----------------\n");
5805 for(i = 0; i < 0xff; i++) {
5806 inSISIDXREG(SISCR, i, reg);
5807 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5809 for(i = 0; i < 0x40; i++) {
5810 inSISIDXREG(SISSR, i, reg);
5811 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5813 printk(KERN_DEBUG "-----------------\n");
5814 #endif
5816 /* Sense CRT1 */
5817 if(ivideo->chip == XGI_20) {
5818 orSISIDXREG(SISCR, 0x32, 0x20);
5819 } else {
5820 inSISIDXREG(SISPART4, 0x00, reg);
5821 if((reg == 1) || (reg == 2)) {
5822 sisfb_sense_crt1(ivideo);
5823 } else {
5824 orSISIDXREG(SISCR, 0x32, 0x20);
5828 /* Set default mode, don't clear screen */
5829 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5830 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5831 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5832 ivideo->curFSTN = ivideo->curDSTN = 0;
5833 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5835 outSISIDXREG(SISSR, 0x05, 0x86);
5837 /* Display off */
5838 orSISIDXREG(SISSR, 0x01, 0x20);
5840 /* Save mode number in CR34 */
5841 outSISIDXREG(SISCR, 0x34, 0x2e);
5843 /* Let everyone know what the current mode is */
5844 ivideo->modeprechange = 0x2e;
5846 if(ivideo->chip == XGI_40) {
5847 inSISIDXREG(SISCR, 0xca, reg);
5848 inSISIDXREG(SISCR, 0xcc, v1);
5849 if((reg & 0x10) && (!(v1 & 0x04))) {
5850 printk(KERN_ERR
5851 "sisfb: Please connect power to the card.\n");
5852 return 0;
5856 return 1;
5858 #endif
5860 static int __devinit
5861 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5863 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5864 struct sis_video_info *ivideo = NULL;
5865 struct fb_info *sis_fb_info = NULL;
5866 u16 reg16;
5867 u8 reg;
5868 int i, ret;
5870 if(sisfb_off)
5871 return -ENXIO;
5873 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5874 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5875 if(!sis_fb_info)
5876 return -ENOMEM;
5877 #else
5878 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
5879 if(!sis_fb_info)
5880 return -ENOMEM;
5881 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5882 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5883 #endif
5885 ivideo = (struct sis_video_info *)sis_fb_info->par;
5886 ivideo->memyselfandi = sis_fb_info;
5888 ivideo->sisfb_id = SISFB_ID;
5890 if(card_list == NULL) {
5891 ivideo->cardnumber = 0;
5892 } else {
5893 struct sis_video_info *countvideo = card_list;
5894 ivideo->cardnumber = 1;
5895 while((countvideo = countvideo->next) != 0)
5896 ivideo->cardnumber++;
5899 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5901 ivideo->warncount = 0;
5902 ivideo->chip_id = pdev->device;
5903 ivideo->chip_vendor = pdev->vendor;
5904 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
5905 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5906 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
5907 ivideo->sisvga_enabled = reg16 & 0x01;
5908 ivideo->pcibus = pdev->bus->number;
5909 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5910 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5911 ivideo->subsysvendor = pdev->subsystem_vendor;
5912 ivideo->subsysdevice = pdev->subsystem_device;
5913 #ifdef SIS_OLD_CONFIG_COMPAT
5914 ivideo->ioctl32registered = 0;
5915 #endif
5917 #ifndef MODULE
5918 if(sisfb_mode_idx == -1) {
5919 sisfb_get_vga_mode_from_kernel();
5921 #endif
5923 ivideo->chip = chipinfo->chip;
5924 ivideo->sisvga_engine = chipinfo->vgaengine;
5925 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5926 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5927 ivideo->mni = chipinfo->mni;
5929 ivideo->detectedpdc = 0xff;
5930 ivideo->detectedpdca = 0xff;
5931 ivideo->detectedlcda = 0xff;
5933 ivideo->sisfb_thismonitor.datavalid = FALSE;
5935 ivideo->current_base = 0;
5937 ivideo->engineok = 0;
5939 ivideo->sisfb_was_boot_device = 0;
5940 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5941 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5942 if(ivideo->sisvga_enabled)
5943 ivideo->sisfb_was_boot_device = 1;
5944 else {
5945 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5946 "but marked as boot video device ???\n");
5947 printk(KERN_DEBUG "sisfb: I will not accept this "
5948 "as the primary VGA device\n");
5951 #endif
5953 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5954 ivideo->sisfb_accel = sisfb_accel;
5955 ivideo->sisfb_ypan = sisfb_ypan;
5956 ivideo->sisfb_max = sisfb_max;
5957 ivideo->sisfb_userom = sisfb_userom;
5958 ivideo->sisfb_useoem = sisfb_useoem;
5959 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5960 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5961 ivideo->sisfb_crt1off = sisfb_crt1off;
5962 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5963 ivideo->sisfb_crt2type = sisfb_crt2type;
5964 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5965 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5966 ivideo->sisfb_dstn = sisfb_dstn;
5967 ivideo->sisfb_fstn = sisfb_fstn;
5968 ivideo->sisfb_tvplug = sisfb_tvplug;
5969 ivideo->sisfb_tvstd = sisfb_tvstd;
5970 ivideo->tvxpos = sisfb_tvxposoffset;
5971 ivideo->tvypos = sisfb_tvyposoffset;
5972 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5973 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5974 ivideo->sisfb_inverse = sisfb_inverse;
5975 #endif
5977 ivideo->refresh_rate = 0;
5978 if(ivideo->sisfb_parm_rate != -1) {
5979 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5982 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5983 ivideo->SiS_Pr.CenterScreen = -1;
5984 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5985 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5987 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5988 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5989 ivideo->SiS_Pr.SiS_ChSW = FALSE;
5990 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5991 ivideo->SiS_Pr.HaveEMI = FALSE;
5992 ivideo->SiS_Pr.HaveEMILCD = FALSE;
5993 ivideo->SiS_Pr.OverruleEMI = FALSE;
5994 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
5995 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5996 ivideo->SiS_Pr.PDC = -1;
5997 ivideo->SiS_Pr.PDCA = -1;
5998 ivideo->SiS_Pr.DDCPortMixup = FALSE;
5999 #ifdef CONFIG_FB_SIS_315
6000 if(ivideo->chip >= SIS_330) {
6001 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
6002 if(ivideo->chip >= SIS_661) {
6003 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
6006 #endif
6008 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6010 pci_set_drvdata(pdev, ivideo);
6012 /* Patch special cases */
6013 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6014 switch(ivideo->nbridge->device) {
6015 #ifdef CONFIG_FB_SIS_300
6016 case PCI_DEVICE_ID_SI_730:
6017 ivideo->chip = SIS_730;
6018 strcpy(ivideo->myid, "SiS 730");
6019 break;
6020 #endif
6021 #ifdef CONFIG_FB_SIS_315
6022 case PCI_DEVICE_ID_SI_651:
6023 /* ivideo->chip is ok */
6024 strcpy(ivideo->myid, "SiS 651");
6025 break;
6026 case PCI_DEVICE_ID_SI_740:
6027 ivideo->chip = SIS_740;
6028 strcpy(ivideo->myid, "SiS 740");
6029 break;
6030 case PCI_DEVICE_ID_SI_661:
6031 ivideo->chip = SIS_661;
6032 strcpy(ivideo->myid, "SiS 661");
6033 break;
6034 case PCI_DEVICE_ID_SI_741:
6035 ivideo->chip = SIS_741;
6036 strcpy(ivideo->myid, "SiS 741");
6037 break;
6038 case PCI_DEVICE_ID_SI_760:
6039 ivideo->chip = SIS_760;
6040 strcpy(ivideo->myid, "SiS 760");
6041 break;
6042 case PCI_DEVICE_ID_SI_761:
6043 ivideo->chip = SIS_761;
6044 strcpy(ivideo->myid, "SiS 761");
6045 break;
6046 #endif
6047 default:
6048 break;
6052 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6053 strcpy(sis_fb_info->modename, ivideo->myid);
6054 #endif
6056 ivideo->SiS_Pr.ChipType = ivideo->chip;
6058 ivideo->SiS_Pr.ivideo = (void *)ivideo;
6060 #ifdef CONFIG_FB_SIS_315
6061 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6062 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6063 ivideo->SiS_Pr.ChipType = SIS_315H;
6065 #endif
6067 if(!ivideo->sisvga_enabled) {
6068 if(pci_enable_device(pdev)) {
6069 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6070 pci_set_drvdata(pdev, NULL);
6071 kfree(sis_fb_info);
6072 return -EIO;
6076 ivideo->video_base = pci_resource_start(pdev, 0);
6077 ivideo->mmio_base = pci_resource_start(pdev, 1);
6078 ivideo->mmio_size = pci_resource_len(pdev, 1);
6079 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
6080 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
6082 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
6084 #ifdef CONFIG_FB_SIS_300
6085 /* Find PCI systems for Chrontel/GPIO communication setup */
6086 if(ivideo->chip == SIS_630) {
6087 i = 0;
6088 do {
6089 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6090 mychswtable[i].subsysCard == ivideo->subsysdevice) {
6091 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6092 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6093 "requiring Chrontel/GPIO setup\n",
6094 mychswtable[i].vendorName,
6095 mychswtable[i].cardName);
6096 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6097 break;
6099 i++;
6100 } while(mychswtable[i].subsysVendor != 0);
6102 #endif
6104 #ifdef CONFIG_FB_SIS_315
6105 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6106 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
6108 #endif
6110 outSISIDXREG(SISSR, 0x05, 0x86);
6112 if( (!ivideo->sisvga_enabled)
6113 #if !defined(__i386__) && !defined(__x86_64__)
6114 || (sisfb_resetcard)
6115 #endif
6117 for(i = 0x30; i <= 0x3f; i++) {
6118 outSISIDXREG(SISCR, i, 0x00);
6122 /* Find out about current video mode */
6123 ivideo->modeprechange = 0x03;
6124 inSISIDXREG(SISCR, 0x34, reg);
6125 if(reg & 0x7f) {
6126 ivideo->modeprechange = reg & 0x7f;
6127 } else if(ivideo->sisvga_enabled) {
6128 #if defined(__i386__) || defined(__x86_64__)
6129 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
6130 if(tt) {
6131 ivideo->modeprechange = readb(tt + 0x49);
6132 iounmap(tt);
6134 #endif
6137 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6138 #ifdef MODULE
6139 if((reg & 0x80) && (reg != 0xff)) {
6140 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6141 != 0xFF) {
6142 printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6143 "X server is active\n");
6144 ret = -EBUSY;
6145 goto error_4;
6148 #endif
6149 #endif
6151 /* Search and copy ROM image */
6152 ivideo->bios_abase = NULL;
6153 ivideo->SiS_Pr.VirtualRomBase = NULL;
6154 ivideo->SiS_Pr.UseROM = FALSE;
6155 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
6156 if(ivideo->sisfb_userom) {
6157 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6158 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6159 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6160 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6161 ivideo->SiS_Pr.UseROM ? "" : "not ");
6162 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6163 ivideo->SiS_Pr.UseROM = FALSE;
6164 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6165 if( (ivideo->revision_id == 2) &&
6166 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6167 ivideo->SiS_Pr.DDCPortMixup = TRUE;
6170 } else {
6171 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6174 /* Find systems for special custom timing */
6175 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6176 sisfb_detect_custom_timing(ivideo);
6179 /* POST card in case this has not been done by the BIOS */
6180 if( (!ivideo->sisvga_enabled)
6181 #if !defined(__i386__) && !defined(__x86_64__)
6182 || (sisfb_resetcard)
6183 #endif
6185 #ifdef CONFIG_FB_SIS_300
6186 if(ivideo->sisvga_engine == SIS_300_VGA) {
6187 if(ivideo->chip == SIS_300) {
6188 sisfb_post_sis300(pdev);
6189 ivideo->sisfb_can_post = 1;
6192 #endif
6194 #ifdef CONFIG_FB_SIS_315
6195 if(ivideo->sisvga_engine == SIS_315_VGA) {
6196 int result = 1;
6197 /* if((ivideo->chip == SIS_315H) ||
6198 (ivideo->chip == SIS_315) ||
6199 (ivideo->chip == SIS_315PRO) ||
6200 (ivideo->chip == SIS_330)) {
6201 sisfb_post_sis315330(pdev);
6202 } else */ if(ivideo->chip == XGI_20) {
6203 result = sisfb_post_xgi(pdev);
6204 ivideo->sisfb_can_post = 1;
6205 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6206 result = sisfb_post_xgi(pdev);
6207 ivideo->sisfb_can_post = 1;
6208 } else {
6209 printk(KERN_INFO "sisfb: Card is not "
6210 "POSTed and sisfb can't do this either.\n");
6212 if(!result) {
6213 printk(KERN_ERR "sisfb: Failed to POST card\n");
6214 ret = -ENODEV;
6215 goto error_3;
6218 #endif
6221 ivideo->sisfb_card_posted = 1;
6223 /* Find out about RAM size */
6224 if(sisfb_get_dram_size(ivideo)) {
6225 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6226 ret = -ENODEV;
6227 goto error_3;
6231 /* Enable PCI addressing and MMIO */
6232 if((ivideo->sisfb_mode_idx < 0) ||
6233 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6234 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6235 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6236 /* Enable 2D accelerator engine */
6237 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6240 if(sisfb_pdc != 0xff) {
6241 if(ivideo->sisvga_engine == SIS_300_VGA)
6242 sisfb_pdc &= 0x3c;
6243 else
6244 sisfb_pdc &= 0x1f;
6245 ivideo->SiS_Pr.PDC = sisfb_pdc;
6247 #ifdef CONFIG_FB_SIS_315
6248 if(ivideo->sisvga_engine == SIS_315_VGA) {
6249 if(sisfb_pdca != 0xff)
6250 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6252 #endif
6254 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6255 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6256 (int)(ivideo->video_size >> 20));
6257 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6258 ret = -ENODEV;
6259 goto error_3;
6262 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6263 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6264 ret = -ENODEV;
6265 goto error_2;
6268 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6269 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6270 if(!ivideo->video_vbase) {
6271 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6272 ret = -ENODEV;
6273 goto error_1;
6276 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6277 if(!ivideo->mmio_vbase) {
6278 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6279 ret = -ENODEV;
6280 error_0: iounmap(ivideo->video_vbase);
6281 error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6282 error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6283 error_3: vfree(ivideo->bios_abase);
6284 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6285 error_4:
6286 #endif
6287 if(ivideo->lpcdev)
6288 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6289 if(ivideo->nbridge)
6290 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6291 pci_set_drvdata(pdev, NULL);
6292 if(!ivideo->sisvga_enabled)
6293 pci_disable_device(pdev);
6294 kfree(sis_fb_info);
6295 return ret;
6298 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6299 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6301 if(ivideo->video_offset) {
6302 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6303 ivideo->video_offset / 1024);
6306 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6307 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6310 /* Determine the size of the command queue */
6311 if(ivideo->sisvga_engine == SIS_300_VGA) {
6312 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6313 } else {
6314 if(ivideo->chip == XGI_20) {
6315 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6316 } else {
6317 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6321 /* Engines are no longer initialized here; this is
6322 * now done after the first mode-switch (if the
6323 * submitted var has its acceleration flags set).
6326 /* Calculate the base of the (unused) hw cursor */
6327 ivideo->hwcursor_vbase = ivideo->video_vbase
6328 + ivideo->video_size
6329 - ivideo->cmdQueueSize
6330 - ivideo->hwcursor_size;
6331 ivideo->caps |= HW_CURSOR_CAP;
6333 /* Initialize offscreen memory manager */
6334 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6335 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6338 /* Used for clearing the screen only, therefore respect our mem limit */
6339 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6340 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6342 ivideo->mtrr = -1;
6344 ivideo->vbflags = 0;
6345 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6346 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6347 ivideo->defmodeidx = DEFAULT_MODE;
6349 ivideo->newrom = 0;
6350 if(ivideo->chip < XGI_20) {
6351 if(ivideo->bios_abase) {
6352 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6356 if((ivideo->sisfb_mode_idx < 0) ||
6357 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6359 sisfb_sense_crt1(ivideo);
6361 sisfb_get_VB_type(ivideo);
6363 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6364 sisfb_detect_VB_connect(ivideo);
6367 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6369 /* Decide on which CRT2 device to use */
6370 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6371 if(ivideo->sisfb_crt2type != -1) {
6372 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6373 (ivideo->vbflags & CRT2_LCD)) {
6374 ivideo->currentvbflags |= CRT2_LCD;
6375 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6376 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6378 } else {
6379 /* Chrontel 700x TV detection often unreliable, therefore
6380 * use a different default order on such machines
6382 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6383 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6384 if(ivideo->vbflags & CRT2_LCD)
6385 ivideo->currentvbflags |= CRT2_LCD;
6386 else if(ivideo->vbflags & CRT2_TV)
6387 ivideo->currentvbflags |= CRT2_TV;
6388 else if(ivideo->vbflags & CRT2_VGA)
6389 ivideo->currentvbflags |= CRT2_VGA;
6390 } else {
6391 if(ivideo->vbflags & CRT2_TV)
6392 ivideo->currentvbflags |= CRT2_TV;
6393 else if(ivideo->vbflags & CRT2_LCD)
6394 ivideo->currentvbflags |= CRT2_LCD;
6395 else if(ivideo->vbflags & CRT2_VGA)
6396 ivideo->currentvbflags |= CRT2_VGA;
6401 if(ivideo->vbflags & CRT2_LCD) {
6402 sisfb_detect_lcd_type(ivideo);
6405 sisfb_save_pdc_emi(ivideo);
6407 if(!ivideo->sisfb_crt1off) {
6408 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6409 } else {
6410 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6411 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6412 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6416 if(ivideo->sisfb_mode_idx >= 0) {
6417 int bu = ivideo->sisfb_mode_idx;
6418 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6419 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6420 if(bu != ivideo->sisfb_mode_idx) {
6421 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6422 sisbios_mode[bu].xres,
6423 sisbios_mode[bu].yres,
6424 sisbios_mode[bu].bpp);
6428 if(ivideo->sisfb_mode_idx < 0) {
6429 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6430 case CRT2_LCD:
6431 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6432 break;
6433 case CRT2_TV:
6434 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6435 break;
6436 default:
6437 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6438 break;
6442 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6444 if(ivideo->refresh_rate != 0) {
6445 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6446 ivideo->sisfb_mode_idx);
6449 if(ivideo->rate_idx == 0) {
6450 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6451 ivideo->refresh_rate = 60;
6454 if(ivideo->sisfb_thismonitor.datavalid) {
6455 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6456 ivideo->sisfb_mode_idx,
6457 ivideo->rate_idx,
6458 ivideo->refresh_rate)) {
6459 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6460 "exceeds monitor specs!\n");
6464 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6465 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6466 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6468 sisfb_set_vparms(ivideo);
6470 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6472 /* ---------------- For 2.4: Now switch the mode ------------------ */
6474 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6475 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6476 ivideo->refresh_rate);
6478 /* Determine whether or not acceleration is to be
6479 * used. Need to know before pre/post_set_mode()
6481 ivideo->accel = 0;
6482 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6483 if(ivideo->sisfb_accel) {
6484 ivideo->accel = -1;
6485 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6488 /* Now switch the mode */
6489 sisfb_pre_setmode(ivideo);
6491 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
6492 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6493 ivideo->mode_no);
6494 ret = -EINVAL;
6495 iounmap(ivideo->mmio_vbase);
6496 goto error_0;
6499 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6501 sisfb_post_setmode(ivideo);
6503 /* Maximize regardless of sisfb_max at startup */
6504 ivideo->default_var.yres_virtual = 32767;
6506 /* Force reset of x virtual in crtc_to_var */
6507 ivideo->default_var.xres_virtual = 0;
6509 /* Copy mode timing to var */
6510 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6512 /* Find out about screen pitch */
6513 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6514 sisfb_set_pitch(ivideo);
6516 /* Init the accelerator (does nothing currently) */
6517 sisfb_initaccel(ivideo);
6519 /* Init some fbinfo entries */
6520 sis_fb_info->node = -1;
6521 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6522 sis_fb_info->fbops = &sisfb_ops;
6523 sis_fb_info->disp = &ivideo->sis_disp;
6524 sis_fb_info->blank = &sisfb_blank;
6525 sis_fb_info->switch_con = &sisfb_switch;
6526 sis_fb_info->updatevar = &sisfb_update_var;
6527 sis_fb_info->changevar = NULL;
6528 strcpy(sis_fb_info->fontname, sisfb_fontname);
6530 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6532 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6534 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6535 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6536 ivideo->refresh_rate);
6538 /* Set up the default var according to chosen default display mode */
6539 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6540 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6541 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6543 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6545 ivideo->default_var.pixclock = (u32) (1000000000 /
6546 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6548 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6549 ivideo->rate_idx, &ivideo->default_var)) {
6550 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6551 ivideo->default_var.pixclock <<= 1;
6555 if(ivideo->sisfb_ypan) {
6556 /* Maximize regardless of sisfb_max at startup */
6557 ivideo->default_var.yres_virtual =
6558 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6559 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6560 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6564 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6566 ivideo->accel = 0;
6567 if(ivideo->sisfb_accel) {
6568 ivideo->accel = -1;
6569 #ifdef STUPID_ACCELF_TEXT_SHIT
6570 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6571 #endif
6573 sisfb_initaccel(ivideo);
6575 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6576 sis_fb_info->flags = FBINFO_DEFAULT |
6577 FBINFO_HWACCEL_YPAN |
6578 FBINFO_HWACCEL_XPAN |
6579 FBINFO_HWACCEL_COPYAREA |
6580 FBINFO_HWACCEL_FILLRECT |
6581 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6582 #else
6583 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6584 #endif
6585 sis_fb_info->var = ivideo->default_var;
6586 sis_fb_info->fix = ivideo->sisfb_fix;
6587 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6588 sis_fb_info->fbops = &sisfb_ops;
6590 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6591 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6593 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6594 #endif /* 2.6 */
6596 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6598 #ifdef CONFIG_MTRR
6599 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6600 MTRR_TYPE_WRCOMB, 1);
6601 if(ivideo->mtrr < 0) {
6602 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6604 #endif
6606 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6607 vc_resize_con(1, 1, 0);
6608 #endif
6610 if(register_framebuffer(sis_fb_info) < 0) {
6611 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6612 ret = -EINVAL;
6613 iounmap(ivideo->mmio_vbase);
6614 goto error_0;
6617 ivideo->registered = 1;
6619 /* Enlist us */
6620 ivideo->next = card_list;
6621 card_list = ivideo;
6623 #ifdef SIS_OLD_CONFIG_COMPAT
6625 int ret;
6626 /* Our ioctls are all "32/64bit compatible" */
6627 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6628 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6629 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6630 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6631 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6632 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6633 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6634 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6635 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6636 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6637 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6638 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6639 if(ret)
6640 printk(KERN_ERR
6641 "sisfb: Error registering ioctl32 translations\n");
6642 else
6643 ivideo->ioctl32registered = 1;
6645 #endif
6647 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6648 ivideo->sisfb_accel ? "enabled" : "disabled",
6649 ivideo->sisfb_ypan ?
6650 (ivideo->sisfb_max ? "enabled (auto-max)" :
6651 "enabled (no auto-max)") :
6652 "disabled");
6655 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6656 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6657 GET_FB_IDX(sis_fb_info->node),
6658 #else
6659 sis_fb_info->node,
6660 #endif
6661 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6663 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6665 } /* if mode = "none" */
6667 return 0;
6670 /*****************************************************/
6671 /* PCI DEVICE HANDLING */
6672 /*****************************************************/
6674 static void __devexit sisfb_remove(struct pci_dev *pdev)
6676 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6677 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6678 int registered = ivideo->registered;
6679 int modechanged = ivideo->modechanged;
6681 #ifdef SIS_OLD_CONFIG_COMPAT
6682 if(ivideo->ioctl32registered) {
6683 int ret;
6684 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6685 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6686 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6687 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6688 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6689 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6690 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6691 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6692 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6693 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6694 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6695 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6696 if(ret)
6697 printk(KERN_ERR
6698 "sisfb: Error unregistering ioctl32 translations\n");
6700 #endif
6702 /* Unmap */
6703 iounmap(ivideo->mmio_vbase);
6704 iounmap(ivideo->video_vbase);
6706 /* Release mem regions */
6707 release_mem_region(ivideo->video_base, ivideo->video_size);
6708 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6710 vfree(ivideo->bios_abase);
6712 if(ivideo->lpcdev)
6713 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6715 if(ivideo->nbridge)
6716 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6718 #ifdef CONFIG_MTRR
6719 /* Release MTRR region */
6720 if(ivideo->mtrr >= 0)
6721 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6722 #endif
6724 pci_set_drvdata(pdev, NULL);
6726 /* If device was disabled when starting, disable
6727 * it when quitting.
6729 if(!ivideo->sisvga_enabled)
6730 pci_disable_device(pdev);
6732 /* Unregister the framebuffer */
6733 if(ivideo->registered) {
6734 unregister_framebuffer(sis_fb_info);
6735 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6736 framebuffer_release(sis_fb_info);
6737 #else
6738 kfree(sis_fb_info);
6739 #endif
6742 /* OK, our ivideo is gone for good from here. */
6744 /* TODO: Restore the initial mode
6745 * This sounds easy but is as good as impossible
6746 * on many machines with SiS chip and video bridge
6747 * since text modes are always set up differently
6748 * from machine to machine. Depends on the type
6749 * of integration between chipset and bridge.
6751 if(registered && modechanged)
6752 printk(KERN_INFO
6753 "sisfb: Restoring of text mode not supported yet\n");
6756 static struct pci_driver sisfb_driver = {
6757 .name = "sisfb",
6758 .id_table = sisfb_pci_table,
6759 .probe = sisfb_probe,
6760 .remove = __devexit_p(sisfb_remove)
6763 SISINITSTATIC int __init sisfb_init(void)
6765 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6766 #ifndef MODULE
6767 char *options = NULL;
6769 if(fb_get_options("sisfb", &options))
6770 return -ENODEV;
6772 sisfb_setup(options);
6773 #endif
6774 #endif
6775 return pci_register_driver(&sisfb_driver);
6778 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6779 #ifndef MODULE
6780 module_init(sisfb_init);
6781 #endif
6782 #endif
6784 /*****************************************************/
6785 /* MODULE */
6786 /*****************************************************/
6788 #ifdef MODULE
6790 static char *mode = NULL;
6791 static int vesa = -1;
6792 static unsigned int rate = 0;
6793 static unsigned int crt1off = 1;
6794 static unsigned int mem = 0;
6795 static char *forcecrt2type = NULL;
6796 static int forcecrt1 = -1;
6797 static int pdc = -1;
6798 static int pdc1 = -1;
6799 static int noaccel = -1;
6800 static int noypan = -1;
6801 static int nomax = -1;
6802 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6803 static int inverse = 0;
6804 #endif
6805 static int userom = -1;
6806 static int useoem = -1;
6807 static char *tvstandard = NULL;
6808 static int nocrt2rate = 0;
6809 static int scalelcd = -1;
6810 static char *specialtiming = NULL;
6811 static int lvdshl = -1;
6812 static int tvxposoffset = 0, tvyposoffset = 0;
6813 #if !defined(__i386__) && !defined(__x86_64__)
6814 static int resetcard = 0;
6815 static int videoram = 0;
6816 #endif
6818 static int __init sisfb_init_module(void)
6820 sisfb_setdefaultparms();
6822 if(rate)
6823 sisfb_parm_rate = rate;
6825 if((scalelcd == 0) || (scalelcd == 1))
6826 sisfb_scalelcd = scalelcd ^ 1;
6828 /* Need to check crt2 type first for fstn/dstn */
6830 if(forcecrt2type)
6831 sisfb_search_crt2type(forcecrt2type);
6833 if(tvstandard)
6834 sisfb_search_tvstd(tvstandard);
6836 if(mode)
6837 sisfb_search_mode(mode, FALSE);
6838 else if(vesa != -1)
6839 sisfb_search_vesamode(vesa, FALSE);
6841 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6843 sisfb_forcecrt1 = forcecrt1;
6844 if(forcecrt1 == 1)
6845 sisfb_crt1off = 0;
6846 else if(forcecrt1 == 0)
6847 sisfb_crt1off = 1;
6849 if(noaccel == 1)
6850 sisfb_accel = 0;
6851 else if(noaccel == 0)
6852 sisfb_accel = 1;
6854 if(noypan == 1)
6855 sisfb_ypan = 0;
6856 else if(noypan == 0)
6857 sisfb_ypan = 1;
6859 if(nomax == 1)
6860 sisfb_max = 0;
6861 else if(nomax == 0)
6862 sisfb_max = 1;
6864 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6865 if(inverse) sisfb_inverse = 1;
6866 #endif
6868 if(mem)
6869 sisfb_parm_mem = mem;
6871 if(userom != -1)
6872 sisfb_userom = userom;
6874 if(useoem != -1)
6875 sisfb_useoem = useoem;
6877 if(pdc != -1)
6878 sisfb_pdc = (pdc & 0x7f);
6880 if(pdc1 != -1)
6881 sisfb_pdca = (pdc1 & 0x1f);
6883 sisfb_nocrt2rate = nocrt2rate;
6885 if(specialtiming)
6886 sisfb_search_specialtiming(specialtiming);
6888 if((lvdshl >= 0) && (lvdshl <= 3))
6889 sisfb_lvdshl = lvdshl;
6891 sisfb_tvxposoffset = tvxposoffset;
6892 sisfb_tvyposoffset = tvyposoffset;
6894 #if !defined(__i386__) && !defined(__x86_64__)
6895 sisfb_resetcard = (resetcard) ? 1 : 0;
6896 if(videoram)
6897 sisfb_videoram = videoram;
6898 #endif
6900 return sisfb_init();
6903 static void __exit sisfb_remove_module(void)
6905 pci_unregister_driver(&sisfb_driver);
6906 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6909 module_init(sisfb_init_module);
6910 module_exit(sisfb_remove_module);
6912 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6913 MODULE_LICENSE("GPL");
6914 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6916 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6917 MODULE_PARM(mem, "i");
6918 MODULE_PARM(noaccel, "i");
6919 MODULE_PARM(noypan, "i");
6920 MODULE_PARM(nomax, "i");
6921 MODULE_PARM(userom, "i");
6922 MODULE_PARM(useoem, "i");
6923 MODULE_PARM(mode, "s");
6924 MODULE_PARM(vesa, "i");
6925 MODULE_PARM(rate, "i");
6926 MODULE_PARM(forcecrt1, "i");
6927 MODULE_PARM(forcecrt2type, "s");
6928 MODULE_PARM(scalelcd, "i");
6929 MODULE_PARM(pdc, "i");
6930 MODULE_PARM(pdc1, "i");
6931 MODULE_PARM(specialtiming, "s");
6932 MODULE_PARM(lvdshl, "i");
6933 MODULE_PARM(tvstandard, "s");
6934 MODULE_PARM(tvxposoffset, "i");
6935 MODULE_PARM(tvyposoffset, "i");
6936 MODULE_PARM(nocrt2rate, "i");
6937 MODULE_PARM(inverse, "i");
6938 #if !defined(__i386__) && !defined(__x86_64__)
6939 MODULE_PARM(resetcard, "i");
6940 MODULE_PARM(videoram, "i");
6941 #endif
6942 #endif
6944 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6945 module_param(mem, int, 0);
6946 module_param(noaccel, int, 0);
6947 module_param(noypan, int, 0);
6948 module_param(nomax, int, 0);
6949 module_param(userom, int, 0);
6950 module_param(useoem, int, 0);
6951 module_param(mode, charp, 0);
6952 module_param(vesa, int, 0);
6953 module_param(rate, int, 0);
6954 module_param(forcecrt1, int, 0);
6955 module_param(forcecrt2type, charp, 0);
6956 module_param(scalelcd, int, 0);
6957 module_param(pdc, int, 0);
6958 module_param(pdc1, int, 0);
6959 module_param(specialtiming, charp, 0);
6960 module_param(lvdshl, int, 0);
6961 module_param(tvstandard, charp, 0);
6962 module_param(tvxposoffset, int, 0);
6963 module_param(tvyposoffset, int, 0);
6964 module_param(nocrt2rate, int, 0);
6965 #if !defined(__i386__) && !defined(__x86_64__)
6966 module_param(resetcard, int, 0);
6967 module_param(videoram, int, 0);
6968 #endif
6969 #endif
6971 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6972 MODULE_PARM_DESC(mem,
6973 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6974 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6975 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6976 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6977 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6978 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6979 "for XFree86 4.x/X.org 6.7 and later.\n");
6980 #else
6981 MODULE_PARM_DESC(mem,
6982 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6983 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6984 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6985 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6986 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6987 "The value is to be specified without 'KB'.\n");
6988 #endif
6990 MODULE_PARM_DESC(noaccel,
6991 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6992 "(default: 0)\n");
6994 MODULE_PARM_DESC(noypan,
6995 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6996 "will be performed by redrawing the screen. (default: 0)\n");
6998 MODULE_PARM_DESC(nomax,
6999 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
7000 "memory for the virtual screen in order to optimize scrolling performance. If\n"
7001 "this is set to anything other than 0, sisfb will not do this and thereby \n"
7002 "enable the user to positively specify a virtual Y size of the screen using\n"
7003 "fbset. (default: 0)\n");
7005 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7006 MODULE_PARM_DESC(mode,
7007 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7008 "1024x768x16. Other formats supported include XxY-Depth and\n"
7009 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7010 "number, it will be interpreted as a VESA mode number. (default: none if\n"
7011 "sisfb is a module; this leaves the console untouched and the driver will\n"
7012 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7013 "is in the kernel)\n");
7014 MODULE_PARM_DESC(vesa,
7015 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7016 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
7017 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7018 "0x0103 if sisfb is in the kernel)\n");
7019 #endif
7021 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7022 MODULE_PARM_DESC(mode,
7023 "\nSelects the desired default display mode in the format XxYxDepth,\n"
7024 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
7025 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7026 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7028 MODULE_PARM_DESC(vesa,
7029 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7030 "0x117 (default: 0x0103)\n");
7031 #endif
7033 MODULE_PARM_DESC(rate,
7034 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7035 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7036 "will be ignored (default: 60)\n");
7038 MODULE_PARM_DESC(forcecrt1,
7039 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7040 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7041 "0=CRT1 OFF) (default: [autodetected])\n");
7043 MODULE_PARM_DESC(forcecrt2type,
7044 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7045 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7046 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7047 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7048 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7049 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7050 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7051 "depends on the very hardware in use. (default: [autodetected])\n");
7053 MODULE_PARM_DESC(scalelcd,
7054 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7055 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7056 "show black bars around the image, TMDS panels will probably do the scaling\n"
7057 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7059 MODULE_PARM_DESC(pdc,
7060 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
7061 "should detect this correctly in most cases; however, sometimes this is not\n"
7062 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
7063 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7064 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7065 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
7067 #ifdef CONFIG_FB_SIS_315
7068 MODULE_PARM_DESC(pdc1,
7069 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
7070 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7071 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7072 "implemented yet.\n");
7073 #endif
7075 MODULE_PARM_DESC(specialtiming,
7076 "\nPlease refer to documentation for more information on this option.\n");
7078 MODULE_PARM_DESC(lvdshl,
7079 "\nPlease refer to documentation for more information on this option.\n");
7081 MODULE_PARM_DESC(tvstandard,
7082 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7083 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7085 MODULE_PARM_DESC(tvxposoffset,
7086 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7087 "Default: 0\n");
7089 MODULE_PARM_DESC(tvyposoffset,
7090 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7091 "Default: 0\n");
7093 MODULE_PARM_DESC(nocrt2rate,
7094 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7095 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7097 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7098 MODULE_PARM_DESC(inverse,
7099 "\nSetting this to anything but 0 should invert the display colors, but this\n"
7100 "does not seem to work. (default: 0)\n");
7101 #endif
7103 #if !defined(__i386__) && !defined(__x86_64__)
7104 #ifdef CONFIG_FB_SIS_300
7105 MODULE_PARM_DESC(resetcard,
7106 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
7107 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7108 "currently). Default: 0\n");
7110 MODULE_PARM_DESC(videoram,
7111 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7112 "some non-x86 architectures where the memory auto detection fails. Only\n"
7113 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
7114 #endif
7115 #endif
7117 #endif /* /MODULE */
7119 /* _GPL only for new symbols. */
7120 EXPORT_SYMBOL(sis_malloc);
7121 EXPORT_SYMBOL(sis_free);
7122 EXPORT_SYMBOL_GPL(sis_malloc_new);
7123 EXPORT_SYMBOL_GPL(sis_free_new);