[PATCH] fbdev: Sanitize ->fb_ioctl prototype
[usb.git] / drivers / video / sis / sis_main.c
blob8adf5bf91eee075716b12d95d5eb26ef6c0312bc
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/config.h>
37 #include <linux/version.h>
38 #include <linux/module.h>
39 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
40 #include <linux/moduleparam.h>
41 #endif
42 #include <linux/kernel.h>
43 #include <linux/smp_lock.h>
44 #include <linux/spinlock.h>
45 #include <linux/errno.h>
46 #include <linux/string.h>
47 #include <linux/mm.h>
48 #include <linux/tty.h>
49 #include <linux/slab.h>
50 #include <linux/fb.h>
51 #include <linux/selection.h>
52 #include <linux/ioport.h>
53 #include <linux/init.h>
54 #include <linux/pci.h>
55 #include <linux/vmalloc.h>
56 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
57 #include <linux/vt_kern.h>
58 #endif
59 #include <linux/capability.h>
60 #include <linux/fs.h>
61 #include <linux/types.h>
62 #include <asm/uaccess.h>
63 #include <asm/io.h>
64 #ifdef CONFIG_MTRR
65 #include <asm/mtrr.h>
66 #endif
68 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
69 #include <video/fbcon.h>
70 #include <video/fbcon-cfb8.h>
71 #include <video/fbcon-cfb16.h>
72 #include <video/fbcon-cfb24.h>
73 #include <video/fbcon-cfb32.h>
74 #endif
76 #include "sis.h"
77 #include "sis_main.h"
79 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
80 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
81 #error "This version of sisfb requires at least 2.6.3"
82 #endif
83 #endif
85 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
86 #ifdef FBCON_HAS_CFB8
87 extern struct display_switch fbcon_sis8;
88 #endif
89 #ifdef FBCON_HAS_CFB16
90 extern struct display_switch fbcon_sis16;
91 #endif
92 #ifdef FBCON_HAS_CFB32
93 extern struct display_switch fbcon_sis32;
94 #endif
95 #endif
97 static void sisfb_handle_command(struct sis_video_info *ivideo,
98 struct sisfb_cmd *sisfb_command);
100 /* ------------------ Internal helper routines ----------------- */
102 static void __init
103 sisfb_setdefaultparms(void)
105 sisfb_off = 0;
106 sisfb_parm_mem = 0;
107 sisfb_accel = -1;
108 sisfb_ypan = -1;
109 sisfb_max = -1;
110 sisfb_userom = -1;
111 sisfb_useoem = -1;
112 #ifdef MODULE
113 /* Module: "None" for 2.4, default mode for 2.5+ */
114 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
115 sisfb_mode_idx = -1;
116 #else
117 sisfb_mode_idx = MODE_INDEX_NONE;
118 #endif
119 #else
120 /* Static: Default mode */
121 sisfb_mode_idx = -1;
122 #endif
123 sisfb_parm_rate = -1;
124 sisfb_crt1off = 0;
125 sisfb_forcecrt1 = -1;
126 sisfb_crt2type = -1;
127 sisfb_crt2flags = 0;
128 sisfb_pdc = 0xff;
129 sisfb_pdca = 0xff;
130 sisfb_scalelcd = -1;
131 sisfb_specialtiming = CUT_NONE;
132 sisfb_lvdshl = -1;
133 sisfb_dstn = 0;
134 sisfb_fstn = 0;
135 sisfb_tvplug = -1;
136 sisfb_tvstd = -1;
137 sisfb_tvxposoffset = 0;
138 sisfb_tvyposoffset = 0;
139 sisfb_nocrt2rate = 0;
140 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
141 sisfb_inverse = 0;
142 sisfb_fontname[0] = 0;
143 #endif
144 #if !defined(__i386__) && !defined(__x86_64__)
145 sisfb_resetcard = 0;
146 sisfb_videoram = 0;
147 #endif
150 /* ------------- Parameter parsing -------------- */
152 static void __devinit
153 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
155 int i = 0, j = 0;
157 /* We don't know the hardware specs yet and there is no ivideo */
159 if(vesamode == 0) {
160 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
161 sisfb_mode_idx = MODE_INDEX_NONE;
162 #else
163 if(!quiet)
164 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
166 sisfb_mode_idx = DEFAULT_MODE;
167 #endif
168 return;
171 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
173 while(sisbios_mode[i++].mode_no[0] != 0) {
174 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
175 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
176 if(sisfb_fstn) {
177 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
178 sisbios_mode[i-1].mode_no[1] == 0x56 ||
179 sisbios_mode[i-1].mode_no[1] == 0x53)
180 continue;
181 } else {
182 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
183 sisbios_mode[i-1].mode_no[1] == 0x5b)
184 continue;
186 sisfb_mode_idx = i - 1;
187 j = 1;
188 break;
191 if((!j) && !quiet)
192 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
195 static void __devinit
196 sisfb_search_mode(char *name, BOOLEAN quiet)
198 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
199 int i = 0;
200 char strbuf[16], strbuf1[20];
201 char *nameptr = name;
203 /* We don't know the hardware specs yet and there is no ivideo */
205 if(name == NULL) {
206 if(!quiet)
207 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
209 sisfb_mode_idx = DEFAULT_MODE;
210 return;
213 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
214 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
215 if(!quiet)
216 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
218 sisfb_mode_idx = DEFAULT_MODE;
219 return;
221 #endif
222 if(strlen(name) <= 19) {
223 strcpy(strbuf1, name);
224 for(i = 0; i < strlen(strbuf1); i++) {
225 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
228 /* This does some fuzzy mode naming detection */
229 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
230 if((rate <= 32) || (depth > 32)) {
231 j = rate; rate = depth; depth = j;
233 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
234 nameptr = strbuf;
235 sisfb_parm_rate = rate;
236 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
237 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
238 nameptr = strbuf;
239 } else {
240 xres = 0;
241 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
242 sprintf(strbuf, "%ux%ux8", xres, yres);
243 nameptr = strbuf;
244 } else {
245 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
246 return;
251 i = 0; j = 0;
252 while(sisbios_mode[i].mode_no[0] != 0) {
253 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
254 if(sisfb_fstn) {
255 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
256 sisbios_mode[i-1].mode_no[1] == 0x56 ||
257 sisbios_mode[i-1].mode_no[1] == 0x53)
258 continue;
259 } else {
260 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
261 sisbios_mode[i-1].mode_no[1] == 0x5b)
262 continue;
264 sisfb_mode_idx = i - 1;
265 j = 1;
266 break;
270 if((!j) && !quiet)
271 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
274 #ifndef MODULE
275 static void __devinit
276 sisfb_get_vga_mode_from_kernel(void)
278 #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
279 char mymode[32];
280 int mydepth = screen_info.lfb_depth;
282 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
284 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
285 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
286 (mydepth >= 8) && (mydepth <= 32) ) {
288 if(mydepth == 24) mydepth = 32;
290 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
291 screen_info.lfb_height,
292 mydepth);
294 printk(KERN_DEBUG
295 "sisfb: Using vga mode %s pre-set by kernel as default\n",
296 mymode);
298 sisfb_search_mode(mymode, TRUE);
300 #endif
301 return;
303 #endif
305 static void __init
306 sisfb_search_crt2type(const char *name)
308 int i = 0;
310 /* We don't know the hardware specs yet and there is no ivideo */
312 if(name == NULL) return;
314 while(sis_crt2type[i].type_no != -1) {
315 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
316 sisfb_crt2type = sis_crt2type[i].type_no;
317 sisfb_tvplug = sis_crt2type[i].tvplug_no;
318 sisfb_crt2flags = sis_crt2type[i].flags;
319 break;
321 i++;
324 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
325 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
327 if(sisfb_crt2type < 0)
328 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
331 static void __init
332 sisfb_search_tvstd(const char *name)
334 int i = 0;
336 /* We don't know the hardware specs yet and there is no ivideo */
338 if(name == NULL)
339 return;
341 while(sis_tvtype[i].type_no != -1) {
342 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
343 sisfb_tvstd = sis_tvtype[i].type_no;
344 break;
346 i++;
350 static void __init
351 sisfb_search_specialtiming(const char *name)
353 int i = 0;
354 BOOLEAN found = FALSE;
356 /* We don't know the hardware specs yet and there is no ivideo */
358 if(name == NULL)
359 return;
361 if(!strnicmp(name, "none", 4)) {
362 sisfb_specialtiming = CUT_FORCENONE;
363 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
364 } else {
365 while(mycustomttable[i].chipID != 0) {
366 if(!strnicmp(name,mycustomttable[i].optionName,
367 strlen(mycustomttable[i].optionName))) {
368 sisfb_specialtiming = mycustomttable[i].SpecialID;
369 found = TRUE;
370 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
371 mycustomttable[i].vendorName,
372 mycustomttable[i].cardName,
373 mycustomttable[i].optionName);
374 break;
376 i++;
378 if(!found) {
379 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
380 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
381 i = 0;
382 while(mycustomttable[i].chipID != 0) {
383 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
384 mycustomttable[i].optionName,
385 mycustomttable[i].vendorName,
386 mycustomttable[i].cardName);
387 i++;
393 /* ----------- Various detection routines ----------- */
395 static void __devinit
396 sisfb_detect_custom_timing(struct sis_video_info *ivideo)
398 unsigned char *biosver = NULL;
399 unsigned char *biosdate = NULL;
400 BOOLEAN footprint;
401 u32 chksum = 0;
402 int i, j;
404 if(ivideo->SiS_Pr.UseROM) {
405 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
406 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
407 for(i = 0; i < 32768; i++)
408 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
411 i = 0;
412 do {
413 if( (mycustomttable[i].chipID == ivideo->chip) &&
414 ((!strlen(mycustomttable[i].biosversion)) ||
415 (ivideo->SiS_Pr.UseROM &&
416 (!strncmp(mycustomttable[i].biosversion, biosver,
417 strlen(mycustomttable[i].biosversion))))) &&
418 ((!strlen(mycustomttable[i].biosdate)) ||
419 (ivideo->SiS_Pr.UseROM &&
420 (!strncmp(mycustomttable[i].biosdate, biosdate,
421 strlen(mycustomttable[i].biosdate))))) &&
422 ((!mycustomttable[i].bioschksum) ||
423 (ivideo->SiS_Pr.UseROM &&
424 (mycustomttable[i].bioschksum == chksum))) &&
425 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
426 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
427 footprint = TRUE;
428 for(j = 0; j < 5; j++) {
429 if(mycustomttable[i].biosFootprintAddr[j]) {
430 if(ivideo->SiS_Pr.UseROM) {
431 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
432 mycustomttable[i].biosFootprintData[j]) {
433 footprint = FALSE;
435 } else
436 footprint = FALSE;
439 if(footprint) {
440 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
441 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
442 mycustomttable[i].vendorName,
443 mycustomttable[i].cardName);
444 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
445 mycustomttable[i].optionName);
446 break;
449 i++;
450 } while(mycustomttable[i].chipID);
453 static BOOLEAN __devinit
454 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
456 int i, j, xres, yres, refresh, index;
457 u32 emodes;
459 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
460 buffer[2] != 0xff || buffer[3] != 0xff ||
461 buffer[4] != 0xff || buffer[5] != 0xff ||
462 buffer[6] != 0xff || buffer[7] != 0x00) {
463 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
464 return FALSE;
467 if(buffer[0x12] != 0x01) {
468 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
469 buffer[0x12]);
470 return FALSE;
473 monitor->feature = buffer[0x18];
475 if(!buffer[0x14] & 0x80) {
476 if(!(buffer[0x14] & 0x08)) {
477 printk(KERN_INFO
478 "sisfb: WARNING: Monitor does not support separate syncs\n");
482 if(buffer[0x13] >= 0x01) {
483 /* EDID V1 rev 1 and 2: Search for monitor descriptor
484 * to extract ranges
486 j = 0x36;
487 for(i=0; i<4; i++) {
488 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
489 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
490 buffer[j + 4] == 0x00) {
491 monitor->hmin = buffer[j + 7];
492 monitor->hmax = buffer[j + 8];
493 monitor->vmin = buffer[j + 5];
494 monitor->vmax = buffer[j + 6];
495 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
496 monitor->datavalid = TRUE;
497 break;
499 j += 18;
503 if(!monitor->datavalid) {
504 /* Otherwise: Get a range from the list of supported
505 * Estabished Timings. This is not entirely accurate,
506 * because fixed frequency monitors are not supported
507 * that way.
509 monitor->hmin = 65535; monitor->hmax = 0;
510 monitor->vmin = 65535; monitor->vmax = 0;
511 monitor->dclockmax = 0;
512 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
513 for(i = 0; i < 13; i++) {
514 if(emodes & sisfb_ddcsmodes[i].mask) {
515 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
516 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
517 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
518 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
519 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
522 index = 0x26;
523 for(i = 0; i < 8; i++) {
524 xres = (buffer[index] + 31) * 8;
525 switch(buffer[index + 1] & 0xc0) {
526 case 0xc0: yres = (xres * 9) / 16; break;
527 case 0x80: yres = (xres * 4) / 5; break;
528 case 0x40: yres = (xres * 3) / 4; break;
529 default: yres = xres; break;
531 refresh = (buffer[index + 1] & 0x3f) + 60;
532 if((xres >= 640) && (yres >= 480)) {
533 for(j = 0; j < 8; j++) {
534 if((xres == sisfb_ddcfmodes[j].x) &&
535 (yres == sisfb_ddcfmodes[j].y) &&
536 (refresh == sisfb_ddcfmodes[j].v)) {
537 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
538 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
539 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
540 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
541 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
545 index += 2;
547 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
548 monitor->datavalid = TRUE;
552 return monitor->datavalid;
555 static void __devinit
556 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
558 unsigned short temp, i, realcrtno = crtno;
559 unsigned char buffer[256];
561 monitor->datavalid = FALSE;
563 if(crtno) {
564 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
565 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
566 else return;
569 if((ivideo->sisfb_crt1off) && (!crtno))
570 return;
572 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
573 realcrtno, 0, &buffer[0], ivideo->vbflags2);
574 if((!temp) || (temp == 0xffff)) {
575 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
576 return;
577 } else {
578 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
579 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
580 crtno + 1,
581 (temp & 0x1a) ? "" : "[none of the supported]",
582 (temp & 0x02) ? "2 " : "",
583 (temp & 0x08) ? "D&P" : "",
584 (temp & 0x10) ? "FPDI-2" : "");
585 if(temp & 0x02) {
586 i = 3; /* Number of retrys */
587 do {
588 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
589 realcrtno, 1, &buffer[0], ivideo->vbflags2);
590 } while((temp) && i--);
591 if(!temp) {
592 if(sisfb_interpret_edid(monitor, &buffer[0])) {
593 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
594 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
595 monitor->dclockmax / 1000);
596 } else {
597 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
599 } else {
600 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
602 } else {
603 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
608 /* -------------- Mode validation --------------- */
610 static BOOLEAN
611 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
612 int mode_idx, int rate_idx, int rate)
614 int htotal, vtotal;
615 unsigned int dclock, hsync;
617 if(!monitor->datavalid)
618 return TRUE;
620 if(mode_idx < 0)
621 return FALSE;
623 /* Skip for 320x200, 320x240, 640x400 */
624 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
625 case 0x59:
626 case 0x41:
627 case 0x4f:
628 case 0x50:
629 case 0x56:
630 case 0x53:
631 case 0x2f:
632 case 0x5d:
633 case 0x5e:
634 return TRUE;
635 #ifdef CONFIG_FB_SIS_315
636 case 0x5a:
637 case 0x5b:
638 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
639 #endif
642 if(rate < (monitor->vmin - 1))
643 return FALSE;
644 if(rate > (monitor->vmax + 1))
645 return FALSE;
647 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
648 sisbios_mode[mode_idx].mode_no[ivideo->mni],
649 &htotal, &vtotal, rate_idx)) {
650 dclock = (htotal * vtotal * rate) / 1000;
651 if(dclock > (monitor->dclockmax + 1000))
652 return FALSE;
653 hsync = dclock / htotal;
654 if(hsync < (monitor->hmin - 1))
655 return FALSE;
656 if(hsync > (monitor->hmax + 1))
657 return FALSE;
658 } else {
659 return FALSE;
661 return TRUE;
664 static int
665 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
667 u16 xres=0, yres, myres;
669 #ifdef CONFIG_FB_SIS_300
670 if(ivideo->sisvga_engine == SIS_300_VGA) {
671 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
672 return -1 ;
674 #endif
675 #ifdef CONFIG_FB_SIS_315
676 if(ivideo->sisvga_engine == SIS_315_VGA) {
677 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
678 return -1;
680 #endif
682 myres = sisbios_mode[myindex].yres;
684 switch(vbflags & VB_DISPTYPE_DISP2) {
686 case CRT2_LCD:
687 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
689 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
690 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
691 if(sisbios_mode[myindex].xres > xres)
692 return -1;
693 if(myres > yres)
694 return -1;
697 if(ivideo->sisfb_fstn) {
698 if(sisbios_mode[myindex].xres == 320) {
699 if(myres == 240) {
700 switch(sisbios_mode[myindex].mode_no[1]) {
701 case 0x50: myindex = MODE_FSTN_8; break;
702 case 0x56: myindex = MODE_FSTN_16; break;
703 case 0x53: return -1;
709 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
710 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
711 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
712 return -1;
714 break;
716 case CRT2_TV:
717 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
718 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
719 return -1;
721 break;
723 case CRT2_VGA:
724 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
725 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
726 return -1;
728 break;
731 return myindex;
734 static u8
735 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
737 int i = 0;
738 u16 xres = sisbios_mode[mode_idx].xres;
739 u16 yres = sisbios_mode[mode_idx].yres;
741 ivideo->rate_idx = 0;
742 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
743 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
744 if(sisfb_vrate[i].refresh == rate) {
745 ivideo->rate_idx = sisfb_vrate[i].idx;
746 break;
747 } else if(sisfb_vrate[i].refresh > rate) {
748 if((sisfb_vrate[i].refresh - rate) <= 3) {
749 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
750 rate, sisfb_vrate[i].refresh);
751 ivideo->rate_idx = sisfb_vrate[i].idx;
752 ivideo->refresh_rate = sisfb_vrate[i].refresh;
753 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
754 && (sisfb_vrate[i].idx != 1)) {
755 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
756 rate, sisfb_vrate[i-1].refresh);
757 ivideo->rate_idx = sisfb_vrate[i-1].idx;
758 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
760 break;
761 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
762 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
763 rate, sisfb_vrate[i].refresh);
764 ivideo->rate_idx = sisfb_vrate[i].idx;
765 break;
768 i++;
770 if(ivideo->rate_idx > 0) {
771 return ivideo->rate_idx;
772 } else {
773 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
774 rate, xres, yres);
775 return 0;
779 static BOOLEAN
780 sisfb_bridgeisslave(struct sis_video_info *ivideo)
782 unsigned char P1_00;
784 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
785 return FALSE;
787 inSISIDXREG(SISPART1,0x00,P1_00);
788 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
789 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
790 return TRUE;
791 } else {
792 return FALSE;
796 static BOOLEAN
797 sisfballowretracecrt1(struct sis_video_info *ivideo)
799 u8 temp;
801 inSISIDXREG(SISCR,0x17,temp);
802 if(!(temp & 0x80))
803 return FALSE;
805 inSISIDXREG(SISSR,0x1f,temp);
806 if(temp & 0xc0)
807 return FALSE;
809 return TRUE;
812 static BOOLEAN
813 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
815 if(!sisfballowretracecrt1(ivideo))
816 return FALSE;
818 if(inSISREG(SISINPSTAT) & 0x08)
819 return TRUE;
820 else
821 return FALSE;
824 static void
825 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
827 int watchdog;
829 if(!sisfballowretracecrt1(ivideo))
830 return;
832 watchdog = 65536;
833 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
834 watchdog = 65536;
835 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
838 static BOOLEAN
839 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
841 unsigned char temp, reg;
843 switch(ivideo->sisvga_engine) {
844 case SIS_300_VGA: reg = 0x25; break;
845 case SIS_315_VGA: reg = 0x30; break;
846 default: return FALSE;
849 inSISIDXREG(SISPART1, reg, temp);
850 if(temp & 0x02)
851 return TRUE;
852 else
853 return FALSE;
856 static BOOLEAN
857 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
859 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
860 if(!sisfb_bridgeisslave(ivideo)) {
861 return sisfbcheckvretracecrt2(ivideo);
864 return sisfbcheckvretracecrt1(ivideo);
867 static u32
868 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
870 u8 idx, reg1, reg2, reg3, reg4;
871 u32 ret = 0;
873 (*vcount) = (*hcount) = 0;
875 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
877 ret |= (FB_VBLANK_HAVE_VSYNC |
878 FB_VBLANK_HAVE_HBLANK |
879 FB_VBLANK_HAVE_VBLANK |
880 FB_VBLANK_HAVE_VCOUNT |
881 FB_VBLANK_HAVE_HCOUNT);
882 switch(ivideo->sisvga_engine) {
883 case SIS_300_VGA: idx = 0x25; break;
884 default:
885 case SIS_315_VGA: idx = 0x30; break;
887 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
888 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
889 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
890 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
891 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
892 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
893 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
894 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
895 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
897 } else if(sisfballowretracecrt1(ivideo)) {
899 ret |= (FB_VBLANK_HAVE_VSYNC |
900 FB_VBLANK_HAVE_VBLANK |
901 FB_VBLANK_HAVE_VCOUNT |
902 FB_VBLANK_HAVE_HCOUNT);
903 reg1 = inSISREG(SISINPSTAT);
904 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
905 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
906 inSISIDXREG(SISCR,0x20,reg1);
907 inSISIDXREG(SISCR,0x1b,reg1);
908 inSISIDXREG(SISCR,0x1c,reg2);
909 inSISIDXREG(SISCR,0x1d,reg3);
910 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
911 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
914 return ret;
917 static int
918 sisfb_myblank(struct sis_video_info *ivideo, int blank)
920 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
921 BOOLEAN backlight = TRUE;
923 switch(blank) {
924 case FB_BLANK_UNBLANK: /* on */
925 sr01 = 0x00;
926 sr11 = 0x00;
927 sr1f = 0x00;
928 cr63 = 0x00;
929 p2_0 = 0x20;
930 p1_13 = 0x00;
931 backlight = TRUE;
932 break;
933 case FB_BLANK_NORMAL: /* blank */
934 sr01 = 0x20;
935 sr11 = 0x00;
936 sr1f = 0x00;
937 cr63 = 0x00;
938 p2_0 = 0x20;
939 p1_13 = 0x00;
940 backlight = TRUE;
941 break;
942 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
943 sr01 = 0x20;
944 sr11 = 0x08;
945 sr1f = 0x80;
946 cr63 = 0x40;
947 p2_0 = 0x40;
948 p1_13 = 0x80;
949 backlight = FALSE;
950 break;
951 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
952 sr01 = 0x20;
953 sr11 = 0x08;
954 sr1f = 0x40;
955 cr63 = 0x40;
956 p2_0 = 0x80;
957 p1_13 = 0x40;
958 backlight = FALSE;
959 break;
960 case FB_BLANK_POWERDOWN: /* off */
961 sr01 = 0x20;
962 sr11 = 0x08;
963 sr1f = 0xc0;
964 cr63 = 0x40;
965 p2_0 = 0xc0;
966 p1_13 = 0xc0;
967 backlight = FALSE;
968 break;
969 default:
970 return 1;
973 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
975 if( (!ivideo->sisfb_thismonitor.datavalid) ||
976 ((ivideo->sisfb_thismonitor.datavalid) &&
977 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
979 if(ivideo->sisvga_engine == SIS_315_VGA) {
980 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
983 if(!(sisfb_bridgeisslave(ivideo))) {
984 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
985 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
991 if(ivideo->currentvbflags & CRT2_LCD) {
993 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
994 if(backlight) {
995 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
996 } else {
997 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
999 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1000 #ifdef CONFIG_FB_SIS_315
1001 if(ivideo->vbflags2 & VB2_CHRONTEL) {
1002 if(backlight) {
1003 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
1004 } else {
1005 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
1008 #endif
1011 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
1012 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
1013 ((ivideo->sisvga_engine == SIS_315_VGA) &&
1014 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
1015 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
1018 if(ivideo->sisvga_engine == SIS_300_VGA) {
1019 if((ivideo->vbflags2 & VB2_30xB) &&
1020 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1021 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
1023 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1024 if((ivideo->vbflags2 & VB2_30xB) &&
1025 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1026 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1030 } else if(ivideo->currentvbflags & CRT2_VGA) {
1032 if(ivideo->vbflags2 & VB2_30xB) {
1033 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1038 return 0;
1041 /* ------------- Callbacks from init.c/init301.c -------------- */
1043 #ifdef CONFIG_FB_SIS_300
1044 unsigned int
1045 sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1047 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1048 u32 val = 0;
1050 pci_read_config_dword(ivideo->nbridge, reg, &val);
1051 return (unsigned int)val;
1054 void
1055 sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1057 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1059 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1062 unsigned int
1063 sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1065 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1066 u32 val = 0;
1068 if(!ivideo->lpcdev) return 0;
1070 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1071 return (unsigned int)val;
1073 #endif
1075 #ifdef CONFIG_FB_SIS_315
1076 void
1077 sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1079 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1081 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1084 unsigned int
1085 sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1087 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1088 u16 val = 0;
1090 if(!ivideo->lpcdev) return 0;
1092 pci_read_config_word(ivideo->lpcdev, reg, &val);
1093 return (unsigned int)val;
1095 #endif
1097 /* ----------- FBDev related routines for all series ----------- */
1099 static int
1100 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1102 return (var->bits_per_pixel == 8) ? 256 : 16;
1105 static void
1106 sisfb_set_vparms(struct sis_video_info *ivideo)
1108 switch(ivideo->video_bpp) {
1109 case 8:
1110 ivideo->DstColor = 0x0000;
1111 ivideo->SiS310_AccelDepth = 0x00000000;
1112 ivideo->video_cmap_len = 256;
1113 break;
1114 case 16:
1115 ivideo->DstColor = 0x8000;
1116 ivideo->SiS310_AccelDepth = 0x00010000;
1117 ivideo->video_cmap_len = 16;
1118 break;
1119 case 32:
1120 ivideo->DstColor = 0xC000;
1121 ivideo->SiS310_AccelDepth = 0x00020000;
1122 ivideo->video_cmap_len = 16;
1123 break;
1124 default:
1125 ivideo->video_cmap_len = 16;
1126 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1127 ivideo->accel = 0;
1131 static int
1132 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1134 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1136 if(maxyres > 32767) maxyres = 32767;
1138 return maxyres;
1141 static void
1142 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1144 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1145 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1146 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1147 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1148 ivideo->scrnpitchCRT1 <<= 1;
1153 static void
1154 sisfb_set_pitch(struct sis_video_info *ivideo)
1156 BOOLEAN isslavemode = FALSE;
1157 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1158 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1160 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
1162 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1163 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1164 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1165 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1168 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1169 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1170 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1171 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1172 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1176 static void
1177 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1179 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1181 switch(var->bits_per_pixel) {
1182 case 8:
1183 var->red.offset = var->green.offset = var->blue.offset = 0;
1184 var->red.length = var->green.length = var->blue.length = 6;
1185 break;
1186 case 16:
1187 var->red.offset = 11;
1188 var->red.length = 5;
1189 var->green.offset = 5;
1190 var->green.length = 6;
1191 var->blue.offset = 0;
1192 var->blue.length = 5;
1193 var->transp.offset = 0;
1194 var->transp.length = 0;
1195 break;
1196 case 32:
1197 var->red.offset = 16;
1198 var->red.length = 8;
1199 var->green.offset = 8;
1200 var->green.length = 8;
1201 var->blue.offset = 0;
1202 var->blue.length = 8;
1203 var->transp.offset = 24;
1204 var->transp.length = 8;
1205 break;
1209 static int
1210 sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1212 unsigned short modeno = ivideo->mode_no;
1214 /* >=2.6.12's fbcon clears the screen anyway */
1215 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
1216 if(!clrscrn) modeno |= 0x80;
1217 #else
1218 modeno |= 0x80;
1219 #endif
1221 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1223 sisfb_pre_setmode(ivideo);
1225 if(SiSSetMode(&ivideo->SiS_Pr, modeno) == 0) {
1226 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1227 return -EINVAL;
1230 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1232 sisfb_post_setmode(ivideo);
1234 return 0;
1238 static int
1239 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1241 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1242 unsigned int htotal = 0, vtotal = 0;
1243 unsigned int drate = 0, hrate = 0;
1244 int found_mode = 0, ret;
1245 int old_mode;
1246 u32 pixclock;
1248 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1250 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1252 pixclock = var->pixclock;
1254 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1255 vtotal += var->yres;
1256 vtotal <<= 1;
1257 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1258 vtotal += var->yres;
1259 vtotal <<= 2;
1260 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1261 vtotal += var->yres;
1262 vtotal <<= 1;
1263 } else vtotal += var->yres;
1265 if(!(htotal) || !(vtotal)) {
1266 DPRINTK("sisfb: Invalid 'var' information\n");
1267 return -EINVAL;
1270 if(pixclock && htotal && vtotal) {
1271 drate = 1000000000 / pixclock;
1272 hrate = (drate * 1000) / htotal;
1273 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1274 } else {
1275 ivideo->refresh_rate = 60;
1278 old_mode = ivideo->sisfb_mode_idx;
1279 ivideo->sisfb_mode_idx = 0;
1281 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1282 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1283 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1284 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1285 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1286 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1287 found_mode = 1;
1288 break;
1290 ivideo->sisfb_mode_idx++;
1293 if(found_mode) {
1294 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1295 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1296 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1297 } else {
1298 ivideo->sisfb_mode_idx = -1;
1301 if(ivideo->sisfb_mode_idx < 0) {
1302 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1303 var->yres, var->bits_per_pixel);
1304 ivideo->sisfb_mode_idx = old_mode;
1305 return -EINVAL;
1308 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1309 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1310 ivideo->refresh_rate = 60;
1313 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1314 if(ivideo->sisfb_thismonitor.datavalid) {
1315 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
1316 ivideo->rate_idx, ivideo->refresh_rate)) {
1317 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1320 #endif
1322 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1323 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1324 #else
1325 if(isactive) {
1326 #endif
1327 /* If acceleration to be used? Need to know
1328 * before pre/post_set_mode()
1330 ivideo->accel = 0;
1331 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1332 #ifdef STUPID_ACCELF_TEXT_SHIT
1333 if(var->accel_flags & FB_ACCELF_TEXT) {
1334 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1335 } else {
1336 info->flags |= FBINFO_HWACCEL_DISABLED;
1338 #endif
1339 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1340 #else
1341 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1342 #endif
1344 if((ret = sisfb_set_mode(ivideo, 1))) {
1345 return ret;
1348 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1349 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1350 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1352 sisfb_calc_pitch(ivideo, var);
1353 sisfb_set_pitch(ivideo);
1355 sisfb_set_vparms(ivideo);
1357 ivideo->current_width = ivideo->video_width;
1358 ivideo->current_height = ivideo->video_height;
1359 ivideo->current_bpp = ivideo->video_bpp;
1360 ivideo->current_htotal = htotal;
1361 ivideo->current_vtotal = vtotal;
1362 ivideo->current_linelength = ivideo->video_linelength;
1363 ivideo->current_pixclock = var->pixclock;
1364 ivideo->current_refresh_rate = ivideo->refresh_rate;
1365 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1366 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1367 #endif
1370 return 0;
1373 static void
1374 sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1376 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1378 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1379 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1380 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1381 if(ivideo->sisvga_engine == SIS_315_VGA) {
1382 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1386 static void
1387 sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1389 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1390 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1391 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1392 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1393 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1394 if(ivideo->sisvga_engine == SIS_315_VGA) {
1395 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1400 static int
1401 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1403 if(var->xoffset > (var->xres_virtual - var->xres)) {
1404 return -EINVAL;
1406 if(var->yoffset > (var->yres_virtual - var->yres)) {
1407 return -EINVAL;
1410 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
1412 /* calculate base bpp dep. */
1413 switch(var->bits_per_pixel) {
1414 case 32:
1415 break;
1416 case 16:
1417 ivideo->current_base >>= 1;
1418 break;
1419 case 8:
1420 default:
1421 ivideo->current_base >>= 2;
1422 break;
1425 ivideo->current_base += (ivideo->video_offset >> 2);
1427 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1428 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1430 return 0;
1433 /* ------------ FBDev related routines for 2.4 series ----------- */
1435 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1437 #include "sisfb_fbdev_2_4.h"
1439 #endif
1441 /* ------------ FBDev related routines for 2.6 series ----------- */
1443 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1445 static int
1446 sisfb_open(struct fb_info *info, int user)
1448 return 0;
1451 static int
1452 sisfb_release(struct fb_info *info, int user)
1454 return 0;
1457 static int
1458 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1459 unsigned transp, struct fb_info *info)
1461 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1463 if(regno >= sisfb_get_cmap_len(&info->var))
1464 return 1;
1466 switch(info->var.bits_per_pixel) {
1467 case 8:
1468 outSISREG(SISDACA, regno);
1469 outSISREG(SISDACD, (red >> 10));
1470 outSISREG(SISDACD, (green >> 10));
1471 outSISREG(SISDACD, (blue >> 10));
1472 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1473 outSISREG(SISDAC2A, regno);
1474 outSISREG(SISDAC2D, (red >> 8));
1475 outSISREG(SISDAC2D, (green >> 8));
1476 outSISREG(SISDAC2D, (blue >> 8));
1478 break;
1479 case 16:
1480 ((u32 *)(info->pseudo_palette))[regno] =
1481 (red & 0xf800) |
1482 ((green & 0xfc00) >> 5) |
1483 ((blue & 0xf800) >> 11);
1484 break;
1485 case 32:
1486 red >>= 8;
1487 green >>= 8;
1488 blue >>= 8;
1489 ((u32 *)(info->pseudo_palette))[regno] =
1490 (red << 16) | (green << 8) | (blue);
1491 break;
1493 return 0;
1496 static int
1497 sisfb_set_par(struct fb_info *info)
1499 int err;
1501 if((err = sisfb_do_set_var(&info->var, 1, info)))
1502 return err;
1504 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1505 sisfb_get_fix(&info->fix, info->currcon, info);
1506 #else
1507 sisfb_get_fix(&info->fix, -1, info);
1508 #endif
1509 return 0;
1512 static int
1513 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1515 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1516 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1517 unsigned int drate = 0, hrate = 0, maxyres;
1518 int found_mode = 0;
1519 int refresh_rate, search_idx, tidx;
1520 BOOLEAN recalc_clock = FALSE;
1521 u32 pixclock;
1523 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1525 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1527 pixclock = var->pixclock;
1529 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1530 vtotal += var->yres;
1531 vtotal <<= 1;
1532 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1533 vtotal += var->yres;
1534 vtotal <<= 2;
1535 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1536 vtotal += var->yres;
1537 vtotal <<= 1;
1538 } else
1539 vtotal += var->yres;
1541 if(!(htotal) || !(vtotal)) {
1542 SISFAIL("sisfb: no valid timing data");
1545 search_idx = 0;
1546 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1547 (sisbios_mode[search_idx].xres <= var->xres) ) {
1548 if( (sisbios_mode[search_idx].xres == var->xres) &&
1549 (sisbios_mode[search_idx].yres == var->yres) &&
1550 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1551 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1552 ivideo->currentvbflags)) > 0) {
1553 found_mode = 1;
1554 search_idx = tidx;
1555 break;
1558 search_idx++;
1561 if(!found_mode) {
1562 search_idx = 0;
1563 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1564 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1565 (var->yres <= sisbios_mode[search_idx].yres) &&
1566 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1567 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1568 ivideo->currentvbflags)) > 0) {
1569 found_mode = 1;
1570 search_idx = tidx;
1571 break;
1574 search_idx++;
1576 if(found_mode) {
1577 printk(KERN_DEBUG
1578 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1579 var->xres, var->yres, var->bits_per_pixel,
1580 sisbios_mode[search_idx].xres,
1581 sisbios_mode[search_idx].yres,
1582 var->bits_per_pixel);
1583 var->xres = sisbios_mode[search_idx].xres;
1584 var->yres = sisbios_mode[search_idx].yres;
1585 } else {
1586 printk(KERN_ERR
1587 "sisfb: Failed to find supported mode near %dx%dx%d\n",
1588 var->xres, var->yres, var->bits_per_pixel);
1589 return -EINVAL;
1593 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1594 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1595 (var->bits_per_pixel == 8) ) {
1596 /* Slave modes on LVDS and 301B-DH */
1597 refresh_rate = 60;
1598 recalc_clock = TRUE;
1599 } else if( (ivideo->current_htotal == htotal) &&
1600 (ivideo->current_vtotal == vtotal) &&
1601 (ivideo->current_pixclock == pixclock) ) {
1602 /* x=x & y=y & c=c -> assume depth change */
1603 drate = 1000000000 / pixclock;
1604 hrate = (drate * 1000) / htotal;
1605 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1606 } else if( ( (ivideo->current_htotal != htotal) ||
1607 (ivideo->current_vtotal != vtotal) ) &&
1608 (ivideo->current_pixclock == var->pixclock) ) {
1609 /* x!=x | y!=y & c=c -> invalid pixclock */
1610 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1611 refresh_rate =
1612 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1613 } else if(ivideo->sisfb_parm_rate != -1) {
1614 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1615 refresh_rate = ivideo->sisfb_parm_rate;
1616 } else {
1617 refresh_rate = 60;
1619 recalc_clock = TRUE;
1620 } else if((pixclock) && (htotal) && (vtotal)) {
1621 drate = 1000000000 / pixclock;
1622 hrate = (drate * 1000) / htotal;
1623 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1624 } else if(ivideo->current_refresh_rate) {
1625 refresh_rate = ivideo->current_refresh_rate;
1626 recalc_clock = TRUE;
1627 } else {
1628 refresh_rate = 60;
1629 recalc_clock = TRUE;
1632 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1634 /* Eventually recalculate timing and clock */
1635 if(recalc_clock) {
1636 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1637 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1638 sisbios_mode[search_idx].mode_no[ivideo->mni],
1639 myrateindex));
1640 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1641 sisbios_mode[search_idx].mode_no[ivideo->mni],
1642 myrateindex, var);
1643 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1644 var->pixclock <<= 1;
1648 if(ivideo->sisfb_thismonitor.datavalid) {
1649 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1650 myrateindex, refresh_rate)) {
1651 printk(KERN_INFO
1652 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1656 /* Adapt RGB settings */
1657 sisfb_bpp_to_var(ivideo, var);
1659 /* Sanity check for offsets */
1660 if(var->xoffset < 0) var->xoffset = 0;
1661 if(var->yoffset < 0) var->yoffset = 0;
1663 if(var->xres > var->xres_virtual)
1664 var->xres_virtual = var->xres;
1666 if(ivideo->sisfb_ypan) {
1667 maxyres = sisfb_calc_maxyres(ivideo, var);
1668 if(ivideo->sisfb_max) {
1669 var->yres_virtual = maxyres;
1670 } else {
1671 if(var->yres_virtual > maxyres) {
1672 var->yres_virtual = maxyres;
1675 if(var->yres_virtual <= var->yres) {
1676 var->yres_virtual = var->yres;
1678 } else {
1679 if(var->yres != var->yres_virtual) {
1680 var->yres_virtual = var->yres;
1682 var->xoffset = 0;
1683 var->yoffset = 0;
1686 /* Truncate offsets to maximum if too high */
1687 if(var->xoffset > var->xres_virtual - var->xres) {
1688 var->xoffset = var->xres_virtual - var->xres - 1;
1691 if(var->yoffset > var->yres_virtual - var->yres) {
1692 var->yoffset = var->yres_virtual - var->yres - 1;
1695 /* Set everything else to 0 */
1696 var->red.msb_right =
1697 var->green.msb_right =
1698 var->blue.msb_right =
1699 var->transp.offset =
1700 var->transp.length =
1701 var->transp.msb_right = 0;
1703 return 0;
1706 static int
1707 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1709 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1710 int err;
1712 if(var->xoffset > (var->xres_virtual - var->xres))
1713 return -EINVAL;
1715 if(var->yoffset > (var->yres_virtual - var->yres))
1716 return -EINVAL;
1718 if(var->vmode & FB_VMODE_YWRAP)
1719 return -EINVAL;
1721 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
1722 var->yoffset + info->var.yres > info->var.yres_virtual)
1723 return -EINVAL;
1725 if((err = sisfb_pan_var(ivideo, var)) < 0)
1726 return err;
1728 info->var.xoffset = var->xoffset;
1729 info->var.yoffset = var->yoffset;
1731 return 0;
1734 static int
1735 sisfb_blank(int blank, struct fb_info *info)
1737 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1739 return sisfb_myblank(ivideo, blank);
1742 #endif
1744 /* ----------- FBDev related routines for all series ---------- */
1746 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1747 static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1748 unsigned long arg)
1749 #else
1750 static int sisfb_ioctl(struct inode *inode, struct file *file,
1751 unsigned int cmd, unsigned long arg,
1752 struct fb_info *info)
1753 #endif
1755 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1756 struct sis_memreq sismemreq;
1757 struct fb_vblank sisvbblank;
1758 u32 gpu32 = 0;
1759 #ifndef __user
1760 #define __user
1761 #endif
1762 u32 __user *argp = (u32 __user *)arg;
1764 switch(cmd) {
1765 case FBIO_ALLOC:
1766 if(!capable(CAP_SYS_RAWIO))
1767 return -EPERM;
1769 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1770 return -EFAULT;
1772 sis_malloc(&sismemreq);
1774 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1775 sis_free((u32)sismemreq.offset);
1776 return -EFAULT;
1778 break;
1780 case FBIO_FREE:
1781 if(!capable(CAP_SYS_RAWIO))
1782 return -EPERM;
1784 if(get_user(gpu32, argp))
1785 return -EFAULT;
1787 sis_free(gpu32);
1788 break;
1790 case FBIOGET_VBLANK:
1791 sisvbblank.count = 0;
1792 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1794 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1795 return -EFAULT;
1797 break;
1799 case SISFB_GET_INFO_SIZE:
1800 return put_user(sizeof(struct sisfb_info), argp);
1802 case SISFB_GET_INFO_OLD:
1803 if(ivideo->warncount++ < 10)
1804 printk(KERN_INFO
1805 "sisfb: Deprecated ioctl call received - update your application!\n");
1806 case SISFB_GET_INFO: /* For communication with X driver */
1807 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1808 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1809 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1810 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1811 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1812 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1813 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1814 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1815 if(ivideo->modechanged) {
1816 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1817 } else {
1818 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1820 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1821 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1822 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1823 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1824 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1825 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1826 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1827 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1828 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1829 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1830 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1831 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1832 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1833 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1834 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1835 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1836 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1837 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1838 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1839 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1840 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1841 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1842 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1843 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1844 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1845 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1846 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1847 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1849 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1850 sizeof(ivideo->sisfb_infoblock)))
1851 return -EFAULT;
1853 break;
1855 case SISFB_GET_VBRSTATUS_OLD:
1856 if(ivideo->warncount++ < 10)
1857 printk(KERN_INFO
1858 "sisfb: Deprecated ioctl call received - update your application!\n");
1859 case SISFB_GET_VBRSTATUS:
1860 if(sisfb_CheckVBRetrace(ivideo))
1861 return put_user((u32)1, argp);
1862 else
1863 return put_user((u32)0, argp);
1865 case SISFB_GET_AUTOMAXIMIZE_OLD:
1866 if(ivideo->warncount++ < 10)
1867 printk(KERN_INFO
1868 "sisfb: Deprecated ioctl call received - update your application!\n");
1869 case SISFB_GET_AUTOMAXIMIZE:
1870 if(ivideo->sisfb_max)
1871 return put_user((u32)1, argp);
1872 else
1873 return put_user((u32)0, argp);
1875 case SISFB_SET_AUTOMAXIMIZE_OLD:
1876 if(ivideo->warncount++ < 10)
1877 printk(KERN_INFO
1878 "sisfb: Deprecated ioctl call received - update your application!\n");
1879 case SISFB_SET_AUTOMAXIMIZE:
1880 if(get_user(gpu32, argp))
1881 return -EFAULT;
1883 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1884 break;
1886 case SISFB_SET_TVPOSOFFSET:
1887 if(get_user(gpu32, argp))
1888 return -EFAULT;
1890 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1891 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1892 break;
1894 case SISFB_GET_TVPOSOFFSET:
1895 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1896 argp);
1898 case SISFB_COMMAND:
1899 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1900 sizeof(struct sisfb_cmd)))
1901 return -EFAULT;
1903 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1905 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1906 sizeof(struct sisfb_cmd)))
1907 return -EFAULT;
1909 break;
1911 case SISFB_SET_LOCK:
1912 if(get_user(gpu32, argp))
1913 return -EFAULT;
1915 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1916 break;
1918 default:
1919 #ifdef SIS_NEW_CONFIG_COMPAT
1920 return -ENOIOCTLCMD;
1921 #else
1922 return -EINVAL;
1923 #endif
1925 return 0;
1928 static int
1929 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1931 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1933 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1935 strcpy(fix->id, ivideo->myid);
1937 fix->smem_start = ivideo->video_base + ivideo->video_offset;
1938 fix->smem_len = ivideo->sisfb_mem;
1939 fix->type = FB_TYPE_PACKED_PIXELS;
1940 fix->type_aux = 0;
1941 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1942 fix->xpanstep = 1;
1943 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1944 fix->ywrapstep = 0;
1945 fix->line_length = ivideo->video_linelength;
1946 fix->mmio_start = ivideo->mmio_base;
1947 fix->mmio_len = ivideo->mmio_size;
1948 if(ivideo->sisvga_engine == SIS_300_VGA) {
1949 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1950 } else if((ivideo->chip == SIS_330) ||
1951 (ivideo->chip == SIS_760) ||
1952 (ivideo->chip == SIS_761)) {
1953 fix->accel = FB_ACCEL_SIS_XABRE;
1954 } else if(ivideo->chip == XGI_20) {
1955 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1956 } else if(ivideo->chip >= XGI_40) {
1957 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1958 } else {
1959 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1962 return 0;
1965 /* ---------------- fb_ops structures ----------------- */
1967 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1968 static struct fb_ops sisfb_ops = {
1969 .owner = THIS_MODULE,
1970 .fb_get_fix = sisfb_get_fix,
1971 .fb_get_var = sisfb_get_var,
1972 .fb_set_var = sisfb_set_var,
1973 .fb_get_cmap = sisfb_get_cmap,
1974 .fb_set_cmap = sisfb_set_cmap,
1975 .fb_pan_display = sisfb_pan_display,
1976 .fb_ioctl = sisfb_ioctl
1978 #endif
1980 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1981 static struct fb_ops sisfb_ops = {
1982 .owner = THIS_MODULE,
1983 .fb_open = sisfb_open,
1984 .fb_release = sisfb_release,
1985 .fb_check_var = sisfb_check_var,
1986 .fb_set_par = sisfb_set_par,
1987 .fb_setcolreg = sisfb_setcolreg,
1988 .fb_pan_display = sisfb_pan_display,
1989 .fb_blank = sisfb_blank,
1990 .fb_fillrect = fbcon_sis_fillrect,
1991 .fb_copyarea = fbcon_sis_copyarea,
1992 .fb_imageblit = cfb_imageblit,
1993 #ifdef CONFIG_FB_SOFT_CURSOR
1994 .fb_cursor = soft_cursor,
1995 #endif
1996 .fb_sync = fbcon_sis_sync,
1997 #ifdef SIS_NEW_CONFIG_COMPAT
1998 .fb_compat_ioctl= sisfb_ioctl,
1999 #endif
2000 .fb_ioctl = sisfb_ioctl
2002 #endif
2004 /* ---------------- Chip generation dependent routines ---------------- */
2006 static struct pci_dev * __devinit
2007 sisfb_get_northbridge(int basechipid)
2009 struct pci_dev *pdev = NULL;
2010 int nbridgenum, nbridgeidx, i;
2011 static const unsigned short nbridgeids[] = {
2012 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2013 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2014 PCI_DEVICE_ID_SI_730,
2015 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2016 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2017 PCI_DEVICE_ID_SI_651,
2018 PCI_DEVICE_ID_SI_740,
2019 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
2020 PCI_DEVICE_ID_SI_741,
2021 PCI_DEVICE_ID_SI_660,
2022 PCI_DEVICE_ID_SI_760,
2023 PCI_DEVICE_ID_SI_761
2026 switch(basechipid) {
2027 #ifdef CONFIG_FB_SIS_300
2028 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2029 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2030 #endif
2031 #ifdef CONFIG_FB_SIS_315
2032 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2033 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
2034 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
2035 #endif
2036 default: return NULL;
2038 for(i = 0; i < nbridgenum; i++) {
2039 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2040 nbridgeids[nbridgeidx+i], NULL)))
2041 break;
2043 return pdev;
2046 static int __devinit
2047 sisfb_get_dram_size(struct sis_video_info *ivideo)
2049 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2050 u8 reg;
2051 #endif
2053 ivideo->video_size = 0;
2054 ivideo->UMAsize = ivideo->LFBsize = 0;
2056 switch(ivideo->chip) {
2057 #ifdef CONFIG_FB_SIS_300
2058 case SIS_300:
2059 inSISIDXREG(SISSR, 0x14, reg);
2060 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2061 break;
2062 case SIS_540:
2063 case SIS_630:
2064 case SIS_730:
2065 if(!ivideo->nbridge)
2066 return -1;
2067 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
2068 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2069 break;
2070 #endif
2071 #ifdef CONFIG_FB_SIS_315
2072 case SIS_315H:
2073 case SIS_315PRO:
2074 case SIS_315:
2075 inSISIDXREG(SISSR, 0x14, reg);
2076 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2077 switch((reg >> 2) & 0x03) {
2078 case 0x01:
2079 case 0x03:
2080 ivideo->video_size <<= 1;
2081 break;
2082 case 0x02:
2083 ivideo->video_size += (ivideo->video_size/2);
2085 break;
2086 case SIS_330:
2087 inSISIDXREG(SISSR, 0x14, reg);
2088 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2089 if(reg & 0x0c) ivideo->video_size <<= 1;
2090 break;
2091 case SIS_550:
2092 case SIS_650:
2093 case SIS_740:
2094 inSISIDXREG(SISSR, 0x14, reg);
2095 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2096 break;
2097 case SIS_661:
2098 case SIS_741:
2099 inSISIDXREG(SISCR, 0x79, reg);
2100 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2101 break;
2102 case SIS_660:
2103 case SIS_760:
2104 case SIS_761:
2105 inSISIDXREG(SISCR, 0x79, reg);
2106 reg = (reg & 0xf0) >> 4;
2107 if(reg) {
2108 ivideo->video_size = (1 << reg) << 20;
2109 ivideo->UMAsize = ivideo->video_size;
2111 inSISIDXREG(SISCR, 0x78, reg);
2112 reg &= 0x30;
2113 if(reg) {
2114 if(reg == 0x10) {
2115 ivideo->LFBsize = (32 << 20);
2116 } else {
2117 ivideo->LFBsize = (64 << 20);
2119 ivideo->video_size += ivideo->LFBsize;
2121 break;
2122 case SIS_340:
2123 case XGI_20:
2124 case XGI_40:
2125 inSISIDXREG(SISSR, 0x14, reg);
2126 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2127 if(ivideo->chip != XGI_20) {
2128 reg = (reg & 0x0c) >> 2;
2129 if(ivideo->revision_id == 2) {
2130 if(reg & 0x01) reg = 0x02;
2131 else reg = 0x00;
2133 if(reg == 0x02) ivideo->video_size <<= 1;
2134 else if(reg == 0x03) ivideo->video_size <<= 2;
2136 break;
2137 #endif
2138 default:
2139 return -1;
2141 return 0;
2144 /* -------------- video bridge device detection --------------- */
2146 static void __devinit
2147 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2149 u8 cr32, temp;
2151 /* No CRT2 on XGI Z7 */
2152 if(ivideo->chip == XGI_20) {
2153 ivideo->sisfb_crt1off = 0;
2154 return;
2157 #ifdef CONFIG_FB_SIS_300
2158 if(ivideo->sisvga_engine == SIS_300_VGA) {
2159 inSISIDXREG(SISSR, 0x17, temp);
2160 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2161 /* PAL/NTSC is stored on SR16 on such machines */
2162 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2163 inSISIDXREG(SISSR, 0x16, temp);
2164 if(temp & 0x20)
2165 ivideo->vbflags |= TV_PAL;
2166 else
2167 ivideo->vbflags |= TV_NTSC;
2171 #endif
2173 inSISIDXREG(SISCR, 0x32, cr32);
2175 if(cr32 & SIS_CRT1) {
2176 ivideo->sisfb_crt1off = 0;
2177 } else {
2178 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2181 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2183 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2184 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2185 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2187 /* Check given parms for hardware compatibility.
2188 * (Cannot do this in the search_xx routines since we don't
2189 * know what hardware we are running on then)
2192 if(ivideo->chip != SIS_550) {
2193 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2196 if(ivideo->sisfb_tvplug != -1) {
2197 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2198 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2199 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2200 ivideo->sisfb_tvplug = -1;
2201 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2205 if(ivideo->sisfb_tvplug != -1) {
2206 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2207 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2208 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2209 ivideo->sisfb_tvplug = -1;
2210 printk(KERN_ERR "sisfb: HiVision not supported\n");
2214 if(ivideo->sisfb_tvstd != -1) {
2215 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2216 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2217 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2218 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2219 ivideo->sisfb_tvstd = -1;
2220 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2225 /* Detect/set TV plug & type */
2226 if(ivideo->sisfb_tvplug != -1) {
2227 ivideo->vbflags |= ivideo->sisfb_tvplug;
2228 } else {
2229 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2230 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2231 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2232 else {
2233 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2234 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2238 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2239 if(ivideo->sisfb_tvstd != -1) {
2240 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2241 ivideo->vbflags |= ivideo->sisfb_tvstd;
2243 if(ivideo->vbflags & TV_SCART) {
2244 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2245 ivideo->vbflags |= TV_PAL;
2247 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2248 if(ivideo->sisvga_engine == SIS_300_VGA) {
2249 inSISIDXREG(SISSR, 0x38, temp);
2250 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2251 else ivideo->vbflags |= TV_NTSC;
2252 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2253 inSISIDXREG(SISSR, 0x38, temp);
2254 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2255 else ivideo->vbflags |= TV_NTSC;
2256 } else {
2257 inSISIDXREG(SISCR, 0x79, temp);
2258 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2259 else ivideo->vbflags |= TV_NTSC;
2264 /* Copy forceCRT1 option to CRT1off if option is given */
2265 if(ivideo->sisfb_forcecrt1 != -1) {
2266 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2270 /* ------------------ Sensing routines ------------------ */
2272 static BOOLEAN __devinit
2273 sisfb_test_DDC1(struct sis_video_info *ivideo)
2275 unsigned short old;
2276 int count = 48;
2278 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2279 do {
2280 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2281 } while(count--);
2282 return (count == -1) ? FALSE : TRUE;
2285 static void __devinit
2286 sisfb_sense_crt1(struct sis_video_info *ivideo)
2288 BOOLEAN mustwait = FALSE;
2289 u8 sr1F, cr17;
2290 #ifdef CONFIG_FB_SIS_315
2291 u8 cr63=0;
2292 #endif
2293 u16 temp = 0xffff;
2294 int i;
2296 inSISIDXREG(SISSR,0x1F,sr1F);
2297 orSISIDXREG(SISSR,0x1F,0x04);
2298 andSISIDXREG(SISSR,0x1F,0x3F);
2299 if(sr1F & 0xc0) mustwait = TRUE;
2301 #ifdef CONFIG_FB_SIS_315
2302 if(ivideo->sisvga_engine == SIS_315_VGA) {
2303 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2304 cr63 &= 0x40;
2305 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2307 #endif
2309 inSISIDXREG(SISCR,0x17,cr17);
2310 cr17 &= 0x80;
2311 if(!cr17) {
2312 orSISIDXREG(SISCR,0x17,0x80);
2313 mustwait = TRUE;
2314 outSISIDXREG(SISSR, 0x00, 0x01);
2315 outSISIDXREG(SISSR, 0x00, 0x03);
2318 if(mustwait) {
2319 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2322 #ifdef CONFIG_FB_SIS_315
2323 if(ivideo->chip >= SIS_330) {
2324 andSISIDXREG(SISCR,0x32,~0x20);
2325 if(ivideo->chip >= SIS_340) {
2326 outSISIDXREG(SISCR, 0x57, 0x4a);
2327 } else {
2328 outSISIDXREG(SISCR, 0x57, 0x5f);
2330 orSISIDXREG(SISCR, 0x53, 0x02);
2331 while((inSISREG(SISINPSTAT)) & 0x01) break;
2332 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2333 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2334 andSISIDXREG(SISCR, 0x53, 0xfd);
2335 andSISIDXREG(SISCR, 0x57, 0x00);
2337 #endif
2339 if(temp == 0xffff) {
2340 i = 3;
2341 do {
2342 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2343 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2344 } while(((temp == 0) || (temp == 0xffff)) && i--);
2346 if((temp == 0) || (temp == 0xffff)) {
2347 if(sisfb_test_DDC1(ivideo)) temp = 1;
2351 if((temp) && (temp != 0xffff)) {
2352 orSISIDXREG(SISCR,0x32,0x20);
2355 #ifdef CONFIG_FB_SIS_315
2356 if(ivideo->sisvga_engine == SIS_315_VGA) {
2357 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2359 #endif
2361 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2363 outSISIDXREG(SISSR,0x1F,sr1F);
2366 /* Determine and detect attached devices on SiS30x */
2367 static void __devinit
2368 SiS_SenseLCD(struct sis_video_info *ivideo)
2370 unsigned char buffer[256];
2371 unsigned short temp, realcrtno, i;
2372 u8 reg, cr37 = 0, paneltype = 0;
2373 u16 xres, yres;
2375 ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2377 /* LCD detection only for TMDS bridges */
2378 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2379 return;
2380 if(ivideo->vbflags2 & VB2_30xBDH)
2381 return;
2383 /* If LCD already set up by BIOS, skip it */
2384 inSISIDXREG(SISCR, 0x32, reg);
2385 if(reg & 0x08)
2386 return;
2388 realcrtno = 1;
2389 if(ivideo->SiS_Pr.DDCPortMixup)
2390 realcrtno = 0;
2392 /* Check DDC capabilities */
2393 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2394 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2396 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2397 return;
2399 /* Read DDC data */
2400 i = 3; /* Number of retrys */
2401 do {
2402 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2403 ivideo->sisvga_engine, realcrtno, 1,
2404 &buffer[0], ivideo->vbflags2);
2405 } while((temp) && i--);
2407 if(temp)
2408 return;
2410 /* No digital device */
2411 if(!(buffer[0x14] & 0x80))
2412 return;
2414 /* First detailed timing preferred timing? */
2415 if(!(buffer[0x18] & 0x02))
2416 return;
2418 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2419 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2421 switch(xres) {
2422 case 1024:
2423 if(yres == 768)
2424 paneltype = 0x02;
2425 break;
2426 case 1280:
2427 if(yres == 1024)
2428 paneltype = 0x03;
2429 break;
2430 case 1600:
2431 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2432 paneltype = 0x0b;
2433 break;
2436 if(!paneltype)
2437 return;
2439 if(buffer[0x23])
2440 cr37 |= 0x10;
2442 if((buffer[0x47] & 0x18) == 0x18)
2443 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2444 else
2445 cr37 |= 0xc0;
2447 outSISIDXREG(SISCR, 0x36, paneltype);
2448 cr37 &= 0xf1;
2449 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2450 orSISIDXREG(SISCR, 0x32, 0x08);
2452 ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2455 static int __devinit
2456 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2458 int temp, mytest, result, i, j;
2460 for(j = 0; j < 10; j++) {
2461 result = 0;
2462 for(i = 0; i < 3; i++) {
2463 mytest = test;
2464 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2465 temp = (type >> 8) | (mytest & 0x00ff);
2466 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2467 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2468 mytest >>= 8;
2469 mytest &= 0x7f;
2470 inSISIDXREG(SISPART4,0x03,temp);
2471 temp ^= 0x0e;
2472 temp &= mytest;
2473 if(temp == mytest) result++;
2474 #if 1
2475 outSISIDXREG(SISPART4,0x11,0x00);
2476 andSISIDXREG(SISPART4,0x10,0xe0);
2477 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2478 #endif
2480 if((result == 0) || (result >= 2)) break;
2482 return result;
2485 static void __devinit
2486 SiS_Sense30x(struct sis_video_info *ivideo)
2488 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2489 u16 svhs=0, svhs_c=0;
2490 u16 cvbs=0, cvbs_c=0;
2491 u16 vga2=0, vga2_c=0;
2492 int myflag, result;
2493 char stdstr[] = "sisfb: Detected";
2494 char tvstr[] = "TV connected to";
2496 if(ivideo->vbflags2 & VB2_301) {
2497 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2498 inSISIDXREG(SISPART4,0x01,myflag);
2499 if(myflag & 0x04) {
2500 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2502 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2503 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2504 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2505 svhs = 0x0200; cvbs = 0x0100;
2506 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2507 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2508 } else
2509 return;
2511 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2512 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2513 svhs_c = 0x0408; cvbs_c = 0x0808;
2516 biosflag = 2;
2517 if(ivideo->haveXGIROM) {
2518 biosflag = ivideo->bios_abase[0x58] & 0x03;
2519 } else if(ivideo->newrom) {
2520 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2521 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2522 if(ivideo->bios_abase) {
2523 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2527 if(ivideo->chip == SIS_300) {
2528 inSISIDXREG(SISSR,0x3b,myflag);
2529 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2532 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2533 vga2 = vga2_c = 0;
2536 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2537 orSISIDXREG(SISSR,0x1e,0x20);
2539 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2540 if(ivideo->vbflags2 & VB2_30xC) {
2541 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2542 } else {
2543 orSISIDXREG(SISPART4,0x0d,0x04);
2545 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2547 inSISIDXREG(SISPART2,0x00,backupP2_00);
2548 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2550 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2551 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2552 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2555 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2556 SISDoSense(ivideo, 0, 0);
2559 andSISIDXREG(SISCR, 0x32, ~0x14);
2561 if(vga2_c || vga2) {
2562 if(SISDoSense(ivideo, vga2, vga2_c)) {
2563 if(biosflag & 0x01) {
2564 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2565 orSISIDXREG(SISCR, 0x32, 0x04);
2566 } else {
2567 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2568 orSISIDXREG(SISCR, 0x32, 0x10);
2573 andSISIDXREG(SISCR, 0x32, 0x3f);
2575 if(ivideo->vbflags2 & VB2_30xCLV) {
2576 orSISIDXREG(SISPART4,0x0d,0x04);
2579 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2580 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2581 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2582 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2583 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2584 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2585 orSISIDXREG(SISCR,0x32,0x80);
2588 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2591 andSISIDXREG(SISCR, 0x32, ~0x03);
2593 if(!(ivideo->vbflags & TV_YPBPR)) {
2594 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2595 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2596 orSISIDXREG(SISCR, 0x32, 0x02);
2598 if((biosflag & 0x02) || (!result)) {
2599 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2600 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2601 orSISIDXREG(SISCR, 0x32, 0x01);
2606 SISDoSense(ivideo, 0, 0);
2608 outSISIDXREG(SISPART2,0x00,backupP2_00);
2609 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2610 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2612 if(ivideo->vbflags2 & VB2_30xCLV) {
2613 inSISIDXREG(SISPART2,0x00,biosflag);
2614 if(biosflag & 0x20) {
2615 for(myflag = 2; myflag > 0; myflag--) {
2616 biosflag ^= 0x20;
2617 outSISIDXREG(SISPART2,0x00,biosflag);
2622 outSISIDXREG(SISPART2,0x00,backupP2_00);
2625 /* Determine and detect attached TV's on Chrontel */
2626 static void __devinit
2627 SiS_SenseCh(struct sis_video_info *ivideo)
2629 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2630 u8 temp1, temp2;
2631 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2632 #endif
2633 #ifdef CONFIG_FB_SIS_300
2634 unsigned char test[3];
2635 int i;
2636 #endif
2638 if(ivideo->chip < SIS_315H) {
2640 #ifdef CONFIG_FB_SIS_300
2641 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2642 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2643 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2644 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2645 /* See Chrontel TB31 for explanation */
2646 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2647 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2648 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2649 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2651 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2652 if(temp2 != temp1) temp1 = temp2;
2654 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2655 /* Read power status */
2656 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2657 if((temp1 & 0x03) != 0x03) {
2658 /* Power all outputs */
2659 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2660 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2662 /* Sense connected TV devices */
2663 for(i = 0; i < 3; i++) {
2664 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2665 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2666 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2667 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2668 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2669 if(!(temp1 & 0x08)) test[i] = 0x02;
2670 else if(!(temp1 & 0x02)) test[i] = 0x01;
2671 else test[i] = 0;
2672 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2675 if(test[0] == test[1]) temp1 = test[0];
2676 else if(test[0] == test[2]) temp1 = test[0];
2677 else if(test[1] == test[2]) temp1 = test[1];
2678 else {
2679 printk(KERN_INFO
2680 "sisfb: TV detection unreliable - test results varied\n");
2681 temp1 = test[2];
2683 if(temp1 == 0x02) {
2684 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2685 ivideo->vbflags |= TV_SVIDEO;
2686 orSISIDXREG(SISCR, 0x32, 0x02);
2687 andSISIDXREG(SISCR, 0x32, ~0x05);
2688 } else if (temp1 == 0x01) {
2689 printk(KERN_INFO "%s CVBS output\n", stdstr);
2690 ivideo->vbflags |= TV_AVIDEO;
2691 orSISIDXREG(SISCR, 0x32, 0x01);
2692 andSISIDXREG(SISCR, 0x32, ~0x06);
2693 } else {
2694 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2695 andSISIDXREG(SISCR, 0x32, ~0x07);
2697 } else if(temp1 == 0) {
2698 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2699 andSISIDXREG(SISCR, 0x32, ~0x07);
2701 /* Set general purpose IO for Chrontel communication */
2702 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2703 #endif
2705 } else {
2707 #ifdef CONFIG_FB_SIS_315
2708 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2709 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2710 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2711 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2712 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2713 temp2 |= 0x01;
2714 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2715 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2716 temp2 ^= 0x01;
2717 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2718 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2719 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2720 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2721 temp1 = 0;
2722 if(temp2 & 0x02) temp1 |= 0x01;
2723 if(temp2 & 0x10) temp1 |= 0x01;
2724 if(temp2 & 0x04) temp1 |= 0x02;
2725 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2726 switch(temp1) {
2727 case 0x01:
2728 printk(KERN_INFO "%s CVBS output\n", stdstr);
2729 ivideo->vbflags |= TV_AVIDEO;
2730 orSISIDXREG(SISCR, 0x32, 0x01);
2731 andSISIDXREG(SISCR, 0x32, ~0x06);
2732 break;
2733 case 0x02:
2734 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2735 ivideo->vbflags |= TV_SVIDEO;
2736 orSISIDXREG(SISCR, 0x32, 0x02);
2737 andSISIDXREG(SISCR, 0x32, ~0x05);
2738 break;
2739 case 0x04:
2740 printk(KERN_INFO "%s SCART output\n", stdstr);
2741 orSISIDXREG(SISCR, 0x32, 0x04);
2742 andSISIDXREG(SISCR, 0x32, ~0x03);
2743 break;
2744 default:
2745 andSISIDXREG(SISCR, 0x32, ~0x07);
2747 #endif
2751 static void __devinit
2752 sisfb_get_VB_type(struct sis_video_info *ivideo)
2754 char stdstr[] = "sisfb: Detected";
2755 char bridgestr[] = "video bridge";
2756 u8 vb_chipid;
2757 u8 reg;
2759 /* No CRT2 on XGI Z7 */
2760 if(ivideo->chip == XGI_20)
2761 return;
2763 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2764 switch(vb_chipid) {
2765 case 0x01:
2766 inSISIDXREG(SISPART4, 0x01, reg);
2767 if(reg < 0xb0) {
2768 ivideo->vbflags |= VB_301; /* Deprecated */
2769 ivideo->vbflags2 |= VB2_301;
2770 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2771 } else if(reg < 0xc0) {
2772 ivideo->vbflags |= VB_301B; /* Deprecated */
2773 ivideo->vbflags2 |= VB2_301B;
2774 inSISIDXREG(SISPART4,0x23,reg);
2775 if(!(reg & 0x02)) {
2776 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2777 ivideo->vbflags2 |= VB2_30xBDH;
2778 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2779 } else {
2780 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2782 } else if(reg < 0xd0) {
2783 ivideo->vbflags |= VB_301C; /* Deprecated */
2784 ivideo->vbflags2 |= VB2_301C;
2785 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2786 } else if(reg < 0xe0) {
2787 ivideo->vbflags |= VB_301LV; /* Deprecated */
2788 ivideo->vbflags2 |= VB2_301LV;
2789 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2790 } else if(reg <= 0xe1) {
2791 inSISIDXREG(SISPART4,0x39,reg);
2792 if(reg == 0xff) {
2793 ivideo->vbflags |= VB_302LV; /* Deprecated */
2794 ivideo->vbflags2 |= VB2_302LV;
2795 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2796 } else {
2797 ivideo->vbflags |= VB_301C; /* Deprecated */
2798 ivideo->vbflags2 |= VB2_301C;
2799 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2800 #if 0
2801 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2802 ivideo->vbflags2 |= VB2_302ELV;
2803 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2804 #endif
2807 break;
2808 case 0x02:
2809 ivideo->vbflags |= VB_302B; /* Deprecated */
2810 ivideo->vbflags2 |= VB2_302B;
2811 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2812 break;
2815 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2816 inSISIDXREG(SISCR, 0x37, reg);
2817 reg &= SIS_EXTERNAL_CHIP_MASK;
2818 reg >>= 1;
2819 if(ivideo->sisvga_engine == SIS_300_VGA) {
2820 #ifdef CONFIG_FB_SIS_300
2821 switch(reg) {
2822 case SIS_EXTERNAL_CHIP_LVDS:
2823 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2824 ivideo->vbflags2 |= VB2_LVDS;
2825 break;
2826 case SIS_EXTERNAL_CHIP_TRUMPION:
2827 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2828 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2829 break;
2830 case SIS_EXTERNAL_CHIP_CHRONTEL:
2831 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2832 ivideo->vbflags2 |= VB2_CHRONTEL;
2833 break;
2834 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2835 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2836 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2837 break;
2839 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2840 #endif
2841 } else if(ivideo->chip < SIS_661) {
2842 #ifdef CONFIG_FB_SIS_315
2843 switch (reg) {
2844 case SIS310_EXTERNAL_CHIP_LVDS:
2845 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2846 ivideo->vbflags2 |= VB2_LVDS;
2847 break;
2848 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2849 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2850 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2851 break;
2853 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2854 #endif
2855 } else if(ivideo->chip >= SIS_661) {
2856 #ifdef CONFIG_FB_SIS_315
2857 inSISIDXREG(SISCR, 0x38, reg);
2858 reg >>= 5;
2859 switch(reg) {
2860 case 0x02:
2861 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2862 ivideo->vbflags2 |= VB2_LVDS;
2863 break;
2864 case 0x03:
2865 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2866 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2867 break;
2868 case 0x04:
2869 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2870 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2871 break;
2873 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2874 #endif
2876 if(ivideo->vbflags2 & VB2_LVDS) {
2877 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2879 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2880 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2882 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2883 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2885 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2886 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2890 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2891 SiS_SenseLCD(ivideo);
2892 SiS_Sense30x(ivideo);
2893 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2894 SiS_SenseCh(ivideo);
2898 /* ---------- Engine initialization routines ------------ */
2900 static void
2901 sisfb_engine_init(struct sis_video_info *ivideo)
2904 /* Initialize command queue (we use MMIO only) */
2906 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2908 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2909 MMIO_CMD_QUEUE_CAP |
2910 VM_CMD_QUEUE_CAP |
2911 AGP_CMD_QUEUE_CAP);
2913 #ifdef CONFIG_FB_SIS_300
2914 if(ivideo->sisvga_engine == SIS_300_VGA) {
2915 u32 tqueue_pos;
2916 u8 tq_state;
2918 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2920 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2921 tq_state |= 0xf0;
2922 tq_state &= 0xfc;
2923 tq_state |= (u8)(tqueue_pos >> 8);
2924 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2926 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2928 ivideo->caps |= TURBO_QUEUE_CAP;
2930 #endif
2932 #ifdef CONFIG_FB_SIS_315
2933 if(ivideo->sisvga_engine == SIS_315_VGA) {
2934 u32 tempq = 0, templ;
2935 u8 temp;
2937 if(ivideo->chip == XGI_20) {
2938 switch(ivideo->cmdQueueSize) {
2939 case (64 * 1024):
2940 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2941 break;
2942 case (128 * 1024):
2943 default:
2944 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2946 } else {
2947 switch(ivideo->cmdQueueSize) {
2948 case (4 * 1024 * 1024):
2949 temp = SIS_CMD_QUEUE_SIZE_4M;
2950 break;
2951 case (2 * 1024 * 1024):
2952 temp = SIS_CMD_QUEUE_SIZE_2M;
2953 break;
2954 case (1 * 1024 * 1024):
2955 temp = SIS_CMD_QUEUE_SIZE_1M;
2956 break;
2957 default:
2958 case (512 * 1024):
2959 temp = SIS_CMD_QUEUE_SIZE_512k;
2963 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2964 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2966 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2967 /* Must disable dual pipe on XGI_40. Can't do
2968 * this in MMIO mode, because it requires
2969 * setting/clearing a bit in the MMIO fire trigger
2970 * register.
2972 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2974 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2976 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2978 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2979 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2981 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2982 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2984 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2985 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2986 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2987 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2989 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2991 sisfb_syncaccel(ivideo);
2993 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2998 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2999 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3001 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3002 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3004 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3005 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3007 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3009 #endif
3011 ivideo->engineok = 1;
3014 static void __devinit
3015 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3017 u8 reg;
3018 int i;
3020 inSISIDXREG(SISCR, 0x36, reg);
3021 reg &= 0x0f;
3022 if(ivideo->sisvga_engine == SIS_300_VGA) {
3023 ivideo->CRT2LCDType = sis300paneltype[reg];
3024 } else if(ivideo->chip >= SIS_661) {
3025 ivideo->CRT2LCDType = sis661paneltype[reg];
3026 } else {
3027 ivideo->CRT2LCDType = sis310paneltype[reg];
3028 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3029 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3030 (ivideo->CRT2LCDType != LCD_320x240_3)) {
3031 ivideo->CRT2LCDType = LCD_320x240;
3036 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3037 /* For broken BIOSes: Assume 1024x768, RGB18 */
3038 ivideo->CRT2LCDType = LCD_1024x768;
3039 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3040 setSISIDXREG(SISCR,0x37,0xee,0x01);
3041 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3044 for(i = 0; i < SIS_LCD_NUMBER; i++) {
3045 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3046 ivideo->lcdxres = sis_lcd_data[i].xres;
3047 ivideo->lcdyres = sis_lcd_data[i].yres;
3048 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3049 break;
3053 #ifdef CONFIG_FB_SIS_300
3054 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3055 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3056 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3057 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3058 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
3059 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3060 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3061 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
3062 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3064 #endif
3066 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3067 ivideo->lcdxres, ivideo->lcdyres);
3070 static void __devinit
3071 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3073 #ifdef CONFIG_FB_SIS_300
3074 /* Save the current PanelDelayCompensation if the LCD is currently used */
3075 if(ivideo->sisvga_engine == SIS_300_VGA) {
3076 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3077 int tmp;
3078 inSISIDXREG(SISCR,0x30,tmp);
3079 if(tmp & 0x20) {
3080 /* Currently on LCD? If yes, read current pdc */
3081 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3082 ivideo->detectedpdc &= 0x3c;
3083 if(ivideo->SiS_Pr.PDC == -1) {
3084 /* Let option override detection */
3085 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3087 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3088 ivideo->detectedpdc);
3090 if((ivideo->SiS_Pr.PDC != -1) &&
3091 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3092 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3093 ivideo->SiS_Pr.PDC);
3097 #endif
3099 #ifdef CONFIG_FB_SIS_315
3100 if(ivideo->sisvga_engine == SIS_315_VGA) {
3102 /* Try to find about LCDA */
3103 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3104 int tmp;
3105 inSISIDXREG(SISPART1,0x13,tmp);
3106 if(tmp & 0x04) {
3107 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3108 ivideo->detectedlcda = 0x03;
3112 /* Save PDC */
3113 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3114 int tmp;
3115 inSISIDXREG(SISCR,0x30,tmp);
3116 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3117 /* Currently on LCD? If yes, read current pdc */
3118 u8 pdc;
3119 inSISIDXREG(SISPART1,0x2D,pdc);
3120 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3121 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3122 inSISIDXREG(SISPART1,0x35,pdc);
3123 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3124 inSISIDXREG(SISPART1,0x20,pdc);
3125 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3126 if(ivideo->newrom) {
3127 /* New ROM invalidates other PDC resp. */
3128 if(ivideo->detectedlcda != 0xff) {
3129 ivideo->detectedpdc = 0xff;
3130 } else {
3131 ivideo->detectedpdca = 0xff;
3134 if(ivideo->SiS_Pr.PDC == -1) {
3135 if(ivideo->detectedpdc != 0xff) {
3136 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3139 if(ivideo->SiS_Pr.PDCA == -1) {
3140 if(ivideo->detectedpdca != 0xff) {
3141 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3144 if(ivideo->detectedpdc != 0xff) {
3145 printk(KERN_INFO
3146 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3147 ivideo->detectedpdc);
3149 if(ivideo->detectedpdca != 0xff) {
3150 printk(KERN_INFO
3151 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3152 ivideo->detectedpdca);
3156 /* Save EMI */
3157 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3158 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3159 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3160 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3161 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3162 ivideo->SiS_Pr.HaveEMI = TRUE;
3163 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3164 ivideo->SiS_Pr.HaveEMILCD = TRUE;
3169 /* Let user override detected PDCs (all bridges) */
3170 if(ivideo->vbflags2 & VB2_30xBLV) {
3171 if((ivideo->SiS_Pr.PDC != -1) &&
3172 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3173 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3174 ivideo->SiS_Pr.PDC);
3176 if((ivideo->SiS_Pr.PDCA != -1) &&
3177 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3178 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3179 ivideo->SiS_Pr.PDCA);
3184 #endif
3187 /* -------------------- Memory manager routines ---------------------- */
3189 static u32 __devinit
3190 sisfb_getheapstart(struct sis_video_info *ivideo)
3192 u32 ret = ivideo->sisfb_parm_mem * 1024;
3193 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3194 u32 def;
3196 /* Calculate heap start = end of memory for console
3198 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3199 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3201 * On 76x in UMA+LFB mode, the layout is as follows:
3202 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3203 * where the heap is the entire UMA area, eventually
3204 * into the LFB area if the given mem parameter is
3205 * higher than the size of the UMA memory.
3207 * Basically given by "mem" parameter
3209 * maximum = videosize - cmd_queue - hwcursor
3210 * (results in a heap of size 0)
3211 * default = SiS 300: depends on videosize
3212 * SiS 315/330/340/XGI: 32k below max
3215 if(ivideo->sisvga_engine == SIS_300_VGA) {
3216 if(ivideo->video_size > 0x1000000) {
3217 def = 0xc00000;
3218 } else if(ivideo->video_size > 0x800000) {
3219 def = 0x800000;
3220 } else {
3221 def = 0x400000;
3223 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3224 ret = def = 0;
3225 } else {
3226 def = maxoffs - 0x8000;
3229 /* Use default for secondary card for now (FIXME) */
3230 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3231 ret = def;
3233 return ret;
3236 static u32 __devinit
3237 sisfb_getheapsize(struct sis_video_info *ivideo)
3239 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3240 u32 ret = 0;
3242 if(ivideo->UMAsize && ivideo->LFBsize) {
3243 if( (!ivideo->sisfb_parm_mem) ||
3244 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3245 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3246 ret = ivideo->UMAsize;
3247 max -= ivideo->UMAsize;
3248 } else {
3249 ret = max - (ivideo->sisfb_parm_mem * 1024);
3250 max = ivideo->sisfb_parm_mem * 1024;
3252 ivideo->video_offset = ret;
3253 ivideo->sisfb_mem = max;
3254 } else {
3255 ret = max - ivideo->heapstart;
3256 ivideo->sisfb_mem = ivideo->heapstart;
3259 return ret;
3262 static int __devinit
3263 sisfb_heap_init(struct sis_video_info *ivideo)
3265 struct SIS_OH *poh;
3267 ivideo->video_offset = 0;
3268 if(ivideo->sisfb_parm_mem) {
3269 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3270 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3271 ivideo->sisfb_parm_mem = 0;
3275 ivideo->heapstart = sisfb_getheapstart(ivideo);
3276 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3278 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3279 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3281 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3282 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3284 ivideo->sisfb_heap.vinfo = ivideo;
3286 ivideo->sisfb_heap.poha_chain = NULL;
3287 ivideo->sisfb_heap.poh_freelist = NULL;
3289 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3290 if(poh == NULL)
3291 return 1;
3293 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3294 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3295 poh->size = ivideo->sisfb_heap_size;
3296 poh->offset = ivideo->heapstart;
3298 ivideo->sisfb_heap.oh_free.poh_next = poh;
3299 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3300 ivideo->sisfb_heap.oh_free.size = 0;
3301 ivideo->sisfb_heap.max_freesize = poh->size;
3303 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3304 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3305 ivideo->sisfb_heap.oh_used.size = SENTINEL;
3307 if(ivideo->cardnumber == 0) {
3308 /* For the first card, make this heap the "global" one
3309 * for old DRM (which could handle only one card)
3311 sisfb_heap = &ivideo->sisfb_heap;
3314 return 0;
3317 static struct SIS_OH *
3318 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3320 struct SIS_OHALLOC *poha;
3321 struct SIS_OH *poh;
3322 unsigned long cOhs;
3323 int i;
3325 if(memheap->poh_freelist == NULL) {
3326 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3327 if(!poha)
3328 return NULL;
3330 poha->poha_next = memheap->poha_chain;
3331 memheap->poha_chain = poha;
3333 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3335 poh = &poha->aoh[0];
3336 for(i = cOhs - 1; i != 0; i--) {
3337 poh->poh_next = poh + 1;
3338 poh = poh + 1;
3341 poh->poh_next = NULL;
3342 memheap->poh_freelist = &poha->aoh[0];
3345 poh = memheap->poh_freelist;
3346 memheap->poh_freelist = poh->poh_next;
3348 return poh;
3351 static struct SIS_OH *
3352 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3354 struct SIS_OH *pohThis;
3355 struct SIS_OH *pohRoot;
3356 int bAllocated = 0;
3358 if(size > memheap->max_freesize) {
3359 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3360 (unsigned int) size / 1024);
3361 return NULL;
3364 pohThis = memheap->oh_free.poh_next;
3366 while(pohThis != &memheap->oh_free) {
3367 if(size <= pohThis->size) {
3368 bAllocated = 1;
3369 break;
3371 pohThis = pohThis->poh_next;
3374 if(!bAllocated) {
3375 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3376 (unsigned int) size / 1024);
3377 return NULL;
3380 if(size == pohThis->size) {
3381 pohRoot = pohThis;
3382 sisfb_delete_node(pohThis);
3383 } else {
3384 pohRoot = sisfb_poh_new_node(memheap);
3385 if(pohRoot == NULL)
3386 return NULL;
3388 pohRoot->offset = pohThis->offset;
3389 pohRoot->size = size;
3391 pohThis->offset += size;
3392 pohThis->size -= size;
3395 memheap->max_freesize -= size;
3397 pohThis = &memheap->oh_used;
3398 sisfb_insert_node(pohThis, pohRoot);
3400 return pohRoot;
3403 static void
3404 sisfb_delete_node(struct SIS_OH *poh)
3406 poh->poh_prev->poh_next = poh->poh_next;
3407 poh->poh_next->poh_prev = poh->poh_prev;
3410 static void
3411 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3413 struct SIS_OH *pohTemp = pohList->poh_next;
3415 pohList->poh_next = poh;
3416 pohTemp->poh_prev = poh;
3418 poh->poh_prev = pohList;
3419 poh->poh_next = pohTemp;
3422 static struct SIS_OH *
3423 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3425 struct SIS_OH *pohThis;
3426 struct SIS_OH *poh_freed;
3427 struct SIS_OH *poh_prev;
3428 struct SIS_OH *poh_next;
3429 u32 ulUpper;
3430 u32 ulLower;
3431 int foundNode = 0;
3433 poh_freed = memheap->oh_used.poh_next;
3435 while(poh_freed != &memheap->oh_used) {
3436 if(poh_freed->offset == base) {
3437 foundNode = 1;
3438 break;
3441 poh_freed = poh_freed->poh_next;
3444 if(!foundNode)
3445 return NULL;
3447 memheap->max_freesize += poh_freed->size;
3449 poh_prev = poh_next = NULL;
3450 ulUpper = poh_freed->offset + poh_freed->size;
3451 ulLower = poh_freed->offset;
3453 pohThis = memheap->oh_free.poh_next;
3455 while(pohThis != &memheap->oh_free) {
3456 if(pohThis->offset == ulUpper) {
3457 poh_next = pohThis;
3458 } else if((pohThis->offset + pohThis->size) == ulLower) {
3459 poh_prev = pohThis;
3461 pohThis = pohThis->poh_next;
3464 sisfb_delete_node(poh_freed);
3466 if(poh_prev && poh_next) {
3467 poh_prev->size += (poh_freed->size + poh_next->size);
3468 sisfb_delete_node(poh_next);
3469 sisfb_free_node(memheap, poh_freed);
3470 sisfb_free_node(memheap, poh_next);
3471 return poh_prev;
3474 if(poh_prev) {
3475 poh_prev->size += poh_freed->size;
3476 sisfb_free_node(memheap, poh_freed);
3477 return poh_prev;
3480 if(poh_next) {
3481 poh_next->size += poh_freed->size;
3482 poh_next->offset = poh_freed->offset;
3483 sisfb_free_node(memheap, poh_freed);
3484 return poh_next;
3487 sisfb_insert_node(&memheap->oh_free, poh_freed);
3489 return poh_freed;
3492 static void
3493 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3495 if(poh == NULL)
3496 return;
3498 poh->poh_next = memheap->poh_freelist;
3499 memheap->poh_freelist = poh;
3502 static void
3503 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3505 struct SIS_OH *poh = NULL;
3507 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3508 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3510 if(poh == NULL) {
3511 req->offset = req->size = 0;
3512 DPRINTK("sisfb: Video RAM allocation failed\n");
3513 } else {
3514 req->offset = poh->offset;
3515 req->size = poh->size;
3516 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3517 (poh->offset + ivideo->video_vbase));
3521 void
3522 sis_malloc(struct sis_memreq *req)
3524 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3526 if(&ivideo->sisfb_heap == sisfb_heap)
3527 sis_int_malloc(ivideo, req);
3528 else
3529 req->offset = req->size = 0;
3532 void
3533 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3535 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3537 sis_int_malloc(ivideo, req);
3540 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3542 static void
3543 sis_int_free(struct sis_video_info *ivideo, u32 base)
3545 struct SIS_OH *poh;
3547 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3548 return;
3550 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3552 if(poh == NULL) {
3553 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3554 (unsigned int) base);
3558 void
3559 sis_free(u32 base)
3561 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3563 sis_int_free(ivideo, base);
3566 void
3567 sis_free_new(struct pci_dev *pdev, u32 base)
3569 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3571 sis_int_free(ivideo, base);
3574 /* --------------------- SetMode routines ------------------------- */
3576 static void
3577 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3579 u8 cr30, cr31;
3581 /* Check if MMIO and engines are enabled,
3582 * and sync in case they are. Can't use
3583 * ivideo->accel here, as this might have
3584 * been changed before this is called.
3586 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3587 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3588 /* MMIO and 2D/3D engine enabled? */
3589 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3590 #ifdef CONFIG_FB_SIS_300
3591 if(ivideo->sisvga_engine == SIS_300_VGA) {
3592 /* Don't care about TurboQueue. It's
3593 * enough to know that the engines
3594 * are enabled
3596 sisfb_syncaccel(ivideo);
3598 #endif
3599 #ifdef CONFIG_FB_SIS_315
3600 if(ivideo->sisvga_engine == SIS_315_VGA) {
3601 /* Check that any queue mode is
3602 * enabled, and that the queue
3603 * is not in the state of "reset"
3605 inSISIDXREG(SISSR, 0x26, cr30);
3606 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3607 sisfb_syncaccel(ivideo);
3610 #endif
3614 static void
3615 sisfb_pre_setmode(struct sis_video_info *ivideo)
3617 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3618 int tvregnum = 0;
3620 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3622 outSISIDXREG(SISSR, 0x05, 0x86);
3624 inSISIDXREG(SISCR, 0x31, cr31);
3625 cr31 &= ~0x60;
3626 cr31 |= 0x04;
3628 cr33 = ivideo->rate_idx & 0x0F;
3630 #ifdef CONFIG_FB_SIS_315
3631 if(ivideo->sisvga_engine == SIS_315_VGA) {
3632 if(ivideo->chip >= SIS_661) {
3633 inSISIDXREG(SISCR, 0x38, cr38);
3634 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3635 } else {
3636 tvregnum = 0x38;
3637 inSISIDXREG(SISCR, tvregnum, cr38);
3638 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3641 #endif
3642 #ifdef CONFIG_FB_SIS_300
3643 if(ivideo->sisvga_engine == SIS_300_VGA) {
3644 tvregnum = 0x35;
3645 inSISIDXREG(SISCR, tvregnum, cr38);
3647 #endif
3649 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3650 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3651 ivideo->curFSTN = ivideo->curDSTN = 0;
3653 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3655 case CRT2_TV:
3656 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3657 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3658 #ifdef CONFIG_FB_SIS_315
3659 if(ivideo->chip >= SIS_661) {
3660 cr38 |= 0x04;
3661 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3662 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3663 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3664 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3665 cr35 &= ~0x01;
3666 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3667 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3668 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3669 cr38 |= 0x08;
3670 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3671 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3672 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3673 cr31 &= ~0x01;
3674 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3676 #endif
3677 } else if((ivideo->vbflags & TV_HIVISION) &&
3678 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3679 if(ivideo->chip >= SIS_661) {
3680 cr38 |= 0x04;
3681 cr35 |= 0x60;
3682 } else {
3683 cr30 |= 0x80;
3685 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3686 cr31 |= 0x01;
3687 cr35 |= 0x01;
3688 ivideo->currentvbflags |= TV_HIVISION;
3689 } else if(ivideo->vbflags & TV_SCART) {
3690 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3691 cr31 |= 0x01;
3692 cr35 |= 0x01;
3693 ivideo->currentvbflags |= TV_SCART;
3694 } else {
3695 if(ivideo->vbflags & TV_SVIDEO) {
3696 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3697 ivideo->currentvbflags |= TV_SVIDEO;
3699 if(ivideo->vbflags & TV_AVIDEO) {
3700 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3701 ivideo->currentvbflags |= TV_AVIDEO;
3704 cr31 |= SIS_DRIVER_MODE;
3706 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3707 if(ivideo->vbflags & TV_PAL) {
3708 cr31 |= 0x01; cr35 |= 0x01;
3709 ivideo->currentvbflags |= TV_PAL;
3710 if(ivideo->vbflags & TV_PALM) {
3711 cr38 |= 0x40; cr35 |= 0x04;
3712 ivideo->currentvbflags |= TV_PALM;
3713 } else if(ivideo->vbflags & TV_PALN) {
3714 cr38 |= 0x80; cr35 |= 0x08;
3715 ivideo->currentvbflags |= TV_PALN;
3717 } else {
3718 cr31 &= ~0x01; cr35 &= ~0x01;
3719 ivideo->currentvbflags |= TV_NTSC;
3720 if(ivideo->vbflags & TV_NTSCJ) {
3721 cr38 |= 0x40; cr35 |= 0x02;
3722 ivideo->currentvbflags |= TV_NTSCJ;
3726 break;
3728 case CRT2_LCD:
3729 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3730 cr31 |= SIS_DRIVER_MODE;
3731 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3732 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3733 ivideo->curFSTN = ivideo->sisfb_fstn;
3734 ivideo->curDSTN = ivideo->sisfb_dstn;
3735 break;
3737 case CRT2_VGA:
3738 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3739 cr31 |= SIS_DRIVER_MODE;
3740 if(ivideo->sisfb_nocrt2rate) {
3741 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3742 } else {
3743 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3745 break;
3747 default: /* disable CRT2 */
3748 cr30 = 0x00;
3749 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3752 outSISIDXREG(SISCR, 0x30, cr30);
3753 outSISIDXREG(SISCR, 0x33, cr33);
3755 if(ivideo->chip >= SIS_661) {
3756 #ifdef CONFIG_FB_SIS_315
3757 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3758 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3759 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3760 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3761 #endif
3762 } else if(ivideo->chip != SIS_300) {
3763 outSISIDXREG(SISCR, tvregnum, cr38);
3765 outSISIDXREG(SISCR, 0x31, cr31);
3767 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3769 sisfb_check_engine_and_sync(ivideo);
3772 /* Fix SR11 for 661 and later */
3773 #ifdef CONFIG_FB_SIS_315
3774 static void
3775 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3777 u8 tmpreg;
3779 if(ivideo->chip >= SIS_661) {
3780 inSISIDXREG(SISSR,0x11,tmpreg);
3781 if(tmpreg & 0x20) {
3782 inSISIDXREG(SISSR,0x3e,tmpreg);
3783 tmpreg = (tmpreg + 1) & 0xff;
3784 outSISIDXREG(SISSR,0x3e,tmpreg);
3785 inSISIDXREG(SISSR,0x11,tmpreg);
3787 if(tmpreg & 0xf0) {
3788 andSISIDXREG(SISSR,0x11,0x0f);
3792 #endif
3794 static void
3795 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3797 if(val > 32) val = 32;
3798 if(val < -32) val = -32;
3799 ivideo->tvxpos = val;
3801 if(ivideo->sisfblocked) return;
3802 if(!ivideo->modechanged) return;
3804 if(ivideo->currentvbflags & CRT2_TV) {
3806 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3808 int x = ivideo->tvx;
3810 switch(ivideo->chronteltype) {
3811 case 1:
3812 x += val;
3813 if(x < 0) x = 0;
3814 outSISIDXREG(SISSR,0x05,0x86);
3815 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3816 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3817 break;
3818 case 2:
3819 /* Not supported by hardware */
3820 break;
3823 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3825 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3826 unsigned short temp;
3828 p2_1f = ivideo->p2_1f;
3829 p2_20 = ivideo->p2_20;
3830 p2_2b = ivideo->p2_2b;
3831 p2_42 = ivideo->p2_42;
3832 p2_43 = ivideo->p2_43;
3834 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3835 temp += (val * 2);
3836 p2_1f = temp & 0xff;
3837 p2_20 = (temp & 0xf00) >> 4;
3838 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3839 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3840 temp += (val * 2);
3841 p2_43 = temp & 0xff;
3842 p2_42 = (temp & 0xf00) >> 4;
3843 outSISIDXREG(SISPART2,0x1f,p2_1f);
3844 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3845 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3846 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3847 outSISIDXREG(SISPART2,0x43,p2_43);
3852 static void
3853 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3855 if(val > 32) val = 32;
3856 if(val < -32) val = -32;
3857 ivideo->tvypos = val;
3859 if(ivideo->sisfblocked) return;
3860 if(!ivideo->modechanged) return;
3862 if(ivideo->currentvbflags & CRT2_TV) {
3864 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3866 int y = ivideo->tvy;
3868 switch(ivideo->chronteltype) {
3869 case 1:
3870 y -= val;
3871 if(y < 0) y = 0;
3872 outSISIDXREG(SISSR,0x05,0x86);
3873 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3874 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3875 break;
3876 case 2:
3877 /* Not supported by hardware */
3878 break;
3881 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3883 char p2_01, p2_02;
3884 val /= 2;
3885 p2_01 = ivideo->p2_01;
3886 p2_02 = ivideo->p2_02;
3888 p2_01 += val;
3889 p2_02 += val;
3890 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3891 while((p2_01 <= 0) || (p2_02 <= 0)) {
3892 p2_01 += 2;
3893 p2_02 += 2;
3896 outSISIDXREG(SISPART2,0x01,p2_01);
3897 outSISIDXREG(SISPART2,0x02,p2_02);
3902 static void
3903 sisfb_post_setmode(struct sis_video_info *ivideo)
3905 BOOLEAN crt1isoff = FALSE;
3906 BOOLEAN doit = TRUE;
3907 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3908 u8 reg;
3909 #endif
3910 #ifdef CONFIG_FB_SIS_315
3911 u8 reg1;
3912 #endif
3914 outSISIDXREG(SISSR, 0x05, 0x86);
3916 #ifdef CONFIG_FB_SIS_315
3917 sisfb_fixup_SR11(ivideo);
3918 #endif
3920 /* Now we actually HAVE changed the display mode */
3921 ivideo->modechanged = 1;
3923 /* We can't switch off CRT1 if bridge is in slave mode */
3924 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3925 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3926 } else
3927 ivideo->sisfb_crt1off = 0;
3929 #ifdef CONFIG_FB_SIS_300
3930 if(ivideo->sisvga_engine == SIS_300_VGA) {
3931 if((ivideo->sisfb_crt1off) && (doit)) {
3932 crt1isoff = TRUE;
3933 reg = 0x00;
3934 } else {
3935 crt1isoff = FALSE;
3936 reg = 0x80;
3938 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3940 #endif
3941 #ifdef CONFIG_FB_SIS_315
3942 if(ivideo->sisvga_engine == SIS_315_VGA) {
3943 if((ivideo->sisfb_crt1off) && (doit)) {
3944 crt1isoff = TRUE;
3945 reg = 0x40;
3946 reg1 = 0xc0;
3947 } else {
3948 crt1isoff = FALSE;
3949 reg = 0x00;
3950 reg1 = 0x00;
3952 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3953 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3955 #endif
3957 if(crt1isoff) {
3958 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3959 ivideo->currentvbflags |= VB_SINGLE_MODE;
3960 } else {
3961 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3962 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3963 ivideo->currentvbflags |= VB_MIRROR_MODE;
3964 } else {
3965 ivideo->currentvbflags |= VB_SINGLE_MODE;
3969 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3971 if(ivideo->currentvbflags & CRT2_TV) {
3972 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3973 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3974 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3975 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3976 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3977 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3978 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3979 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3980 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3981 if(ivideo->chronteltype == 1) {
3982 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3983 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3984 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3985 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3990 if(ivideo->tvxpos) {
3991 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3993 if(ivideo->tvypos) {
3994 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3997 /* Eventually sync engines */
3998 sisfb_check_engine_and_sync(ivideo);
4000 /* (Re-)Initialize chip engines */
4001 if(ivideo->accel) {
4002 sisfb_engine_init(ivideo);
4003 } else {
4004 ivideo->engineok = 0;
4008 static int
4009 sisfb_reset_mode(struct sis_video_info *ivideo)
4011 if(sisfb_set_mode(ivideo, 0))
4012 return 1;
4014 sisfb_set_pitch(ivideo);
4015 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4016 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
4018 return 0;
4021 static void
4022 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4024 int mycrt1off;
4026 switch(sisfb_command->sisfb_cmd) {
4027 case SISFB_CMD_GETVBFLAGS:
4028 if(!ivideo->modechanged) {
4029 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4030 } else {
4031 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4032 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4033 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
4035 break;
4036 case SISFB_CMD_SWITCHCRT1:
4037 /* arg[0]: 0 = off, 1 = on, 99 = query */
4038 if(!ivideo->modechanged) {
4039 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4040 } else if(sisfb_command->sisfb_arg[0] == 99) {
4041 /* Query */
4042 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4043 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4044 } else if(ivideo->sisfblocked) {
4045 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4046 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4047 (sisfb_command->sisfb_arg[0] == 0)) {
4048 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4049 } else {
4050 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4051 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4052 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4053 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4054 ivideo->sisfb_crt1off = mycrt1off;
4055 if(sisfb_reset_mode(ivideo)) {
4056 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
4059 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4061 break;
4062 /* more to come */
4063 default:
4064 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4065 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4066 sisfb_command->sisfb_cmd);
4070 #ifndef MODULE
4071 SISINITSTATIC int __init
4072 sisfb_setup(char *options)
4074 char *this_opt;
4076 sisfb_setdefaultparms();
4078 if(!options || !(*options))
4079 return 0;
4081 while((this_opt = strsep(&options, ",")) != NULL) {
4083 if(!(*this_opt)) continue;
4085 if(!strnicmp(this_opt, "off", 3)) {
4086 sisfb_off = 1;
4087 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4088 /* Need to check crt2 type first for fstn/dstn */
4089 sisfb_search_crt2type(this_opt + 14);
4090 } else if(!strnicmp(this_opt, "tvmode:",7)) {
4091 sisfb_search_tvstd(this_opt + 7);
4092 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4093 sisfb_search_tvstd(this_opt + 11);
4094 } else if(!strnicmp(this_opt, "mode:", 5)) {
4095 sisfb_search_mode(this_opt + 5, FALSE);
4096 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4097 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4098 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4099 } else if(!strnicmp(this_opt, "inverse", 7)) {
4100 sisfb_inverse = 1;
4101 /* fb_invert_cmaps(); */
4102 } else if(!strnicmp(this_opt, "font:", 5)) {
4103 if(strlen(this_opt + 5) < 40) {
4104 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4105 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4107 #endif
4108 } else if(!strnicmp(this_opt, "rate:", 5)) {
4109 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4110 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4111 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4112 } else if(!strnicmp(this_opt, "mem:",4)) {
4113 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4114 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4115 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4116 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4117 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4118 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4119 sisfb_accel = 0;
4120 } else if(!strnicmp(this_opt, "accel", 5)) {
4121 sisfb_accel = -1;
4122 } else if(!strnicmp(this_opt, "noypan", 6)) {
4123 sisfb_ypan = 0;
4124 } else if(!strnicmp(this_opt, "ypan", 4)) {
4125 sisfb_ypan = -1;
4126 } else if(!strnicmp(this_opt, "nomax", 5)) {
4127 sisfb_max = 0;
4128 } else if(!strnicmp(this_opt, "max", 3)) {
4129 sisfb_max = -1;
4130 } else if(!strnicmp(this_opt, "userom:", 7)) {
4131 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4132 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4133 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4134 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4135 sisfb_nocrt2rate = 1;
4136 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4137 unsigned long temp = 2;
4138 temp = simple_strtoul(this_opt + 9, NULL, 0);
4139 if((temp == 0) || (temp == 1)) {
4140 sisfb_scalelcd = temp ^ 1;
4142 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4143 int temp = 0;
4144 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4145 if((temp >= -32) && (temp <= 32)) {
4146 sisfb_tvxposoffset = temp;
4148 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4149 int temp = 0;
4150 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4151 if((temp >= -32) && (temp <= 32)) {
4152 sisfb_tvyposoffset = temp;
4154 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4155 sisfb_search_specialtiming(this_opt + 14);
4156 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4157 int temp = 4;
4158 temp = simple_strtoul(this_opt + 7, NULL, 0);
4159 if((temp >= 0) && (temp <= 3)) {
4160 sisfb_lvdshl = temp;
4162 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4163 sisfb_search_mode(this_opt, TRUE);
4164 #if !defined(__i386__) && !defined(__x86_64__)
4165 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4166 sisfb_resetcard = 1;
4167 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4168 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4169 #endif
4170 } else {
4171 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4176 return 0;
4178 #endif
4180 static int __devinit
4181 sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4183 SIS_IOTYPE1 *rom;
4184 int romptr;
4186 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4187 return 0;
4189 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4190 if(romptr > (0x10000 - 8))
4191 return 0;
4193 rom = rom_base + romptr;
4195 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4196 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4197 return 0;
4199 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4200 return 0;
4202 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4203 return 0;
4205 return 1;
4208 static unsigned char * __devinit
4209 sisfb_find_rom(struct pci_dev *pdev)
4211 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4212 SIS_IOTYPE1 *rom_base;
4213 unsigned char *myrombase = NULL;
4214 u32 temp;
4215 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4216 size_t romsize;
4218 /* First, try the official pci ROM functions (except
4219 * on integrated chipsets which have no ROM).
4222 if(!ivideo->nbridge) {
4224 if((rom_base = pci_map_rom(pdev, &romsize))) {
4226 if(sisfb_check_rom(rom_base, ivideo)) {
4228 if((myrombase = vmalloc(65536))) {
4230 /* Work around bug in pci/rom.c: Folks forgot to check
4231 * whether the size retrieved from the BIOS image eventually
4232 * is larger than the mapped size
4234 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4235 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4237 memcpy_fromio(myrombase, rom_base,
4238 (romsize > 65536) ? 65536 : romsize);
4241 pci_unmap_rom(pdev, rom_base);
4245 if(myrombase) return myrombase;
4246 #endif
4248 /* Otherwise do it the conventional way. */
4250 #if defined(__i386__) || defined(__x86_64__)
4252 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4254 rom_base = ioremap(temp, 65536);
4255 if(!rom_base)
4256 continue;
4258 if(!sisfb_check_rom(rom_base, ivideo)) {
4259 iounmap(rom_base);
4260 continue;
4263 if((myrombase = vmalloc(65536)))
4264 memcpy_fromio(myrombase, rom_base, 65536);
4266 iounmap(rom_base);
4267 break;
4271 #else
4273 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4274 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4275 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4277 rom_base = ioremap(ivideo->video_base, 65536);
4278 if(rom_base) {
4279 if(sisfb_check_rom(rom_base, ivideo)) {
4280 if((myrombase = vmalloc(65536)))
4281 memcpy_fromio(myrombase, rom_base, 65536);
4283 iounmap(rom_base);
4286 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4288 #endif
4290 return myrombase;
4293 static void __devinit
4294 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4295 unsigned int min)
4297 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4299 if(!ivideo->video_vbase) {
4300 printk(KERN_ERR
4301 "sisfb: Unable to map maximum video RAM for size detection\n");
4302 (*mapsize) >>= 1;
4303 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4304 (*mapsize) >>= 1;
4305 if((*mapsize) < (min << 20))
4306 break;
4308 if(ivideo->video_vbase) {
4309 printk(KERN_ERR
4310 "sisfb: Video RAM size detection limited to %dMB\n",
4311 (int)((*mapsize) >> 20));
4316 #ifdef CONFIG_FB_SIS_300
4317 static int __devinit
4318 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4320 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4321 unsigned short temp;
4322 unsigned char reg;
4323 int i, j;
4325 andSISIDXREG(SISSR, 0x15, 0xFB);
4326 orSISIDXREG(SISSR, 0x15, 0x04);
4327 outSISIDXREG(SISSR, 0x13, 0x00);
4328 outSISIDXREG(SISSR, 0x14, 0xBF);
4330 for(i = 0; i < 2; i++) {
4331 temp = 0x1234;
4332 for(j = 0; j < 4; j++) {
4333 writew(temp, FBAddress);
4334 if(readw(FBAddress) == temp)
4335 break;
4336 orSISIDXREG(SISSR, 0x3c, 0x01);
4337 inSISIDXREG(SISSR, 0x05, reg);
4338 inSISIDXREG(SISSR, 0x05, reg);
4339 andSISIDXREG(SISSR, 0x3c, 0xfe);
4340 inSISIDXREG(SISSR, 0x05, reg);
4341 inSISIDXREG(SISSR, 0x05, reg);
4342 temp++;
4346 writel(0x01234567L, FBAddress);
4347 writel(0x456789ABL, (FBAddress + 4));
4348 writel(0x89ABCDEFL, (FBAddress + 8));
4349 writel(0xCDEF0123L, (FBAddress + 12));
4351 inSISIDXREG(SISSR, 0x3b, reg);
4352 if(reg & 0x01) {
4353 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4354 return 4; /* Channel A 128bit */
4357 if(readl((FBAddress + 4)) == 0x456789ABL)
4358 return 2; /* Channel B 64bit */
4360 return 1; /* 32bit */
4363 static int __devinit
4364 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4365 int PseudoRankCapacity, int PseudoAdrPinCount,
4366 unsigned int mapsize)
4368 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4369 unsigned short sr14;
4370 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4371 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4372 static const unsigned short SiS_DRAMType[17][5] = {
4373 {0x0C,0x0A,0x02,0x40,0x39},
4374 {0x0D,0x0A,0x01,0x40,0x48},
4375 {0x0C,0x09,0x02,0x20,0x35},
4376 {0x0D,0x09,0x01,0x20,0x44},
4377 {0x0C,0x08,0x02,0x10,0x31},
4378 {0x0D,0x08,0x01,0x10,0x40},
4379 {0x0C,0x0A,0x01,0x20,0x34},
4380 {0x0C,0x09,0x01,0x08,0x32},
4381 {0x0B,0x08,0x02,0x08,0x21},
4382 {0x0C,0x08,0x01,0x08,0x30},
4383 {0x0A,0x08,0x02,0x04,0x11},
4384 {0x0B,0x0A,0x01,0x10,0x28},
4385 {0x09,0x08,0x02,0x02,0x01},
4386 {0x0B,0x09,0x01,0x08,0x24},
4387 {0x0B,0x08,0x01,0x04,0x20},
4388 {0x0A,0x08,0x01,0x02,0x10},
4389 {0x09,0x08,0x01,0x01,0x00}
4392 for(k = 0; k <= 16; k++) {
4394 RankCapacity = buswidth * SiS_DRAMType[k][3];
4396 if(RankCapacity != PseudoRankCapacity)
4397 continue;
4399 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4400 continue;
4402 BankNumHigh = RankCapacity * 16 * iteration - 1;
4403 if(iteration == 3) { /* Rank No */
4404 BankNumMid = RankCapacity * 16 - 1;
4405 } else {
4406 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4409 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4410 PhysicalAdrHigh = BankNumHigh;
4411 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4412 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4414 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4415 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4416 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4417 if(buswidth == 4) sr14 |= 0x80;
4418 else if(buswidth == 2) sr14 |= 0x40;
4419 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4420 outSISIDXREG(SISSR, 0x14, sr14);
4422 BankNumHigh <<= 16;
4423 BankNumMid <<= 16;
4425 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4426 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4427 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4428 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4429 continue;
4431 /* Write data */
4432 writew(((unsigned short)PhysicalAdrHigh),
4433 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4434 writew(((unsigned short)BankNumMid),
4435 (FBAddr + BankNumMid + PhysicalAdrHigh));
4436 writew(((unsigned short)PhysicalAdrHalfPage),
4437 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4438 writew(((unsigned short)PhysicalAdrOtherPage),
4439 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4441 /* Read data */
4442 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4443 return 1;
4446 return 0;
4449 static void __devinit
4450 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4452 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4453 int i, j, buswidth;
4454 int PseudoRankCapacity, PseudoAdrPinCount;
4456 buswidth = sisfb_post_300_buswidth(ivideo);
4458 for(i = 6; i >= 0; i--) {
4459 PseudoRankCapacity = 1 << i;
4460 for(j = 4; j >= 1; j--) {
4461 PseudoAdrPinCount = 15 - j;
4462 if((PseudoRankCapacity * j) <= 64) {
4463 if(sisfb_post_300_rwtest(ivideo,
4465 buswidth,
4466 PseudoRankCapacity,
4467 PseudoAdrPinCount,
4468 mapsize))
4469 return;
4475 static void __devinit
4476 sisfb_post_sis300(struct pci_dev *pdev)
4478 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4479 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4480 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4481 u16 index, rindex, memtype = 0;
4482 unsigned int mapsize;
4484 if(!ivideo->SiS_Pr.UseROM)
4485 bios = NULL;
4487 outSISIDXREG(SISSR, 0x05, 0x86);
4489 if(bios) {
4490 if(bios[0x52] & 0x80) {
4491 memtype = bios[0x52];
4492 } else {
4493 inSISIDXREG(SISSR, 0x3a, memtype);
4495 memtype &= 0x07;
4498 v3 = 0x80; v6 = 0x80;
4499 if(ivideo->revision_id <= 0x13) {
4500 v1 = 0x44; v2 = 0x42;
4501 v4 = 0x44; v5 = 0x42;
4502 } else {
4503 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4504 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4505 if(bios) {
4506 index = memtype * 5;
4507 rindex = index + 0x54;
4508 v1 = bios[rindex++];
4509 v2 = bios[rindex++];
4510 v3 = bios[rindex++];
4511 rindex = index + 0x7c;
4512 v4 = bios[rindex++];
4513 v5 = bios[rindex++];
4514 v6 = bios[rindex++];
4517 outSISIDXREG(SISSR, 0x28, v1);
4518 outSISIDXREG(SISSR, 0x29, v2);
4519 outSISIDXREG(SISSR, 0x2a, v3);
4520 outSISIDXREG(SISSR, 0x2e, v4);
4521 outSISIDXREG(SISSR, 0x2f, v5);
4522 outSISIDXREG(SISSR, 0x30, v6);
4524 v1 = 0x10;
4525 if(bios)
4526 v1 = bios[0xa4];
4527 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4529 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4531 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4532 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4533 if(bios) {
4534 memtype += 0xa5;
4535 v1 = bios[memtype];
4536 v2 = bios[memtype + 8];
4537 v3 = bios[memtype + 16];
4538 v4 = bios[memtype + 24];
4539 v5 = bios[memtype + 32];
4540 v6 = bios[memtype + 40];
4541 v7 = bios[memtype + 48];
4542 v8 = bios[memtype + 56];
4544 if(ivideo->revision_id >= 0x80)
4545 v3 &= 0xfd;
4546 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4547 outSISIDXREG(SISSR, 0x16, v2);
4548 outSISIDXREG(SISSR, 0x17, v3);
4549 outSISIDXREG(SISSR, 0x18, v4);
4550 outSISIDXREG(SISSR, 0x19, v5);
4551 outSISIDXREG(SISSR, 0x1a, v6);
4552 outSISIDXREG(SISSR, 0x1b, v7);
4553 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4554 andSISIDXREG(SISSR, 0x15 ,0xfb);
4555 orSISIDXREG(SISSR, 0x15, 0x04);
4556 if(bios) {
4557 if(bios[0x53] & 0x02) {
4558 orSISIDXREG(SISSR, 0x19, 0x20);
4561 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4562 if(ivideo->revision_id >= 0x80)
4563 v1 |= 0x01;
4564 outSISIDXREG(SISSR, 0x1f, v1);
4565 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4566 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4567 if(bios) {
4568 v1 = bios[0xe8];
4569 v2 = bios[0xe9];
4570 v3 = bios[0xea];
4572 outSISIDXREG(SISSR, 0x23, v1);
4573 outSISIDXREG(SISSR, 0x24, v2);
4574 outSISIDXREG(SISSR, 0x25, v3);
4575 outSISIDXREG(SISSR, 0x21, 0x84);
4576 outSISIDXREG(SISSR, 0x22, 0x00);
4577 outSISIDXREG(SISCR, 0x37, 0x00);
4578 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4579 outSISIDXREG(SISPART1, 0x00, 0x00);
4580 v1 = 0x40; v2 = 0x11;
4581 if(bios) {
4582 v1 = bios[0xec];
4583 v2 = bios[0xeb];
4585 outSISIDXREG(SISPART1, 0x02, v1);
4587 if(ivideo->revision_id >= 0x80)
4588 v2 &= ~0x01;
4590 inSISIDXREG(SISPART4, 0x00, reg);
4591 if((reg == 1) || (reg == 2)) {
4592 outSISIDXREG(SISCR, 0x37, 0x02);
4593 outSISIDXREG(SISPART2, 0x00, 0x1c);
4594 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4595 if(ivideo->SiS_Pr.UseROM) {
4596 v4 = bios[0xf5];
4597 v5 = bios[0xf6];
4598 v6 = bios[0xf7];
4600 outSISIDXREG(SISPART4, 0x0d, v4);
4601 outSISIDXREG(SISPART4, 0x0e, v5);
4602 outSISIDXREG(SISPART4, 0x10, v6);
4603 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4604 inSISIDXREG(SISPART4, 0x01, reg);
4605 if(reg >= 0xb0) {
4606 inSISIDXREG(SISPART4, 0x23, reg);
4607 reg &= 0x20;
4608 reg <<= 1;
4609 outSISIDXREG(SISPART4, 0x23, reg);
4611 } else {
4612 v2 &= ~0x10;
4614 outSISIDXREG(SISSR, 0x32, v2);
4616 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4618 inSISIDXREG(SISSR, 0x16, reg);
4619 reg &= 0xc3;
4620 outSISIDXREG(SISCR, 0x35, reg);
4621 outSISIDXREG(SISCR, 0x83, 0x00);
4622 #if !defined(__i386__) && !defined(__x86_64__)
4623 if(sisfb_videoram) {
4624 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4625 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4626 outSISIDXREG(SISSR, 0x14, reg);
4627 } else {
4628 #endif
4629 /* Need to map max FB size for finding out about RAM size */
4630 mapsize = 64 << 20;
4631 sisfb_post_map_vram(ivideo, &mapsize, 4);
4633 if(ivideo->video_vbase) {
4634 sisfb_post_300_ramsize(pdev, mapsize);
4635 iounmap(ivideo->video_vbase);
4636 } else {
4637 printk(KERN_DEBUG
4638 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4639 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4640 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4642 #if !defined(__i386__) && !defined(__x86_64__)
4644 #endif
4645 if(bios) {
4646 v1 = bios[0xe6];
4647 v2 = bios[0xe7];
4648 } else {
4649 inSISIDXREG(SISSR, 0x3a, reg);
4650 if((reg & 0x30) == 0x30) {
4651 v1 = 0x04; /* PCI */
4652 v2 = 0x92;
4653 } else {
4654 v1 = 0x14; /* AGP */
4655 v2 = 0xb2;
4658 outSISIDXREG(SISSR, 0x21, v1);
4659 outSISIDXREG(SISSR, 0x22, v2);
4661 /* Sense CRT1 */
4662 sisfb_sense_crt1(ivideo);
4664 /* Set default mode, don't clear screen */
4665 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4666 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4667 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4668 ivideo->curFSTN = ivideo->curDSTN = 0;
4669 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4670 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4672 outSISIDXREG(SISSR, 0x05, 0x86);
4674 /* Display off */
4675 orSISIDXREG(SISSR, 0x01, 0x20);
4677 /* Save mode number in CR34 */
4678 outSISIDXREG(SISCR, 0x34, 0x2e);
4680 /* Let everyone know what the current mode is */
4681 ivideo->modeprechange = 0x2e;
4683 #endif
4685 #ifdef CONFIG_FB_SIS_315
4686 #if 0
4687 static void __devinit
4688 sisfb_post_sis315330(struct pci_dev *pdev)
4690 /* TODO */
4692 #endif
4694 static void __devinit
4695 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4697 unsigned int i;
4698 u8 reg;
4700 for(i = 0; i <= (delay * 10 * 36); i++) {
4701 inSISIDXREG(SISSR, 0x05, reg);
4702 reg++;
4706 static int __devinit
4707 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4708 unsigned short pcivendor)
4710 struct pci_dev *pdev = NULL;
4711 unsigned short temp;
4712 int ret = 0;
4714 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4715 temp = pdev->vendor;
4716 SIS_PCI_PUT_DEVICE(pdev);
4717 if(temp == pcivendor) {
4718 ret = 1;
4719 break;
4723 return ret;
4726 static int __devinit
4727 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4728 unsigned int enda, unsigned int mapsize)
4730 unsigned int pos;
4731 int i;
4733 writel(0, ivideo->video_vbase);
4735 for(i = starta; i <= enda; i++) {
4736 pos = 1 << i;
4737 if(pos < mapsize)
4738 writel(pos, ivideo->video_vbase + pos);
4741 sisfb_post_xgi_delay(ivideo, 150);
4743 if(readl(ivideo->video_vbase) != 0)
4744 return 0;
4746 for(i = starta; i <= enda; i++) {
4747 pos = 1 << i;
4748 if(pos < mapsize) {
4749 if(readl(ivideo->video_vbase + pos) != pos)
4750 return 0;
4751 } else
4752 return 0;
4755 return 1;
4758 static void __devinit
4759 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4761 unsigned int buswidth, ranksize, channelab, mapsize;
4762 int i, j, k, l;
4763 u8 reg, sr14;
4764 static const u8 dramsr13[12 * 5] = {
4765 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4766 0x02, 0x0e, 0x0a, 0x40, 0x59,
4767 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4768 0x02, 0x0e, 0x09, 0x20, 0x55,
4769 0x02, 0x0d, 0x0a, 0x20, 0x49,
4770 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4771 0x02, 0x0e, 0x08, 0x10, 0x51,
4772 0x02, 0x0d, 0x09, 0x10, 0x45,
4773 0x02, 0x0c, 0x0a, 0x10, 0x39,
4774 0x02, 0x0d, 0x08, 0x08, 0x41,
4775 0x02, 0x0c, 0x09, 0x08, 0x35,
4776 0x02, 0x0c, 0x08, 0x04, 0x31
4778 static const u8 dramsr13_4[4 * 5] = {
4779 0x02, 0x0d, 0x09, 0x40, 0x45,
4780 0x02, 0x0c, 0x09, 0x20, 0x35,
4781 0x02, 0x0c, 0x08, 0x10, 0x31,
4782 0x02, 0x0b, 0x08, 0x08, 0x21
4785 /* Enable linear mode, disable 0xa0000 address decoding */
4786 /* We disable a0000 address decoding, because
4787 * - if running on x86, if the card is disabled, it means
4788 * that another card is in the system. We don't want
4789 * to interphere with that primary card's textmode.
4790 * - if running on non-x86, there usually is no VGA window
4791 * at a0000.
4793 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4795 /* Need to map max FB size for finding out about RAM size */
4796 mapsize = 256 << 20;
4797 sisfb_post_map_vram(ivideo, &mapsize, 32);
4799 if(!ivideo->video_vbase) {
4800 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4801 outSISIDXREG(SISSR, 0x13, 0x35);
4802 outSISIDXREG(SISSR, 0x14, 0x41);
4803 /* TODO */
4804 return;
4807 /* Non-interleaving */
4808 outSISIDXREG(SISSR, 0x15, 0x00);
4809 /* No tiling */
4810 outSISIDXREG(SISSR, 0x1c, 0x00);
4812 if(ivideo->chip == XGI_20) {
4814 channelab = 1;
4815 inSISIDXREG(SISCR, 0x97, reg);
4816 if(!(reg & 0x01)) { /* Single 32/16 */
4817 buswidth = 32;
4818 outSISIDXREG(SISSR, 0x13, 0xb1);
4819 outSISIDXREG(SISSR, 0x14, 0x52);
4820 sisfb_post_xgi_delay(ivideo, 1);
4821 sr14 = 0x02;
4822 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4823 goto bail_out;
4825 outSISIDXREG(SISSR, 0x13, 0x31);
4826 outSISIDXREG(SISSR, 0x14, 0x42);
4827 sisfb_post_xgi_delay(ivideo, 1);
4828 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4829 goto bail_out;
4831 buswidth = 16;
4832 outSISIDXREG(SISSR, 0x13, 0xb1);
4833 outSISIDXREG(SISSR, 0x14, 0x41);
4834 sisfb_post_xgi_delay(ivideo, 1);
4835 sr14 = 0x01;
4836 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4837 goto bail_out;
4838 else
4839 outSISIDXREG(SISSR, 0x13, 0x31);
4840 } else { /* Dual 16/8 */
4841 buswidth = 16;
4842 outSISIDXREG(SISSR, 0x13, 0xb1);
4843 outSISIDXREG(SISSR, 0x14, 0x41);
4844 sisfb_post_xgi_delay(ivideo, 1);
4845 sr14 = 0x01;
4846 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4847 goto bail_out;
4849 outSISIDXREG(SISSR, 0x13, 0x31);
4850 outSISIDXREG(SISSR, 0x14, 0x31);
4851 sisfb_post_xgi_delay(ivideo, 1);
4852 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4853 goto bail_out;
4855 buswidth = 8;
4856 outSISIDXREG(SISSR, 0x13, 0xb1);
4857 outSISIDXREG(SISSR, 0x14, 0x30);
4858 sisfb_post_xgi_delay(ivideo, 1);
4859 sr14 = 0x00;
4860 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4861 goto bail_out;
4862 else
4863 outSISIDXREG(SISSR, 0x13, 0x31);
4866 } else { /* XGI_40 */
4868 inSISIDXREG(SISCR, 0x97, reg);
4869 if(!(reg & 0x10)) {
4870 inSISIDXREG(SISSR, 0x39, reg);
4871 reg >>= 1;
4874 if(reg & 0x01) { /* DDRII */
4875 buswidth = 32;
4876 if(ivideo->revision_id == 2) {
4877 channelab = 2;
4878 outSISIDXREG(SISSR, 0x13, 0xa1);
4879 outSISIDXREG(SISSR, 0x14, 0x44);
4880 sr14 = 0x04;
4881 sisfb_post_xgi_delay(ivideo, 1);
4882 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4883 goto bail_out;
4885 outSISIDXREG(SISSR, 0x13, 0x21);
4886 outSISIDXREG(SISSR, 0x14, 0x34);
4887 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4888 goto bail_out;
4890 channelab = 1;
4891 outSISIDXREG(SISSR, 0x13, 0xa1);
4892 outSISIDXREG(SISSR, 0x14, 0x40);
4893 sr14 = 0x00;
4894 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4895 goto bail_out;
4897 outSISIDXREG(SISSR, 0x13, 0x21);
4898 outSISIDXREG(SISSR, 0x14, 0x30);
4899 } else {
4900 channelab = 3;
4901 outSISIDXREG(SISSR, 0x13, 0xa1);
4902 outSISIDXREG(SISSR, 0x14, 0x4c);
4903 sr14 = 0x0c;
4904 sisfb_post_xgi_delay(ivideo, 1);
4905 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4906 goto bail_out;
4908 channelab = 2;
4909 outSISIDXREG(SISSR, 0x14, 0x48);
4910 sisfb_post_xgi_delay(ivideo, 1);
4911 sr14 = 0x08;
4912 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4913 goto bail_out;
4915 outSISIDXREG(SISSR, 0x13, 0x21);
4916 outSISIDXREG(SISSR, 0x14, 0x3c);
4917 sr14 = 0x0c;
4919 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4920 channelab = 3;
4921 } else {
4922 channelab = 2;
4923 outSISIDXREG(SISSR, 0x14, 0x38);
4924 sr14 = 0x08;
4927 sisfb_post_xgi_delay(ivideo, 1);
4929 } else { /* DDR */
4931 buswidth = 64;
4932 if(ivideo->revision_id == 2) {
4933 channelab = 1;
4934 outSISIDXREG(SISSR, 0x13, 0xa1);
4935 outSISIDXREG(SISSR, 0x14, 0x52);
4936 sisfb_post_xgi_delay(ivideo, 1);
4937 sr14 = 0x02;
4938 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4939 goto bail_out;
4941 outSISIDXREG(SISSR, 0x13, 0x21);
4942 outSISIDXREG(SISSR, 0x14, 0x42);
4943 } else {
4944 channelab = 2;
4945 outSISIDXREG(SISSR, 0x13, 0xa1);
4946 outSISIDXREG(SISSR, 0x14, 0x5a);
4947 sisfb_post_xgi_delay(ivideo, 1);
4948 sr14 = 0x0a;
4949 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4950 goto bail_out;
4952 outSISIDXREG(SISSR, 0x13, 0x21);
4953 outSISIDXREG(SISSR, 0x14, 0x4a);
4955 sisfb_post_xgi_delay(ivideo, 1);
4960 bail_out:
4961 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4962 sisfb_post_xgi_delay(ivideo, 1);
4964 j = (ivideo->chip == XGI_20) ? 5 : 9;
4965 k = (ivideo->chip == XGI_20) ? 12 : 4;
4967 for(i = 0; i < k; i++) {
4969 reg = (ivideo->chip == XGI_20) ?
4970 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4971 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4972 sisfb_post_xgi_delay(ivideo, 50);
4974 ranksize = (ivideo->chip == XGI_20) ?
4975 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4977 inSISIDXREG(SISSR, 0x13, reg);
4978 if(reg & 0x80) ranksize <<= 1;
4980 if(ivideo->chip == XGI_20) {
4981 if(buswidth == 16) ranksize <<= 1;
4982 else if(buswidth == 32) ranksize <<= 2;
4983 } else {
4984 if(buswidth == 64) ranksize <<= 1;
4987 reg = 0;
4988 l = channelab;
4989 if(l == 3) l = 4;
4990 if((ranksize * l) <= 256) {
4991 while((ranksize >>= 1)) reg += 0x10;
4994 if(!reg) continue;
4996 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4997 sisfb_post_xgi_delay(ivideo, 1);
4999 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5000 break;
5003 iounmap(ivideo->video_vbase);
5006 static void __devinit
5007 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5009 u8 v1, v2, v3;
5010 int index;
5011 static const u8 cs90[8 * 3] = {
5012 0x16, 0x01, 0x01,
5013 0x3e, 0x03, 0x01,
5014 0x7c, 0x08, 0x01,
5015 0x79, 0x06, 0x01,
5016 0x29, 0x01, 0x81,
5017 0x5c, 0x23, 0x01,
5018 0x5c, 0x23, 0x01,
5019 0x5c, 0x23, 0x01
5021 static const u8 csb8[8 * 3] = {
5022 0x5c, 0x23, 0x01,
5023 0x29, 0x01, 0x01,
5024 0x7c, 0x08, 0x01,
5025 0x79, 0x06, 0x01,
5026 0x29, 0x01, 0x81,
5027 0x5c, 0x23, 0x01,
5028 0x5c, 0x23, 0x01,
5029 0x5c, 0x23, 0x01
5032 regb = 0; /* ! */
5034 index = regb * 3;
5035 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5036 if(ivideo->haveXGIROM) {
5037 v1 = ivideo->bios_abase[0x90 + index];
5038 v2 = ivideo->bios_abase[0x90 + index + 1];
5039 v3 = ivideo->bios_abase[0x90 + index + 2];
5041 outSISIDXREG(SISSR, 0x28, v1);
5042 outSISIDXREG(SISSR, 0x29, v2);
5043 outSISIDXREG(SISSR, 0x2a, v3);
5044 sisfb_post_xgi_delay(ivideo, 0x43);
5045 sisfb_post_xgi_delay(ivideo, 0x43);
5046 sisfb_post_xgi_delay(ivideo, 0x43);
5047 index = regb * 3;
5048 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5049 if(ivideo->haveXGIROM) {
5050 v1 = ivideo->bios_abase[0xb8 + index];
5051 v2 = ivideo->bios_abase[0xb8 + index + 1];
5052 v3 = ivideo->bios_abase[0xb8 + index + 2];
5054 outSISIDXREG(SISSR, 0x2e, v1);
5055 outSISIDXREG(SISSR, 0x2f, v2);
5056 outSISIDXREG(SISSR, 0x30, v3);
5057 sisfb_post_xgi_delay(ivideo, 0x43);
5058 sisfb_post_xgi_delay(ivideo, 0x43);
5059 sisfb_post_xgi_delay(ivideo, 0x43);
5062 static int __devinit
5063 sisfb_post_xgi(struct pci_dev *pdev)
5065 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5066 unsigned char *bios = ivideo->bios_abase;
5067 struct pci_dev *mypdev = NULL;
5068 const u8 *ptr, *ptr2;
5069 u8 v1, v2, v3, v4, v5, reg, ramtype;
5070 u32 rega, regb, regd;
5071 int i, j, k, index;
5072 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5073 static const u8 cs76[2] = { 0xa3, 0xfb };
5074 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5075 static const u8 cs158[8] = {
5076 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5078 static const u8 cs160[8] = {
5079 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5081 static const u8 cs168[8] = {
5082 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5084 static const u8 cs128[3 * 8] = {
5085 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5086 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5087 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5089 static const u8 cs148[2 * 8] = {
5090 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5093 static const u8 cs31a[8 * 4] = {
5094 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5095 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5096 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5097 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5099 static const u8 cs33a[8 * 4] = {
5100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5105 static const u8 cs45a[8 * 2] = {
5106 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5109 static const u8 cs170[7 * 8] = {
5110 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5111 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5112 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5113 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5114 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5115 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5116 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5118 static const u8 cs1a8[3 * 8] = {
5119 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5120 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5123 static const u8 cs100[2 * 8] = {
5124 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5125 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5128 /* VGA enable */
5129 reg = inSISREG(SISVGAENABLE) | 0x01;
5130 outSISREG(SISVGAENABLE, reg);
5132 /* Misc */
5133 reg = inSISREG(SISMISCR) | 0x01;
5134 outSISREG(SISMISCW, reg);
5136 /* Unlock SR */
5137 outSISIDXREG(SISSR, 0x05, 0x86);
5138 inSISIDXREG(SISSR, 0x05, reg);
5139 if(reg != 0xa1)
5140 return 0;
5142 /* Clear some regs */
5143 for(i = 0; i < 0x22; i++) {
5144 if(0x06 + i == 0x20) continue;
5145 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5147 for(i = 0; i < 0x0b; i++) {
5148 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5150 for(i = 0; i < 0x10; i++) {
5151 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5154 ptr = cs78;
5155 if(ivideo->haveXGIROM) {
5156 ptr = (const u8 *)&bios[0x78];
5158 for(i = 0; i < 3; i++) {
5159 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5162 ptr = cs76;
5163 if(ivideo->haveXGIROM) {
5164 ptr = (const u8 *)&bios[0x76];
5166 for(i = 0; i < 2; i++) {
5167 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5170 v1 = 0x18; v2 = 0x00;
5171 if(ivideo->haveXGIROM) {
5172 v1 = bios[0x74];
5173 v2 = bios[0x75];
5175 outSISIDXREG(SISSR, 0x07, v1);
5176 outSISIDXREG(SISSR, 0x11, 0x0f);
5177 outSISIDXREG(SISSR, 0x1f, v2);
5178 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5179 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5180 outSISIDXREG(SISSR, 0x27, 0x74);
5182 ptr = cs7b;
5183 if(ivideo->haveXGIROM) {
5184 ptr = (const u8 *)&bios[0x7b];
5186 for(i = 0; i < 3; i++) {
5187 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5190 if(ivideo->chip == XGI_40) {
5191 if(ivideo->revision_id == 2) {
5192 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5194 outSISIDXREG(SISCR, 0x7d, 0xfe);
5195 outSISIDXREG(SISCR, 0x7e, 0x0f);
5197 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5198 andSISIDXREG(SISCR, 0x58, 0xd7);
5199 inSISIDXREG(SISCR, 0xcb, reg);
5200 if(reg & 0x20) {
5201 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5205 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5206 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5208 if(ivideo->chip == XGI_20) {
5209 outSISIDXREG(SISSR, 0x36, 0x70);
5210 } else {
5211 outSISIDXREG(SISVID, 0x00, 0x86);
5212 outSISIDXREG(SISVID, 0x32, 0x00);
5213 outSISIDXREG(SISVID, 0x30, 0x00);
5214 outSISIDXREG(SISVID, 0x32, 0x01);
5215 outSISIDXREG(SISVID, 0x30, 0x00);
5216 andSISIDXREG(SISVID, 0x2f, 0xdf);
5217 andSISIDXREG(SISCAP, 0x00, 0x3f);
5219 outSISIDXREG(SISPART1, 0x2f, 0x01);
5220 outSISIDXREG(SISPART1, 0x00, 0x00);
5221 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5222 outSISIDXREG(SISPART1, 0x2e, 0x08);
5223 andSISIDXREG(SISPART1, 0x35, 0x7f);
5224 andSISIDXREG(SISPART1, 0x50, 0xfe);
5226 inSISIDXREG(SISPART4, 0x00, reg);
5227 if(reg == 1 || reg == 2) {
5228 outSISIDXREG(SISPART2, 0x00, 0x1c);
5229 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5230 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5231 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5232 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5234 inSISIDXREG(SISPART4, 0x01, reg);
5235 if((reg & 0xf0) >= 0xb0) {
5236 inSISIDXREG(SISPART4, 0x23, reg);
5237 if(reg & 0x20) reg |= 0x40;
5238 outSISIDXREG(SISPART4, 0x23, reg);
5239 reg = (reg & 0x20) ? 0x02 : 0x00;
5240 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5244 v1 = bios[0x77];
5246 inSISIDXREG(SISSR, 0x3b, reg);
5247 if(reg & 0x02) {
5248 inSISIDXREG(SISSR, 0x3a, reg);
5249 v2 = (reg & 0x30) >> 3;
5250 if(!(v2 & 0x04)) v2 ^= 0x02;
5251 inSISIDXREG(SISSR, 0x39, reg);
5252 if(reg & 0x80) v2 |= 0x80;
5253 v2 |= 0x01;
5255 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5256 SIS_PCI_PUT_DEVICE(mypdev);
5257 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5258 v2 &= 0xf9;
5259 v2 |= 0x08;
5260 v1 &= 0xfe;
5261 } else {
5262 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5263 if(!mypdev)
5264 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5265 if(!mypdev)
5266 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5267 if(mypdev) {
5268 pci_read_config_dword(mypdev, 0x94, &regd);
5269 regd &= 0xfffffeff;
5270 pci_write_config_dword(mypdev, 0x94, regd);
5271 v1 &= 0xfe;
5272 SIS_PCI_PUT_DEVICE(mypdev);
5273 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5274 v1 &= 0xfe;
5275 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5276 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5277 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5278 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5279 if((v2 & 0x06) == 4)
5280 v2 ^= 0x06;
5281 v2 |= 0x08;
5284 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5286 outSISIDXREG(SISSR, 0x22, v1);
5288 if(ivideo->revision_id == 2) {
5289 inSISIDXREG(SISSR, 0x3b, v1);
5290 inSISIDXREG(SISSR, 0x3a, v2);
5291 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5292 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5293 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5295 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5296 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5297 * of nforce 2 ROM
5299 if(0)
5300 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5301 SIS_PCI_PUT_DEVICE(mypdev);
5305 v1 = 0x30;
5306 inSISIDXREG(SISSR, 0x3b, reg);
5307 inSISIDXREG(SISCR, 0x5f, v2);
5308 if((!(reg & 0x02)) && (v2 & 0x0e))
5309 v1 |= 0x08;
5310 outSISIDXREG(SISSR, 0x27, v1);
5312 if(bios[0x64] & 0x01) {
5313 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5316 v1 = bios[0x4f7];
5317 pci_read_config_dword(pdev, 0x50, &regd);
5318 regd = (regd >> 20) & 0x0f;
5319 if(regd == 1) {
5320 v1 &= 0xfc;
5321 orSISIDXREG(SISCR, 0x5f, 0x08);
5323 outSISIDXREG(SISCR, 0x48, v1);
5325 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5326 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5327 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5328 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5329 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5330 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5331 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5332 outSISIDXREG(SISCR, 0x74, 0xd0);
5333 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5334 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5335 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5336 v1 = bios[0x501];
5337 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5338 v1 = 0xf0;
5339 SIS_PCI_PUT_DEVICE(mypdev);
5341 outSISIDXREG(SISCR, 0x77, v1);
5344 /* RAM type */
5346 regb = 0; /* ! */
5348 v1 = 0xff;
5349 if(ivideo->haveXGIROM) {
5350 v1 = bios[0x140 + regb];
5352 outSISIDXREG(SISCR, 0x6d, v1);
5354 ptr = cs128;
5355 if(ivideo->haveXGIROM) {
5356 ptr = (const u8 *)&bios[0x128];
5358 for(i = 0, j = 0; i < 3; i++, j += 8) {
5359 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5362 ptr = cs31a;
5363 ptr2 = cs33a;
5364 if(ivideo->haveXGIROM) {
5365 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5366 ptr = (const u8 *)&bios[index];
5367 ptr2 = (const u8 *)&bios[index + 0x20];
5369 for(i = 0; i < 2; i++) {
5370 if(i == 0) {
5371 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5372 rega = 0x6b;
5373 } else {
5374 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5375 rega = 0x6e;
5377 reg = 0x00;
5378 for(j = 0; j < 16; j++) {
5379 reg &= 0xf3;
5380 if(regd & 0x01) reg |= 0x04;
5381 if(regd & 0x02) reg |= 0x08;
5382 regd >>= 2;
5383 outSISIDXREG(SISCR, rega, reg);
5384 inSISIDXREG(SISCR, rega, reg);
5385 inSISIDXREG(SISCR, rega, reg);
5386 reg += 0x10;
5390 andSISIDXREG(SISCR, 0x6e, 0xfc);
5392 ptr = NULL;
5393 if(ivideo->haveXGIROM) {
5394 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5395 ptr = (const u8 *)&bios[index];
5397 for(i = 0; i < 4; i++) {
5398 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5399 reg = 0x00;
5400 for(j = 0; j < 2; j++) {
5401 regd = 0;
5402 if(ptr) {
5403 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5404 ptr += 4;
5406 /* reg = 0x00; */
5407 for(k = 0; k < 16; k++) {
5408 reg &= 0xfc;
5409 if(regd & 0x01) reg |= 0x01;
5410 if(regd & 0x02) reg |= 0x02;
5411 regd >>= 2;
5412 outSISIDXREG(SISCR, 0x6f, reg);
5413 inSISIDXREG(SISCR, 0x6f, reg);
5414 inSISIDXREG(SISCR, 0x6f, reg);
5415 reg += 0x08;
5420 ptr = cs148;
5421 if(ivideo->haveXGIROM) {
5422 ptr = (const u8 *)&bios[0x148];
5424 for(i = 0, j = 0; i < 2; i++, j += 8) {
5425 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5428 andSISIDXREG(SISCR, 0x89, 0x8f);
5430 ptr = cs45a;
5431 if(ivideo->haveXGIROM) {
5432 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5433 ptr = (const u8 *)&bios[index];
5435 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5436 reg = 0x80;
5437 for(i = 0; i < 5; i++) {
5438 reg &= 0xfc;
5439 if(regd & 0x01) reg |= 0x01;
5440 if(regd & 0x02) reg |= 0x02;
5441 regd >>= 2;
5442 outSISIDXREG(SISCR, 0x89, reg);
5443 inSISIDXREG(SISCR, 0x89, reg);
5444 inSISIDXREG(SISCR, 0x89, reg);
5445 reg += 0x10;
5448 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5449 if(ivideo->haveXGIROM) {
5450 v1 = bios[0x118 + regb];
5451 v2 = bios[0xf8 + regb];
5452 v3 = bios[0x120 + regb];
5453 v4 = bios[0x1ca];
5455 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5456 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5457 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5458 outSISIDXREG(SISCR, 0x41, v2);
5460 ptr = cs170;
5461 if(ivideo->haveXGIROM) {
5462 ptr = (const u8 *)&bios[0x170];
5464 for(i = 0, j = 0; i < 7; i++, j += 8) {
5465 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5468 outSISIDXREG(SISCR, 0x59, v3);
5470 ptr = cs1a8;
5471 if(ivideo->haveXGIROM) {
5472 ptr = (const u8 *)&bios[0x1a8];
5474 for(i = 0, j = 0; i < 3; i++, j += 8) {
5475 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5478 ptr = cs100;
5479 if(ivideo->haveXGIROM) {
5480 ptr = (const u8 *)&bios[0x100];
5482 for(i = 0, j = 0; i < 2; i++, j += 8) {
5483 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5486 outSISIDXREG(SISCR, 0xcf, v4);
5488 outSISIDXREG(SISCR, 0x83, 0x09);
5489 outSISIDXREG(SISCR, 0x87, 0x00);
5491 if(ivideo->chip == XGI_40) {
5492 if( (ivideo->revision_id == 1) ||
5493 (ivideo->revision_id == 2) ) {
5494 outSISIDXREG(SISCR, 0x8c, 0x87);
5498 outSISIDXREG(SISSR, 0x17, 0x00);
5499 outSISIDXREG(SISSR, 0x1a, 0x87);
5501 if(ivideo->chip == XGI_20) {
5502 outSISIDXREG(SISSR, 0x15, 0x00);
5503 outSISIDXREG(SISSR, 0x1c, 0x00);
5506 ramtype = 0x00; v1 = 0x10;
5507 if(ivideo->haveXGIROM) {
5508 ramtype = bios[0x62];
5509 v1 = bios[0x1d2];
5511 if(!(ramtype & 0x80)) {
5512 if(ivideo->chip == XGI_20) {
5513 outSISIDXREG(SISCR, 0x97, v1);
5514 inSISIDXREG(SISCR, 0x97, reg);
5515 if(reg & 0x10) {
5516 ramtype = (reg & 0x01) << 1;
5518 } else {
5519 inSISIDXREG(SISSR, 0x39, reg);
5520 ramtype = reg & 0x02;
5521 if(!(ramtype)) {
5522 inSISIDXREG(SISSR, 0x3a, reg);
5523 ramtype = (reg >> 1) & 0x01;
5527 ramtype &= 0x07;
5529 regb = 0; /* ! */
5531 switch(ramtype) {
5532 case 0:
5533 sisfb_post_xgi_setclocks(ivideo, regb);
5534 if((ivideo->chip == XGI_20) ||
5535 (ivideo->revision_id == 1) ||
5536 (ivideo->revision_id == 2)) {
5537 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5538 if(ivideo->haveXGIROM) {
5539 v1 = bios[regb + 0x158];
5540 v2 = bios[regb + 0x160];
5541 v3 = bios[regb + 0x168];
5543 outSISIDXREG(SISCR, 0x82, v1);
5544 outSISIDXREG(SISCR, 0x85, v2);
5545 outSISIDXREG(SISCR, 0x86, v3);
5546 } else {
5547 outSISIDXREG(SISCR, 0x82, 0x88);
5548 outSISIDXREG(SISCR, 0x86, 0x00);
5549 inSISIDXREG(SISCR, 0x86, reg);
5550 outSISIDXREG(SISCR, 0x86, 0x88);
5551 inSISIDXREG(SISCR, 0x86, reg);
5552 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5553 outSISIDXREG(SISCR, 0x82, 0x77);
5554 outSISIDXREG(SISCR, 0x85, 0x00);
5555 inSISIDXREG(SISCR, 0x85, reg);
5556 outSISIDXREG(SISCR, 0x85, 0x88);
5557 inSISIDXREG(SISCR, 0x85, reg);
5558 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5559 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5561 if(ivideo->chip == XGI_40) {
5562 outSISIDXREG(SISCR, 0x97, 0x00);
5564 outSISIDXREG(SISCR, 0x98, 0x01);
5565 outSISIDXREG(SISCR, 0x9a, 0x02);
5567 outSISIDXREG(SISSR, 0x18, 0x01);
5568 if((ivideo->chip == XGI_20) ||
5569 (ivideo->revision_id == 2)) {
5570 outSISIDXREG(SISSR, 0x19, 0x40);
5571 } else {
5572 outSISIDXREG(SISSR, 0x19, 0x20);
5574 outSISIDXREG(SISSR, 0x16, 0x00);
5575 outSISIDXREG(SISSR, 0x16, 0x80);
5576 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5577 sisfb_post_xgi_delay(ivideo, 0x43);
5578 sisfb_post_xgi_delay(ivideo, 0x43);
5579 sisfb_post_xgi_delay(ivideo, 0x43);
5580 outSISIDXREG(SISSR, 0x18, 0x00);
5581 if((ivideo->chip == XGI_20) ||
5582 (ivideo->revision_id == 2)) {
5583 outSISIDXREG(SISSR, 0x19, 0x40);
5584 } else {
5585 outSISIDXREG(SISSR, 0x19, 0x20);
5587 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5588 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5590 outSISIDXREG(SISSR, 0x16, 0x00);
5591 outSISIDXREG(SISSR, 0x16, 0x80);
5592 sisfb_post_xgi_delay(ivideo, 4);
5593 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5594 if(ivideo->haveXGIROM) {
5595 v1 = bios[0xf0];
5596 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5597 v2 = bios[index];
5598 v3 = bios[index + 1];
5599 v4 = bios[index + 2];
5600 v5 = bios[index + 3];
5602 outSISIDXREG(SISSR, 0x18, v1);
5603 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5604 outSISIDXREG(SISSR, 0x16, v2);
5605 outSISIDXREG(SISSR, 0x16, v3);
5606 sisfb_post_xgi_delay(ivideo, 0x43);
5607 outSISIDXREG(SISSR, 0x1b, 0x03);
5608 sisfb_post_xgi_delay(ivideo, 0x22);
5609 outSISIDXREG(SISSR, 0x18, v1);
5610 outSISIDXREG(SISSR, 0x19, 0x00);
5611 outSISIDXREG(SISSR, 0x16, v4);
5612 outSISIDXREG(SISSR, 0x16, v5);
5613 outSISIDXREG(SISSR, 0x1b, 0x00);
5614 break;
5615 case 1:
5616 outSISIDXREG(SISCR, 0x82, 0x77);
5617 outSISIDXREG(SISCR, 0x86, 0x00);
5618 inSISIDXREG(SISCR, 0x86, reg);
5619 outSISIDXREG(SISCR, 0x86, 0x88);
5620 inSISIDXREG(SISCR, 0x86, reg);
5621 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5622 if(ivideo->haveXGIROM) {
5623 v1 = bios[regb + 0x168];
5624 v2 = bios[regb + 0x160];
5625 v3 = bios[regb + 0x158];
5627 outSISIDXREG(SISCR, 0x86, v1);
5628 outSISIDXREG(SISCR, 0x82, 0x77);
5629 outSISIDXREG(SISCR, 0x85, 0x00);
5630 inSISIDXREG(SISCR, 0x85, reg);
5631 outSISIDXREG(SISCR, 0x85, 0x88);
5632 inSISIDXREG(SISCR, 0x85, reg);
5633 outSISIDXREG(SISCR, 0x85, v2);
5634 outSISIDXREG(SISCR, 0x82, v3);
5635 outSISIDXREG(SISCR, 0x98, 0x01);
5636 outSISIDXREG(SISCR, 0x9a, 0x02);
5638 outSISIDXREG(SISSR, 0x28, 0x64);
5639 outSISIDXREG(SISSR, 0x29, 0x63);
5640 sisfb_post_xgi_delay(ivideo, 15);
5641 outSISIDXREG(SISSR, 0x18, 0x00);
5642 outSISIDXREG(SISSR, 0x19, 0x20);
5643 outSISIDXREG(SISSR, 0x16, 0x00);
5644 outSISIDXREG(SISSR, 0x16, 0x80);
5645 outSISIDXREG(SISSR, 0x18, 0xc5);
5646 outSISIDXREG(SISSR, 0x19, 0x23);
5647 outSISIDXREG(SISSR, 0x16, 0x00);
5648 outSISIDXREG(SISSR, 0x16, 0x80);
5649 sisfb_post_xgi_delay(ivideo, 1);
5650 outSISIDXREG(SISCR, 0x97,0x11);
5651 sisfb_post_xgi_setclocks(ivideo, regb);
5652 sisfb_post_xgi_delay(ivideo, 0x46);
5653 outSISIDXREG(SISSR, 0x18, 0xc5);
5654 outSISIDXREG(SISSR, 0x19, 0x23);
5655 outSISIDXREG(SISSR, 0x16, 0x00);
5656 outSISIDXREG(SISSR, 0x16, 0x80);
5657 sisfb_post_xgi_delay(ivideo, 1);
5658 outSISIDXREG(SISSR, 0x1b, 0x04);
5659 sisfb_post_xgi_delay(ivideo, 1);
5660 outSISIDXREG(SISSR, 0x1b, 0x00);
5661 sisfb_post_xgi_delay(ivideo, 1);
5662 v1 = 0x31;
5663 if(ivideo->haveXGIROM) {
5664 v1 = bios[0xf0];
5666 outSISIDXREG(SISSR, 0x18, v1);
5667 outSISIDXREG(SISSR, 0x19, 0x06);
5668 outSISIDXREG(SISSR, 0x16, 0x04);
5669 outSISIDXREG(SISSR, 0x16, 0x84);
5670 sisfb_post_xgi_delay(ivideo, 1);
5671 break;
5672 default:
5673 sisfb_post_xgi_setclocks(ivideo, regb);
5674 if((ivideo->chip == XGI_40) &&
5675 ((ivideo->revision_id == 1) ||
5676 (ivideo->revision_id == 2))) {
5677 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5678 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5679 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5680 } else {
5681 outSISIDXREG(SISCR, 0x82, 0x88);
5682 outSISIDXREG(SISCR, 0x86, 0x00);
5683 inSISIDXREG(SISCR, 0x86, reg);
5684 outSISIDXREG(SISCR, 0x86, 0x88);
5685 outSISIDXREG(SISCR, 0x82, 0x77);
5686 outSISIDXREG(SISCR, 0x85, 0x00);
5687 inSISIDXREG(SISCR, 0x85, reg);
5688 outSISIDXREG(SISCR, 0x85, 0x88);
5689 inSISIDXREG(SISCR, 0x85, reg);
5690 v1 = cs160[regb]; v2 = cs158[regb];
5691 if(ivideo->haveXGIROM) {
5692 v1 = bios[regb + 0x160];
5693 v2 = bios[regb + 0x158];
5695 outSISIDXREG(SISCR, 0x85, v1);
5696 outSISIDXREG(SISCR, 0x82, v2);
5698 if(ivideo->chip == XGI_40) {
5699 outSISIDXREG(SISCR, 0x97, 0x11);
5701 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5702 outSISIDXREG(SISCR, 0x98, 0x01);
5703 } else {
5704 outSISIDXREG(SISCR, 0x98, 0x03);
5706 outSISIDXREG(SISCR, 0x9a, 0x02);
5708 if(ivideo->chip == XGI_40) {
5709 outSISIDXREG(SISSR, 0x18, 0x01);
5710 } else {
5711 outSISIDXREG(SISSR, 0x18, 0x00);
5713 outSISIDXREG(SISSR, 0x19, 0x40);
5714 outSISIDXREG(SISSR, 0x16, 0x00);
5715 outSISIDXREG(SISSR, 0x16, 0x80);
5716 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5717 sisfb_post_xgi_delay(ivideo, 0x43);
5718 sisfb_post_xgi_delay(ivideo, 0x43);
5719 sisfb_post_xgi_delay(ivideo, 0x43);
5720 outSISIDXREG(SISSR, 0x18, 0x00);
5721 outSISIDXREG(SISSR, 0x19, 0x40);
5722 outSISIDXREG(SISSR, 0x16, 0x00);
5723 outSISIDXREG(SISSR, 0x16, 0x80);
5725 sisfb_post_xgi_delay(ivideo, 4);
5726 v1 = 0x31;
5727 if(ivideo->haveXGIROM) {
5728 v1 = bios[0xf0];
5730 outSISIDXREG(SISSR, 0x18, v1);
5731 outSISIDXREG(SISSR, 0x19, 0x01);
5732 if(ivideo->chip == XGI_40) {
5733 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5734 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5735 } else {
5736 outSISIDXREG(SISSR, 0x16, 0x05);
5737 outSISIDXREG(SISSR, 0x16, 0x85);
5739 sisfb_post_xgi_delay(ivideo, 0x43);
5740 if(ivideo->chip == XGI_40) {
5741 outSISIDXREG(SISSR, 0x1b, 0x01);
5742 } else {
5743 outSISIDXREG(SISSR, 0x1b, 0x03);
5745 sisfb_post_xgi_delay(ivideo, 0x22);
5746 outSISIDXREG(SISSR, 0x18, v1);
5747 outSISIDXREG(SISSR, 0x19, 0x00);
5748 if(ivideo->chip == XGI_40) {
5749 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5750 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5751 } else {
5752 outSISIDXREG(SISSR, 0x16, 0x05);
5753 outSISIDXREG(SISSR, 0x16, 0x85);
5755 outSISIDXREG(SISSR, 0x1b, 0x00);
5758 regb = 0; /* ! */
5759 v1 = 0x03;
5760 if(ivideo->haveXGIROM) {
5761 v1 = bios[0x110 + regb];
5763 outSISIDXREG(SISSR, 0x1b, v1);
5765 /* RAM size */
5766 v1 = 0x00; v2 = 0x00;
5767 if(ivideo->haveXGIROM) {
5768 v1 = bios[0x62];
5769 v2 = bios[0x63];
5771 regb = 0; /* ! */
5772 regd = 1 << regb;
5773 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5775 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5776 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5778 } else {
5780 /* Set default mode, don't clear screen */
5781 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5782 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5783 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5784 ivideo->curFSTN = ivideo->curDSTN = 0;
5785 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5786 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5788 outSISIDXREG(SISSR, 0x05, 0x86);
5790 /* Disable read-cache */
5791 andSISIDXREG(SISSR, 0x21, 0xdf);
5792 sisfb_post_xgi_ramsize(ivideo);
5793 /* Enable read-cache */
5794 orSISIDXREG(SISSR, 0x21, 0x20);
5798 #if 0
5799 printk(KERN_DEBUG "-----------------\n");
5800 for(i = 0; i < 0xff; i++) {
5801 inSISIDXREG(SISCR, i, reg);
5802 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5804 for(i = 0; i < 0x40; i++) {
5805 inSISIDXREG(SISSR, i, reg);
5806 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5808 printk(KERN_DEBUG "-----------------\n");
5809 #endif
5811 /* Sense CRT1 */
5812 if(ivideo->chip == XGI_20) {
5813 orSISIDXREG(SISCR, 0x32, 0x20);
5814 } else {
5815 inSISIDXREG(SISPART4, 0x00, reg);
5816 if((reg == 1) || (reg == 2)) {
5817 sisfb_sense_crt1(ivideo);
5818 } else {
5819 orSISIDXREG(SISCR, 0x32, 0x20);
5823 /* Set default mode, don't clear screen */
5824 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5825 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5826 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5827 ivideo->curFSTN = ivideo->curDSTN = 0;
5828 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5830 outSISIDXREG(SISSR, 0x05, 0x86);
5832 /* Display off */
5833 orSISIDXREG(SISSR, 0x01, 0x20);
5835 /* Save mode number in CR34 */
5836 outSISIDXREG(SISCR, 0x34, 0x2e);
5838 /* Let everyone know what the current mode is */
5839 ivideo->modeprechange = 0x2e;
5841 if(ivideo->chip == XGI_40) {
5842 inSISIDXREG(SISCR, 0xca, reg);
5843 inSISIDXREG(SISCR, 0xcc, v1);
5844 if((reg & 0x10) && (!(v1 & 0x04))) {
5845 printk(KERN_ERR
5846 "sisfb: Please connect power to the card.\n");
5847 return 0;
5851 return 1;
5853 #endif
5855 static int __devinit
5856 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5858 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5859 struct sis_video_info *ivideo = NULL;
5860 struct fb_info *sis_fb_info = NULL;
5861 u16 reg16;
5862 u8 reg;
5863 int i, ret;
5865 if(sisfb_off)
5866 return -ENXIO;
5868 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5869 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5870 if(!sis_fb_info)
5871 return -ENOMEM;
5872 #else
5873 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
5874 if(!sis_fb_info)
5875 return -ENOMEM;
5876 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5877 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5878 #endif
5880 ivideo = (struct sis_video_info *)sis_fb_info->par;
5881 ivideo->memyselfandi = sis_fb_info;
5883 ivideo->sisfb_id = SISFB_ID;
5885 if(card_list == NULL) {
5886 ivideo->cardnumber = 0;
5887 } else {
5888 struct sis_video_info *countvideo = card_list;
5889 ivideo->cardnumber = 1;
5890 while((countvideo = countvideo->next) != 0)
5891 ivideo->cardnumber++;
5894 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5896 ivideo->warncount = 0;
5897 ivideo->chip_id = pdev->device;
5898 ivideo->chip_vendor = pdev->vendor;
5899 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
5900 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5901 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
5902 ivideo->sisvga_enabled = reg16 & 0x01;
5903 ivideo->pcibus = pdev->bus->number;
5904 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5905 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5906 ivideo->subsysvendor = pdev->subsystem_vendor;
5907 ivideo->subsysdevice = pdev->subsystem_device;
5908 #ifdef SIS_OLD_CONFIG_COMPAT
5909 ivideo->ioctl32registered = 0;
5910 #endif
5912 #ifndef MODULE
5913 if(sisfb_mode_idx == -1) {
5914 sisfb_get_vga_mode_from_kernel();
5916 #endif
5918 ivideo->chip = chipinfo->chip;
5919 ivideo->sisvga_engine = chipinfo->vgaengine;
5920 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5921 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5922 ivideo->mni = chipinfo->mni;
5924 ivideo->detectedpdc = 0xff;
5925 ivideo->detectedpdca = 0xff;
5926 ivideo->detectedlcda = 0xff;
5928 ivideo->sisfb_thismonitor.datavalid = FALSE;
5930 ivideo->current_base = 0;
5932 ivideo->engineok = 0;
5934 ivideo->sisfb_was_boot_device = 0;
5935 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5936 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5937 if(ivideo->sisvga_enabled)
5938 ivideo->sisfb_was_boot_device = 1;
5939 else {
5940 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5941 "but marked as boot video device ???\n");
5942 printk(KERN_DEBUG "sisfb: I will not accept this "
5943 "as the primary VGA device\n");
5946 #endif
5948 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5949 ivideo->sisfb_accel = sisfb_accel;
5950 ivideo->sisfb_ypan = sisfb_ypan;
5951 ivideo->sisfb_max = sisfb_max;
5952 ivideo->sisfb_userom = sisfb_userom;
5953 ivideo->sisfb_useoem = sisfb_useoem;
5954 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5955 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5956 ivideo->sisfb_crt1off = sisfb_crt1off;
5957 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5958 ivideo->sisfb_crt2type = sisfb_crt2type;
5959 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5960 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5961 ivideo->sisfb_dstn = sisfb_dstn;
5962 ivideo->sisfb_fstn = sisfb_fstn;
5963 ivideo->sisfb_tvplug = sisfb_tvplug;
5964 ivideo->sisfb_tvstd = sisfb_tvstd;
5965 ivideo->tvxpos = sisfb_tvxposoffset;
5966 ivideo->tvypos = sisfb_tvyposoffset;
5967 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5968 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5969 ivideo->sisfb_inverse = sisfb_inverse;
5970 #endif
5972 ivideo->refresh_rate = 0;
5973 if(ivideo->sisfb_parm_rate != -1) {
5974 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5977 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5978 ivideo->SiS_Pr.CenterScreen = -1;
5979 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5980 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5982 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5983 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5984 ivideo->SiS_Pr.SiS_ChSW = FALSE;
5985 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5986 ivideo->SiS_Pr.HaveEMI = FALSE;
5987 ivideo->SiS_Pr.HaveEMILCD = FALSE;
5988 ivideo->SiS_Pr.OverruleEMI = FALSE;
5989 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
5990 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5991 ivideo->SiS_Pr.PDC = -1;
5992 ivideo->SiS_Pr.PDCA = -1;
5993 ivideo->SiS_Pr.DDCPortMixup = FALSE;
5994 #ifdef CONFIG_FB_SIS_315
5995 if(ivideo->chip >= SIS_330) {
5996 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5997 if(ivideo->chip >= SIS_661) {
5998 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
6001 #endif
6003 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6005 pci_set_drvdata(pdev, ivideo);
6007 /* Patch special cases */
6008 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6009 switch(ivideo->nbridge->device) {
6010 #ifdef CONFIG_FB_SIS_300
6011 case PCI_DEVICE_ID_SI_730:
6012 ivideo->chip = SIS_730;
6013 strcpy(ivideo->myid, "SiS 730");
6014 break;
6015 #endif
6016 #ifdef CONFIG_FB_SIS_315
6017 case PCI_DEVICE_ID_SI_651:
6018 /* ivideo->chip is ok */
6019 strcpy(ivideo->myid, "SiS 651");
6020 break;
6021 case PCI_DEVICE_ID_SI_740:
6022 ivideo->chip = SIS_740;
6023 strcpy(ivideo->myid, "SiS 740");
6024 break;
6025 case PCI_DEVICE_ID_SI_661:
6026 ivideo->chip = SIS_661;
6027 strcpy(ivideo->myid, "SiS 661");
6028 break;
6029 case PCI_DEVICE_ID_SI_741:
6030 ivideo->chip = SIS_741;
6031 strcpy(ivideo->myid, "SiS 741");
6032 break;
6033 case PCI_DEVICE_ID_SI_760:
6034 ivideo->chip = SIS_760;
6035 strcpy(ivideo->myid, "SiS 760");
6036 break;
6037 case PCI_DEVICE_ID_SI_761:
6038 ivideo->chip = SIS_761;
6039 strcpy(ivideo->myid, "SiS 761");
6040 break;
6041 #endif
6042 default:
6043 break;
6047 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6048 strcpy(sis_fb_info->modename, ivideo->myid);
6049 #endif
6051 ivideo->SiS_Pr.ChipType = ivideo->chip;
6053 ivideo->SiS_Pr.ivideo = (void *)ivideo;
6055 #ifdef CONFIG_FB_SIS_315
6056 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6057 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6058 ivideo->SiS_Pr.ChipType = SIS_315H;
6060 #endif
6062 if(!ivideo->sisvga_enabled) {
6063 if(pci_enable_device(pdev)) {
6064 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6065 pci_set_drvdata(pdev, NULL);
6066 kfree(sis_fb_info);
6067 return -EIO;
6071 ivideo->video_base = pci_resource_start(pdev, 0);
6072 ivideo->mmio_base = pci_resource_start(pdev, 1);
6073 ivideo->mmio_size = pci_resource_len(pdev, 1);
6074 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
6075 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
6077 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
6079 #ifdef CONFIG_FB_SIS_300
6080 /* Find PCI systems for Chrontel/GPIO communication setup */
6081 if(ivideo->chip == SIS_630) {
6082 i = 0;
6083 do {
6084 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6085 mychswtable[i].subsysCard == ivideo->subsysdevice) {
6086 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6087 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6088 "requiring Chrontel/GPIO setup\n",
6089 mychswtable[i].vendorName,
6090 mychswtable[i].cardName);
6091 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6092 break;
6094 i++;
6095 } while(mychswtable[i].subsysVendor != 0);
6097 #endif
6099 #ifdef CONFIG_FB_SIS_315
6100 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6101 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
6103 #endif
6105 outSISIDXREG(SISSR, 0x05, 0x86);
6107 if( (!ivideo->sisvga_enabled)
6108 #if !defined(__i386__) && !defined(__x86_64__)
6109 || (sisfb_resetcard)
6110 #endif
6112 for(i = 0x30; i <= 0x3f; i++) {
6113 outSISIDXREG(SISCR, i, 0x00);
6117 /* Find out about current video mode */
6118 ivideo->modeprechange = 0x03;
6119 inSISIDXREG(SISCR, 0x34, reg);
6120 if(reg & 0x7f) {
6121 ivideo->modeprechange = reg & 0x7f;
6122 } else if(ivideo->sisvga_enabled) {
6123 #if defined(__i386__) || defined(__x86_64__)
6124 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
6125 if(tt) {
6126 ivideo->modeprechange = readb(tt + 0x49);
6127 iounmap(tt);
6129 #endif
6132 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6133 #ifdef MODULE
6134 if((reg & 0x80) && (reg != 0xff)) {
6135 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6136 != 0xFF) {
6137 printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6138 "X server is active\n");
6139 ret = -EBUSY;
6140 goto error_4;
6143 #endif
6144 #endif
6146 /* Search and copy ROM image */
6147 ivideo->bios_abase = NULL;
6148 ivideo->SiS_Pr.VirtualRomBase = NULL;
6149 ivideo->SiS_Pr.UseROM = FALSE;
6150 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
6151 if(ivideo->sisfb_userom) {
6152 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6153 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6154 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6155 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6156 ivideo->SiS_Pr.UseROM ? "" : "not ");
6157 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6158 ivideo->SiS_Pr.UseROM = FALSE;
6159 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6160 if( (ivideo->revision_id == 2) &&
6161 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6162 ivideo->SiS_Pr.DDCPortMixup = TRUE;
6165 } else {
6166 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6169 /* Find systems for special custom timing */
6170 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6171 sisfb_detect_custom_timing(ivideo);
6174 /* POST card in case this has not been done by the BIOS */
6175 if( (!ivideo->sisvga_enabled)
6176 #if !defined(__i386__) && !defined(__x86_64__)
6177 || (sisfb_resetcard)
6178 #endif
6180 #ifdef CONFIG_FB_SIS_300
6181 if(ivideo->sisvga_engine == SIS_300_VGA) {
6182 if(ivideo->chip == SIS_300) {
6183 sisfb_post_sis300(pdev);
6184 ivideo->sisfb_can_post = 1;
6187 #endif
6189 #ifdef CONFIG_FB_SIS_315
6190 if(ivideo->sisvga_engine == SIS_315_VGA) {
6191 int result = 1;
6192 /* if((ivideo->chip == SIS_315H) ||
6193 (ivideo->chip == SIS_315) ||
6194 (ivideo->chip == SIS_315PRO) ||
6195 (ivideo->chip == SIS_330)) {
6196 sisfb_post_sis315330(pdev);
6197 } else */ if(ivideo->chip == XGI_20) {
6198 result = sisfb_post_xgi(pdev);
6199 ivideo->sisfb_can_post = 1;
6200 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6201 result = sisfb_post_xgi(pdev);
6202 ivideo->sisfb_can_post = 1;
6203 } else {
6204 printk(KERN_INFO "sisfb: Card is not "
6205 "POSTed and sisfb can't do this either.\n");
6207 if(!result) {
6208 printk(KERN_ERR "sisfb: Failed to POST card\n");
6209 ret = -ENODEV;
6210 goto error_3;
6213 #endif
6216 ivideo->sisfb_card_posted = 1;
6218 /* Find out about RAM size */
6219 if(sisfb_get_dram_size(ivideo)) {
6220 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6221 ret = -ENODEV;
6222 goto error_3;
6226 /* Enable PCI addressing and MMIO */
6227 if((ivideo->sisfb_mode_idx < 0) ||
6228 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6229 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6230 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6231 /* Enable 2D accelerator engine */
6232 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6235 if(sisfb_pdc != 0xff) {
6236 if(ivideo->sisvga_engine == SIS_300_VGA)
6237 sisfb_pdc &= 0x3c;
6238 else
6239 sisfb_pdc &= 0x1f;
6240 ivideo->SiS_Pr.PDC = sisfb_pdc;
6242 #ifdef CONFIG_FB_SIS_315
6243 if(ivideo->sisvga_engine == SIS_315_VGA) {
6244 if(sisfb_pdca != 0xff)
6245 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6247 #endif
6249 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6250 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6251 (int)(ivideo->video_size >> 20));
6252 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6253 ret = -ENODEV;
6254 goto error_3;
6257 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6258 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6259 ret = -ENODEV;
6260 goto error_2;
6263 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6264 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6265 if(!ivideo->video_vbase) {
6266 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6267 ret = -ENODEV;
6268 goto error_1;
6271 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6272 if(!ivideo->mmio_vbase) {
6273 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6274 ret = -ENODEV;
6275 error_0: iounmap(ivideo->video_vbase);
6276 error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6277 error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6278 error_3: vfree(ivideo->bios_abase);
6279 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6280 error_4:
6281 #endif
6282 if(ivideo->lpcdev)
6283 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6284 if(ivideo->nbridge)
6285 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6286 pci_set_drvdata(pdev, NULL);
6287 if(!ivideo->sisvga_enabled)
6288 pci_disable_device(pdev);
6289 kfree(sis_fb_info);
6290 return ret;
6293 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6294 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6296 if(ivideo->video_offset) {
6297 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6298 ivideo->video_offset / 1024);
6301 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6302 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6305 /* Determine the size of the command queue */
6306 if(ivideo->sisvga_engine == SIS_300_VGA) {
6307 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6308 } else {
6309 if(ivideo->chip == XGI_20) {
6310 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6311 } else {
6312 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6316 /* Engines are no longer initialized here; this is
6317 * now done after the first mode-switch (if the
6318 * submitted var has its acceleration flags set).
6321 /* Calculate the base of the (unused) hw cursor */
6322 ivideo->hwcursor_vbase = ivideo->video_vbase
6323 + ivideo->video_size
6324 - ivideo->cmdQueueSize
6325 - ivideo->hwcursor_size;
6326 ivideo->caps |= HW_CURSOR_CAP;
6328 /* Initialize offscreen memory manager */
6329 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6330 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6333 /* Used for clearing the screen only, therefore respect our mem limit */
6334 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6335 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6337 ivideo->mtrr = -1;
6339 ivideo->vbflags = 0;
6340 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6341 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6342 ivideo->defmodeidx = DEFAULT_MODE;
6344 ivideo->newrom = 0;
6345 if(ivideo->chip < XGI_20) {
6346 if(ivideo->bios_abase) {
6347 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6351 if((ivideo->sisfb_mode_idx < 0) ||
6352 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6354 sisfb_sense_crt1(ivideo);
6356 sisfb_get_VB_type(ivideo);
6358 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6359 sisfb_detect_VB_connect(ivideo);
6362 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6364 /* Decide on which CRT2 device to use */
6365 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6366 if(ivideo->sisfb_crt2type != -1) {
6367 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6368 (ivideo->vbflags & CRT2_LCD)) {
6369 ivideo->currentvbflags |= CRT2_LCD;
6370 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6371 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6373 } else {
6374 /* Chrontel 700x TV detection often unreliable, therefore
6375 * use a different default order on such machines
6377 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6378 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6379 if(ivideo->vbflags & CRT2_LCD)
6380 ivideo->currentvbflags |= CRT2_LCD;
6381 else if(ivideo->vbflags & CRT2_TV)
6382 ivideo->currentvbflags |= CRT2_TV;
6383 else if(ivideo->vbflags & CRT2_VGA)
6384 ivideo->currentvbflags |= CRT2_VGA;
6385 } else {
6386 if(ivideo->vbflags & CRT2_TV)
6387 ivideo->currentvbflags |= CRT2_TV;
6388 else if(ivideo->vbflags & CRT2_LCD)
6389 ivideo->currentvbflags |= CRT2_LCD;
6390 else if(ivideo->vbflags & CRT2_VGA)
6391 ivideo->currentvbflags |= CRT2_VGA;
6396 if(ivideo->vbflags & CRT2_LCD) {
6397 sisfb_detect_lcd_type(ivideo);
6400 sisfb_save_pdc_emi(ivideo);
6402 if(!ivideo->sisfb_crt1off) {
6403 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6404 } else {
6405 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6406 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6407 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6411 if(ivideo->sisfb_mode_idx >= 0) {
6412 int bu = ivideo->sisfb_mode_idx;
6413 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6414 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6415 if(bu != ivideo->sisfb_mode_idx) {
6416 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6417 sisbios_mode[bu].xres,
6418 sisbios_mode[bu].yres,
6419 sisbios_mode[bu].bpp);
6423 if(ivideo->sisfb_mode_idx < 0) {
6424 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6425 case CRT2_LCD:
6426 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6427 break;
6428 case CRT2_TV:
6429 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6430 break;
6431 default:
6432 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6433 break;
6437 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6439 if(ivideo->refresh_rate != 0) {
6440 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6441 ivideo->sisfb_mode_idx);
6444 if(ivideo->rate_idx == 0) {
6445 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6446 ivideo->refresh_rate = 60;
6449 if(ivideo->sisfb_thismonitor.datavalid) {
6450 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6451 ivideo->sisfb_mode_idx,
6452 ivideo->rate_idx,
6453 ivideo->refresh_rate)) {
6454 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6455 "exceeds monitor specs!\n");
6459 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6460 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6461 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6463 sisfb_set_vparms(ivideo);
6465 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6467 /* ---------------- For 2.4: Now switch the mode ------------------ */
6469 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6470 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6471 ivideo->refresh_rate);
6473 /* Determine whether or not acceleration is to be
6474 * used. Need to know before pre/post_set_mode()
6476 ivideo->accel = 0;
6477 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6478 if(ivideo->sisfb_accel) {
6479 ivideo->accel = -1;
6480 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6483 /* Now switch the mode */
6484 sisfb_pre_setmode(ivideo);
6486 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
6487 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6488 ivideo->mode_no);
6489 ret = -EINVAL;
6490 iounmap(ivideo->mmio_vbase);
6491 goto error_0;
6494 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6496 sisfb_post_setmode(ivideo);
6498 /* Maximize regardless of sisfb_max at startup */
6499 ivideo->default_var.yres_virtual = 32767;
6501 /* Force reset of x virtual in crtc_to_var */
6502 ivideo->default_var.xres_virtual = 0;
6504 /* Copy mode timing to var */
6505 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6507 /* Find out about screen pitch */
6508 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6509 sisfb_set_pitch(ivideo);
6511 /* Init the accelerator (does nothing currently) */
6512 sisfb_initaccel(ivideo);
6514 /* Init some fbinfo entries */
6515 sis_fb_info->node = -1;
6516 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6517 sis_fb_info->fbops = &sisfb_ops;
6518 sis_fb_info->disp = &ivideo->sis_disp;
6519 sis_fb_info->blank = &sisfb_blank;
6520 sis_fb_info->switch_con = &sisfb_switch;
6521 sis_fb_info->updatevar = &sisfb_update_var;
6522 sis_fb_info->changevar = NULL;
6523 strcpy(sis_fb_info->fontname, sisfb_fontname);
6525 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6527 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6529 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6530 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6531 ivideo->refresh_rate);
6533 /* Set up the default var according to chosen default display mode */
6534 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6535 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6536 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6538 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6540 ivideo->default_var.pixclock = (u32) (1000000000 /
6541 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6543 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6544 ivideo->rate_idx, &ivideo->default_var)) {
6545 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6546 ivideo->default_var.pixclock <<= 1;
6550 if(ivideo->sisfb_ypan) {
6551 /* Maximize regardless of sisfb_max at startup */
6552 ivideo->default_var.yres_virtual =
6553 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6554 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6555 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6559 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6561 ivideo->accel = 0;
6562 if(ivideo->sisfb_accel) {
6563 ivideo->accel = -1;
6564 #ifdef STUPID_ACCELF_TEXT_SHIT
6565 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6566 #endif
6568 sisfb_initaccel(ivideo);
6570 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6571 sis_fb_info->flags = FBINFO_DEFAULT |
6572 FBINFO_HWACCEL_YPAN |
6573 FBINFO_HWACCEL_XPAN |
6574 FBINFO_HWACCEL_COPYAREA |
6575 FBINFO_HWACCEL_FILLRECT |
6576 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6577 #else
6578 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6579 #endif
6580 sis_fb_info->var = ivideo->default_var;
6581 sis_fb_info->fix = ivideo->sisfb_fix;
6582 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6583 sis_fb_info->fbops = &sisfb_ops;
6585 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6586 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6588 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6589 #endif /* 2.6 */
6591 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6593 #ifdef CONFIG_MTRR
6594 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6595 MTRR_TYPE_WRCOMB, 1);
6596 if(ivideo->mtrr < 0) {
6597 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6599 #endif
6601 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6602 vc_resize_con(1, 1, 0);
6603 #endif
6605 if(register_framebuffer(sis_fb_info) < 0) {
6606 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6607 ret = -EINVAL;
6608 iounmap(ivideo->mmio_vbase);
6609 goto error_0;
6612 ivideo->registered = 1;
6614 /* Enlist us */
6615 ivideo->next = card_list;
6616 card_list = ivideo;
6618 #ifdef SIS_OLD_CONFIG_COMPAT
6620 int ret;
6621 /* Our ioctls are all "32/64bit compatible" */
6622 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6623 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6624 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6625 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6626 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6627 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6628 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6629 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6630 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6631 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6632 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6633 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6634 if(ret)
6635 printk(KERN_ERR
6636 "sisfb: Error registering ioctl32 translations\n");
6637 else
6638 ivideo->ioctl32registered = 1;
6640 #endif
6642 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6643 ivideo->sisfb_accel ? "enabled" : "disabled",
6644 ivideo->sisfb_ypan ?
6645 (ivideo->sisfb_max ? "enabled (auto-max)" :
6646 "enabled (no auto-max)") :
6647 "disabled");
6650 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6651 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6652 GET_FB_IDX(sis_fb_info->node),
6653 #else
6654 sis_fb_info->node,
6655 #endif
6656 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6658 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6660 } /* if mode = "none" */
6662 return 0;
6665 /*****************************************************/
6666 /* PCI DEVICE HANDLING */
6667 /*****************************************************/
6669 static void __devexit sisfb_remove(struct pci_dev *pdev)
6671 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6672 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6673 int registered = ivideo->registered;
6674 int modechanged = ivideo->modechanged;
6676 #ifdef SIS_OLD_CONFIG_COMPAT
6677 if(ivideo->ioctl32registered) {
6678 int ret;
6679 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6680 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6681 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6682 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6683 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6684 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6685 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6686 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6687 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6688 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6689 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6690 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6691 if(ret)
6692 printk(KERN_ERR
6693 "sisfb: Error unregistering ioctl32 translations\n");
6695 #endif
6697 /* Unmap */
6698 iounmap(ivideo->mmio_vbase);
6699 iounmap(ivideo->video_vbase);
6701 /* Release mem regions */
6702 release_mem_region(ivideo->video_base, ivideo->video_size);
6703 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6705 vfree(ivideo->bios_abase);
6707 if(ivideo->lpcdev)
6708 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6710 if(ivideo->nbridge)
6711 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6713 #ifdef CONFIG_MTRR
6714 /* Release MTRR region */
6715 if(ivideo->mtrr >= 0)
6716 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6717 #endif
6719 pci_set_drvdata(pdev, NULL);
6721 /* If device was disabled when starting, disable
6722 * it when quitting.
6724 if(!ivideo->sisvga_enabled)
6725 pci_disable_device(pdev);
6727 /* Unregister the framebuffer */
6728 if(ivideo->registered) {
6729 unregister_framebuffer(sis_fb_info);
6730 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6731 framebuffer_release(sis_fb_info);
6732 #else
6733 kfree(sis_fb_info);
6734 #endif
6737 /* OK, our ivideo is gone for good from here. */
6739 /* TODO: Restore the initial mode
6740 * This sounds easy but is as good as impossible
6741 * on many machines with SiS chip and video bridge
6742 * since text modes are always set up differently
6743 * from machine to machine. Depends on the type
6744 * of integration between chipset and bridge.
6746 if(registered && modechanged)
6747 printk(KERN_INFO
6748 "sisfb: Restoring of text mode not supported yet\n");
6751 static struct pci_driver sisfb_driver = {
6752 .name = "sisfb",
6753 .id_table = sisfb_pci_table,
6754 .probe = sisfb_probe,
6755 .remove = __devexit_p(sisfb_remove)
6758 SISINITSTATIC int __init sisfb_init(void)
6760 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6761 #ifndef MODULE
6762 char *options = NULL;
6764 if(fb_get_options("sisfb", &options))
6765 return -ENODEV;
6767 sisfb_setup(options);
6768 #endif
6769 #endif
6770 return pci_register_driver(&sisfb_driver);
6773 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6774 #ifndef MODULE
6775 module_init(sisfb_init);
6776 #endif
6777 #endif
6779 /*****************************************************/
6780 /* MODULE */
6781 /*****************************************************/
6783 #ifdef MODULE
6785 static char *mode = NULL;
6786 static int vesa = -1;
6787 static unsigned int rate = 0;
6788 static unsigned int crt1off = 1;
6789 static unsigned int mem = 0;
6790 static char *forcecrt2type = NULL;
6791 static int forcecrt1 = -1;
6792 static int pdc = -1;
6793 static int pdc1 = -1;
6794 static int noaccel = -1;
6795 static int noypan = -1;
6796 static int nomax = -1;
6797 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6798 static int inverse = 0;
6799 #endif
6800 static int userom = -1;
6801 static int useoem = -1;
6802 static char *tvstandard = NULL;
6803 static int nocrt2rate = 0;
6804 static int scalelcd = -1;
6805 static char *specialtiming = NULL;
6806 static int lvdshl = -1;
6807 static int tvxposoffset = 0, tvyposoffset = 0;
6808 #if !defined(__i386__) && !defined(__x86_64__)
6809 static int resetcard = 0;
6810 static int videoram = 0;
6811 #endif
6813 static int __init sisfb_init_module(void)
6815 sisfb_setdefaultparms();
6817 if(rate)
6818 sisfb_parm_rate = rate;
6820 if((scalelcd == 0) || (scalelcd == 1))
6821 sisfb_scalelcd = scalelcd ^ 1;
6823 /* Need to check crt2 type first for fstn/dstn */
6825 if(forcecrt2type)
6826 sisfb_search_crt2type(forcecrt2type);
6828 if(tvstandard)
6829 sisfb_search_tvstd(tvstandard);
6831 if(mode)
6832 sisfb_search_mode(mode, FALSE);
6833 else if(vesa != -1)
6834 sisfb_search_vesamode(vesa, FALSE);
6836 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6838 sisfb_forcecrt1 = forcecrt1;
6839 if(forcecrt1 == 1)
6840 sisfb_crt1off = 0;
6841 else if(forcecrt1 == 0)
6842 sisfb_crt1off = 1;
6844 if(noaccel == 1)
6845 sisfb_accel = 0;
6846 else if(noaccel == 0)
6847 sisfb_accel = 1;
6849 if(noypan == 1)
6850 sisfb_ypan = 0;
6851 else if(noypan == 0)
6852 sisfb_ypan = 1;
6854 if(nomax == 1)
6855 sisfb_max = 0;
6856 else if(nomax == 0)
6857 sisfb_max = 1;
6859 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6860 if(inverse) sisfb_inverse = 1;
6861 #endif
6863 if(mem)
6864 sisfb_parm_mem = mem;
6866 if(userom != -1)
6867 sisfb_userom = userom;
6869 if(useoem != -1)
6870 sisfb_useoem = useoem;
6872 if(pdc != -1)
6873 sisfb_pdc = (pdc & 0x7f);
6875 if(pdc1 != -1)
6876 sisfb_pdca = (pdc1 & 0x1f);
6878 sisfb_nocrt2rate = nocrt2rate;
6880 if(specialtiming)
6881 sisfb_search_specialtiming(specialtiming);
6883 if((lvdshl >= 0) && (lvdshl <= 3))
6884 sisfb_lvdshl = lvdshl;
6886 sisfb_tvxposoffset = tvxposoffset;
6887 sisfb_tvyposoffset = tvyposoffset;
6889 #if !defined(__i386__) && !defined(__x86_64__)
6890 sisfb_resetcard = (resetcard) ? 1 : 0;
6891 if(videoram)
6892 sisfb_videoram = videoram;
6893 #endif
6895 return sisfb_init();
6898 static void __exit sisfb_remove_module(void)
6900 pci_unregister_driver(&sisfb_driver);
6901 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6904 module_init(sisfb_init_module);
6905 module_exit(sisfb_remove_module);
6907 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6908 MODULE_LICENSE("GPL");
6909 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6911 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6912 MODULE_PARM(mem, "i");
6913 MODULE_PARM(noaccel, "i");
6914 MODULE_PARM(noypan, "i");
6915 MODULE_PARM(nomax, "i");
6916 MODULE_PARM(userom, "i");
6917 MODULE_PARM(useoem, "i");
6918 MODULE_PARM(mode, "s");
6919 MODULE_PARM(vesa, "i");
6920 MODULE_PARM(rate, "i");
6921 MODULE_PARM(forcecrt1, "i");
6922 MODULE_PARM(forcecrt2type, "s");
6923 MODULE_PARM(scalelcd, "i");
6924 MODULE_PARM(pdc, "i");
6925 MODULE_PARM(pdc1, "i");
6926 MODULE_PARM(specialtiming, "s");
6927 MODULE_PARM(lvdshl, "i");
6928 MODULE_PARM(tvstandard, "s");
6929 MODULE_PARM(tvxposoffset, "i");
6930 MODULE_PARM(tvyposoffset, "i");
6931 MODULE_PARM(nocrt2rate, "i");
6932 MODULE_PARM(inverse, "i");
6933 #if !defined(__i386__) && !defined(__x86_64__)
6934 MODULE_PARM(resetcard, "i");
6935 MODULE_PARM(videoram, "i");
6936 #endif
6937 #endif
6939 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6940 module_param(mem, int, 0);
6941 module_param(noaccel, int, 0);
6942 module_param(noypan, int, 0);
6943 module_param(nomax, int, 0);
6944 module_param(userom, int, 0);
6945 module_param(useoem, int, 0);
6946 module_param(mode, charp, 0);
6947 module_param(vesa, int, 0);
6948 module_param(rate, int, 0);
6949 module_param(forcecrt1, int, 0);
6950 module_param(forcecrt2type, charp, 0);
6951 module_param(scalelcd, int, 0);
6952 module_param(pdc, int, 0);
6953 module_param(pdc1, int, 0);
6954 module_param(specialtiming, charp, 0);
6955 module_param(lvdshl, int, 0);
6956 module_param(tvstandard, charp, 0);
6957 module_param(tvxposoffset, int, 0);
6958 module_param(tvyposoffset, int, 0);
6959 module_param(nocrt2rate, int, 0);
6960 #if !defined(__i386__) && !defined(__x86_64__)
6961 module_param(resetcard, int, 0);
6962 module_param(videoram, int, 0);
6963 #endif
6964 #endif
6966 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6967 MODULE_PARM_DESC(mem,
6968 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6969 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6970 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6971 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6972 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6973 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6974 "for XFree86 4.x/X.org 6.7 and later.\n");
6975 #else
6976 MODULE_PARM_DESC(mem,
6977 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6978 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6979 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6980 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6981 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6982 "The value is to be specified without 'KB'.\n");
6983 #endif
6985 MODULE_PARM_DESC(noaccel,
6986 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6987 "(default: 0)\n");
6989 MODULE_PARM_DESC(noypan,
6990 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6991 "will be performed by redrawing the screen. (default: 0)\n");
6993 MODULE_PARM_DESC(nomax,
6994 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
6995 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6996 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6997 "enable the user to positively specify a virtual Y size of the screen using\n"
6998 "fbset. (default: 0)\n");
7000 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7001 MODULE_PARM_DESC(mode,
7002 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7003 "1024x768x16. Other formats supported include XxY-Depth and\n"
7004 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7005 "number, it will be interpreted as a VESA mode number. (default: none if\n"
7006 "sisfb is a module; this leaves the console untouched and the driver will\n"
7007 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7008 "is in the kernel)\n");
7009 MODULE_PARM_DESC(vesa,
7010 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7011 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
7012 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7013 "0x0103 if sisfb is in the kernel)\n");
7014 #endif
7016 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7017 MODULE_PARM_DESC(mode,
7018 "\nSelects the desired default display mode in the format XxYxDepth,\n"
7019 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
7020 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7021 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7023 MODULE_PARM_DESC(vesa,
7024 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7025 "0x117 (default: 0x0103)\n");
7026 #endif
7028 MODULE_PARM_DESC(rate,
7029 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7030 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7031 "will be ignored (default: 60)\n");
7033 MODULE_PARM_DESC(forcecrt1,
7034 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7035 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7036 "0=CRT1 OFF) (default: [autodetected])\n");
7038 MODULE_PARM_DESC(forcecrt2type,
7039 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7040 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7041 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7042 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7043 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7044 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7045 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7046 "depends on the very hardware in use. (default: [autodetected])\n");
7048 MODULE_PARM_DESC(scalelcd,
7049 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7050 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7051 "show black bars around the image, TMDS panels will probably do the scaling\n"
7052 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7054 MODULE_PARM_DESC(pdc,
7055 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
7056 "should detect this correctly in most cases; however, sometimes this is not\n"
7057 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
7058 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7059 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7060 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
7062 #ifdef CONFIG_FB_SIS_315
7063 MODULE_PARM_DESC(pdc1,
7064 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
7065 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7066 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7067 "implemented yet.\n");
7068 #endif
7070 MODULE_PARM_DESC(specialtiming,
7071 "\nPlease refer to documentation for more information on this option.\n");
7073 MODULE_PARM_DESC(lvdshl,
7074 "\nPlease refer to documentation for more information on this option.\n");
7076 MODULE_PARM_DESC(tvstandard,
7077 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7078 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7080 MODULE_PARM_DESC(tvxposoffset,
7081 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7082 "Default: 0\n");
7084 MODULE_PARM_DESC(tvyposoffset,
7085 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7086 "Default: 0\n");
7088 MODULE_PARM_DESC(nocrt2rate,
7089 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7090 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7092 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7093 MODULE_PARM_DESC(inverse,
7094 "\nSetting this to anything but 0 should invert the display colors, but this\n"
7095 "does not seem to work. (default: 0)\n");
7096 #endif
7098 #if !defined(__i386__) && !defined(__x86_64__)
7099 #ifdef CONFIG_FB_SIS_300
7100 MODULE_PARM_DESC(resetcard,
7101 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
7102 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7103 "currently). Default: 0\n");
7105 MODULE_PARM_DESC(videoram,
7106 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7107 "some non-x86 architectures where the memory auto detection fails. Only\n"
7108 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
7109 #endif
7110 #endif
7112 #endif /* /MODULE */
7114 /* _GPL only for new symbols. */
7115 EXPORT_SYMBOL(sis_malloc);
7116 EXPORT_SYMBOL(sis_free);
7117 EXPORT_SYMBOL_GPL(sis_malloc_new);
7118 EXPORT_SYMBOL_GPL(sis_free_new);