sisfb: delete obsolete PCI ROM bug workaround
[linux-2.6.git] / drivers / video / sis / sis_main.c
blob1073b70dd857997d336aac4ebcd62435b7efae27
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/module.h>
37 #include <linux/moduleparam.h>
38 #include <linux/kernel.h>
39 #include <linux/spinlock.h>
40 #include <linux/errno.h>
41 #include <linux/string.h>
42 #include <linux/mm.h>
43 #include <linux/screen_info.h>
44 #include <linux/slab.h>
45 #include <linux/fb.h>
46 #include <linux/selection.h>
47 #include <linux/ioport.h>
48 #include <linux/init.h>
49 #include <linux/pci.h>
50 #include <linux/vmalloc.h>
51 #include <linux/capability.h>
52 #include <linux/fs.h>
53 #include <linux/types.h>
54 #include <linux/uaccess.h>
55 #include <asm/io.h>
56 #ifdef CONFIG_MTRR
57 #include <asm/mtrr.h>
58 #endif
60 #include "sis.h"
61 #include "sis_main.h"
63 static void sisfb_handle_command(struct sis_video_info *ivideo,
64 struct sisfb_cmd *sisfb_command);
66 /* ------------------ Internal helper routines ----------------- */
68 static void __init
69 sisfb_setdefaultparms(void)
71 sisfb_off = 0;
72 sisfb_parm_mem = 0;
73 sisfb_accel = -1;
74 sisfb_ypan = -1;
75 sisfb_max = -1;
76 sisfb_userom = -1;
77 sisfb_useoem = -1;
78 sisfb_mode_idx = -1;
79 sisfb_parm_rate = -1;
80 sisfb_crt1off = 0;
81 sisfb_forcecrt1 = -1;
82 sisfb_crt2type = -1;
83 sisfb_crt2flags = 0;
84 sisfb_pdc = 0xff;
85 sisfb_pdca = 0xff;
86 sisfb_scalelcd = -1;
87 sisfb_specialtiming = CUT_NONE;
88 sisfb_lvdshl = -1;
89 sisfb_dstn = 0;
90 sisfb_fstn = 0;
91 sisfb_tvplug = -1;
92 sisfb_tvstd = -1;
93 sisfb_tvxposoffset = 0;
94 sisfb_tvyposoffset = 0;
95 sisfb_nocrt2rate = 0;
96 #if !defined(__i386__) && !defined(__x86_64__)
97 sisfb_resetcard = 0;
98 sisfb_videoram = 0;
99 #endif
102 /* ------------- Parameter parsing -------------- */
104 static void __devinit
105 sisfb_search_vesamode(unsigned int vesamode, bool quiet)
107 int i = 0, j = 0;
109 /* We don't know the hardware specs yet and there is no ivideo */
111 if(vesamode == 0) {
112 if(!quiet)
113 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
115 sisfb_mode_idx = DEFAULT_MODE;
117 return;
120 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
122 while(sisbios_mode[i++].mode_no[0] != 0) {
123 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
124 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
125 if(sisfb_fstn) {
126 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
127 sisbios_mode[i-1].mode_no[1] == 0x56 ||
128 sisbios_mode[i-1].mode_no[1] == 0x53)
129 continue;
130 } else {
131 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
132 sisbios_mode[i-1].mode_no[1] == 0x5b)
133 continue;
135 sisfb_mode_idx = i - 1;
136 j = 1;
137 break;
140 if((!j) && !quiet)
141 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
144 static void __devinit
145 sisfb_search_mode(char *name, bool quiet)
147 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
148 int i = 0;
149 char strbuf[16], strbuf1[20];
150 char *nameptr = name;
152 /* We don't know the hardware specs yet and there is no ivideo */
154 if(name == NULL) {
155 if(!quiet)
156 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
158 sisfb_mode_idx = DEFAULT_MODE;
159 return;
162 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
163 if(!quiet)
164 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
166 sisfb_mode_idx = DEFAULT_MODE;
167 return;
170 if(strlen(name) <= 19) {
171 strcpy(strbuf1, name);
172 for(i = 0; i < strlen(strbuf1); i++) {
173 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
176 /* This does some fuzzy mode naming detection */
177 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
178 if((rate <= 32) || (depth > 32)) {
179 j = rate; rate = depth; depth = j;
181 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
182 nameptr = strbuf;
183 sisfb_parm_rate = rate;
184 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
185 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
186 nameptr = strbuf;
187 } else {
188 xres = 0;
189 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
190 sprintf(strbuf, "%ux%ux8", xres, yres);
191 nameptr = strbuf;
192 } else {
193 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
194 return;
199 i = 0; j = 0;
200 while(sisbios_mode[i].mode_no[0] != 0) {
201 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
202 if(sisfb_fstn) {
203 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
204 sisbios_mode[i-1].mode_no[1] == 0x56 ||
205 sisbios_mode[i-1].mode_no[1] == 0x53)
206 continue;
207 } else {
208 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
209 sisbios_mode[i-1].mode_no[1] == 0x5b)
210 continue;
212 sisfb_mode_idx = i - 1;
213 j = 1;
214 break;
218 if((!j) && !quiet)
219 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
222 #ifndef MODULE
223 static void __devinit
224 sisfb_get_vga_mode_from_kernel(void)
226 #ifdef CONFIG_X86
227 char mymode[32];
228 int mydepth = screen_info.lfb_depth;
230 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
232 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
233 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
234 (mydepth >= 8) && (mydepth <= 32) ) {
236 if(mydepth == 24) mydepth = 32;
238 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
239 screen_info.lfb_height,
240 mydepth);
242 printk(KERN_DEBUG
243 "sisfb: Using vga mode %s pre-set by kernel as default\n",
244 mymode);
246 sisfb_search_mode(mymode, true);
248 #endif
249 return;
251 #endif
253 static void __init
254 sisfb_search_crt2type(const char *name)
256 int i = 0;
258 /* We don't know the hardware specs yet and there is no ivideo */
260 if(name == NULL) return;
262 while(sis_crt2type[i].type_no != -1) {
263 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
264 sisfb_crt2type = sis_crt2type[i].type_no;
265 sisfb_tvplug = sis_crt2type[i].tvplug_no;
266 sisfb_crt2flags = sis_crt2type[i].flags;
267 break;
269 i++;
272 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
273 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
275 if(sisfb_crt2type < 0)
276 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
279 static void __init
280 sisfb_search_tvstd(const char *name)
282 int i = 0;
284 /* We don't know the hardware specs yet and there is no ivideo */
286 if(name == NULL)
287 return;
289 while(sis_tvtype[i].type_no != -1) {
290 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
291 sisfb_tvstd = sis_tvtype[i].type_no;
292 break;
294 i++;
298 static void __init
299 sisfb_search_specialtiming(const char *name)
301 int i = 0;
302 bool found = false;
304 /* We don't know the hardware specs yet and there is no ivideo */
306 if(name == NULL)
307 return;
309 if(!strnicmp(name, "none", 4)) {
310 sisfb_specialtiming = CUT_FORCENONE;
311 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
312 } else {
313 while(mycustomttable[i].chipID != 0) {
314 if(!strnicmp(name,mycustomttable[i].optionName,
315 strlen(mycustomttable[i].optionName))) {
316 sisfb_specialtiming = mycustomttable[i].SpecialID;
317 found = true;
318 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
319 mycustomttable[i].vendorName,
320 mycustomttable[i].cardName,
321 mycustomttable[i].optionName);
322 break;
324 i++;
326 if(!found) {
327 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
328 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
329 i = 0;
330 while(mycustomttable[i].chipID != 0) {
331 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
332 mycustomttable[i].optionName,
333 mycustomttable[i].vendorName,
334 mycustomttable[i].cardName);
335 i++;
341 /* ----------- Various detection routines ----------- */
343 static void __devinit
344 sisfb_detect_custom_timing(struct sis_video_info *ivideo)
346 unsigned char *biosver = NULL;
347 unsigned char *biosdate = NULL;
348 bool footprint;
349 u32 chksum = 0;
350 int i, j;
352 if(ivideo->SiS_Pr.UseROM) {
353 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
354 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
355 for(i = 0; i < 32768; i++)
356 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
359 i = 0;
360 do {
361 if( (mycustomttable[i].chipID == ivideo->chip) &&
362 ((!strlen(mycustomttable[i].biosversion)) ||
363 (ivideo->SiS_Pr.UseROM &&
364 (!strncmp(mycustomttable[i].biosversion, biosver,
365 strlen(mycustomttable[i].biosversion))))) &&
366 ((!strlen(mycustomttable[i].biosdate)) ||
367 (ivideo->SiS_Pr.UseROM &&
368 (!strncmp(mycustomttable[i].biosdate, biosdate,
369 strlen(mycustomttable[i].biosdate))))) &&
370 ((!mycustomttable[i].bioschksum) ||
371 (ivideo->SiS_Pr.UseROM &&
372 (mycustomttable[i].bioschksum == chksum))) &&
373 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
374 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
375 footprint = true;
376 for(j = 0; j < 5; j++) {
377 if(mycustomttable[i].biosFootprintAddr[j]) {
378 if(ivideo->SiS_Pr.UseROM) {
379 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
380 mycustomttable[i].biosFootprintData[j]) {
381 footprint = false;
383 } else
384 footprint = false;
387 if(footprint) {
388 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
389 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
390 mycustomttable[i].vendorName,
391 mycustomttable[i].cardName);
392 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
393 mycustomttable[i].optionName);
394 break;
397 i++;
398 } while(mycustomttable[i].chipID);
401 static bool __devinit
402 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
404 int i, j, xres, yres, refresh, index;
405 u32 emodes;
407 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
408 buffer[2] != 0xff || buffer[3] != 0xff ||
409 buffer[4] != 0xff || buffer[5] != 0xff ||
410 buffer[6] != 0xff || buffer[7] != 0x00) {
411 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
412 return false;
415 if(buffer[0x12] != 0x01) {
416 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
417 buffer[0x12]);
418 return false;
421 monitor->feature = buffer[0x18];
423 if(!(buffer[0x14] & 0x80)) {
424 if(!(buffer[0x14] & 0x08)) {
425 printk(KERN_INFO
426 "sisfb: WARNING: Monitor does not support separate syncs\n");
430 if(buffer[0x13] >= 0x01) {
431 /* EDID V1 rev 1 and 2: Search for monitor descriptor
432 * to extract ranges
434 j = 0x36;
435 for(i=0; i<4; i++) {
436 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
437 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
438 buffer[j + 4] == 0x00) {
439 monitor->hmin = buffer[j + 7];
440 monitor->hmax = buffer[j + 8];
441 monitor->vmin = buffer[j + 5];
442 monitor->vmax = buffer[j + 6];
443 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
444 monitor->datavalid = true;
445 break;
447 j += 18;
451 if(!monitor->datavalid) {
452 /* Otherwise: Get a range from the list of supported
453 * Estabished Timings. This is not entirely accurate,
454 * because fixed frequency monitors are not supported
455 * that way.
457 monitor->hmin = 65535; monitor->hmax = 0;
458 monitor->vmin = 65535; monitor->vmax = 0;
459 monitor->dclockmax = 0;
460 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
461 for(i = 0; i < 13; i++) {
462 if(emodes & sisfb_ddcsmodes[i].mask) {
463 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
464 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
465 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
466 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
467 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
470 index = 0x26;
471 for(i = 0; i < 8; i++) {
472 xres = (buffer[index] + 31) * 8;
473 switch(buffer[index + 1] & 0xc0) {
474 case 0xc0: yres = (xres * 9) / 16; break;
475 case 0x80: yres = (xres * 4) / 5; break;
476 case 0x40: yres = (xres * 3) / 4; break;
477 default: yres = xres; break;
479 refresh = (buffer[index + 1] & 0x3f) + 60;
480 if((xres >= 640) && (yres >= 480)) {
481 for(j = 0; j < 8; j++) {
482 if((xres == sisfb_ddcfmodes[j].x) &&
483 (yres == sisfb_ddcfmodes[j].y) &&
484 (refresh == sisfb_ddcfmodes[j].v)) {
485 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
486 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
487 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
488 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
489 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
493 index += 2;
495 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
496 monitor->datavalid = true;
500 return monitor->datavalid;
503 static void __devinit
504 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
506 unsigned short temp, i, realcrtno = crtno;
507 unsigned char buffer[256];
509 monitor->datavalid = false;
511 if(crtno) {
512 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
513 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
514 else return;
517 if((ivideo->sisfb_crt1off) && (!crtno))
518 return;
520 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
521 realcrtno, 0, &buffer[0], ivideo->vbflags2);
522 if((!temp) || (temp == 0xffff)) {
523 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
524 return;
525 } else {
526 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
527 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
528 crtno + 1,
529 (temp & 0x1a) ? "" : "[none of the supported]",
530 (temp & 0x02) ? "2 " : "",
531 (temp & 0x08) ? "D&P" : "",
532 (temp & 0x10) ? "FPDI-2" : "");
533 if(temp & 0x02) {
534 i = 3; /* Number of retrys */
535 do {
536 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
537 realcrtno, 1, &buffer[0], ivideo->vbflags2);
538 } while((temp) && i--);
539 if(!temp) {
540 if(sisfb_interpret_edid(monitor, &buffer[0])) {
541 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
542 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
543 monitor->dclockmax / 1000);
544 } else {
545 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
547 } else {
548 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
550 } else {
551 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
556 /* -------------- Mode validation --------------- */
558 static bool
559 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
560 int mode_idx, int rate_idx, int rate)
562 int htotal, vtotal;
563 unsigned int dclock, hsync;
565 if(!monitor->datavalid)
566 return true;
568 if(mode_idx < 0)
569 return false;
571 /* Skip for 320x200, 320x240, 640x400 */
572 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
573 case 0x59:
574 case 0x41:
575 case 0x4f:
576 case 0x50:
577 case 0x56:
578 case 0x53:
579 case 0x2f:
580 case 0x5d:
581 case 0x5e:
582 return true;
583 #ifdef CONFIG_FB_SIS_315
584 case 0x5a:
585 case 0x5b:
586 if(ivideo->sisvga_engine == SIS_315_VGA) return true;
587 #endif
590 if(rate < (monitor->vmin - 1))
591 return false;
592 if(rate > (monitor->vmax + 1))
593 return false;
595 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
596 sisbios_mode[mode_idx].mode_no[ivideo->mni],
597 &htotal, &vtotal, rate_idx)) {
598 dclock = (htotal * vtotal * rate) / 1000;
599 if(dclock > (monitor->dclockmax + 1000))
600 return false;
601 hsync = dclock / htotal;
602 if(hsync < (monitor->hmin - 1))
603 return false;
604 if(hsync > (monitor->hmax + 1))
605 return false;
606 } else {
607 return false;
609 return true;
612 static int
613 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
615 u16 xres=0, yres, myres;
617 #ifdef CONFIG_FB_SIS_300
618 if(ivideo->sisvga_engine == SIS_300_VGA) {
619 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
620 return -1 ;
622 #endif
623 #ifdef CONFIG_FB_SIS_315
624 if(ivideo->sisvga_engine == SIS_315_VGA) {
625 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
626 return -1;
628 #endif
630 myres = sisbios_mode[myindex].yres;
632 switch(vbflags & VB_DISPTYPE_DISP2) {
634 case CRT2_LCD:
635 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
637 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
638 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
639 if(sisbios_mode[myindex].xres > xres)
640 return -1;
641 if(myres > yres)
642 return -1;
645 if(ivideo->sisfb_fstn) {
646 if(sisbios_mode[myindex].xres == 320) {
647 if(myres == 240) {
648 switch(sisbios_mode[myindex].mode_no[1]) {
649 case 0x50: myindex = MODE_FSTN_8; break;
650 case 0x56: myindex = MODE_FSTN_16; break;
651 case 0x53: return -1;
657 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
658 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
659 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
660 return -1;
662 break;
664 case CRT2_TV:
665 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
666 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
667 return -1;
669 break;
671 case CRT2_VGA:
672 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
673 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
674 return -1;
676 break;
679 return myindex;
682 static u8
683 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
685 int i = 0;
686 u16 xres = sisbios_mode[mode_idx].xres;
687 u16 yres = sisbios_mode[mode_idx].yres;
689 ivideo->rate_idx = 0;
690 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
691 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
692 if(sisfb_vrate[i].refresh == rate) {
693 ivideo->rate_idx = sisfb_vrate[i].idx;
694 break;
695 } else if(sisfb_vrate[i].refresh > rate) {
696 if((sisfb_vrate[i].refresh - rate) <= 3) {
697 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
698 rate, sisfb_vrate[i].refresh);
699 ivideo->rate_idx = sisfb_vrate[i].idx;
700 ivideo->refresh_rate = sisfb_vrate[i].refresh;
701 } else if((sisfb_vrate[i].idx != 1) &&
702 ((rate - sisfb_vrate[i-1].refresh) <= 2)) {
703 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
704 rate, sisfb_vrate[i-1].refresh);
705 ivideo->rate_idx = sisfb_vrate[i-1].idx;
706 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
708 break;
709 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
710 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
711 rate, sisfb_vrate[i].refresh);
712 ivideo->rate_idx = sisfb_vrate[i].idx;
713 break;
716 i++;
718 if(ivideo->rate_idx > 0) {
719 return ivideo->rate_idx;
720 } else {
721 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
722 rate, xres, yres);
723 return 0;
727 static bool
728 sisfb_bridgeisslave(struct sis_video_info *ivideo)
730 unsigned char P1_00;
732 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
733 return false;
735 inSISIDXREG(SISPART1,0x00,P1_00);
736 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
737 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
738 return true;
739 } else {
740 return false;
744 static bool
745 sisfballowretracecrt1(struct sis_video_info *ivideo)
747 u8 temp;
749 inSISIDXREG(SISCR,0x17,temp);
750 if(!(temp & 0x80))
751 return false;
753 inSISIDXREG(SISSR,0x1f,temp);
754 if(temp & 0xc0)
755 return false;
757 return true;
760 static bool
761 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
763 if(!sisfballowretracecrt1(ivideo))
764 return false;
766 if(inSISREG(SISINPSTAT) & 0x08)
767 return true;
768 else
769 return false;
772 static void
773 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
775 int watchdog;
777 if(!sisfballowretracecrt1(ivideo))
778 return;
780 watchdog = 65536;
781 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
782 watchdog = 65536;
783 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
786 static bool
787 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
789 unsigned char temp, reg;
791 switch(ivideo->sisvga_engine) {
792 case SIS_300_VGA: reg = 0x25; break;
793 case SIS_315_VGA: reg = 0x30; break;
794 default: return false;
797 inSISIDXREG(SISPART1, reg, temp);
798 if(temp & 0x02)
799 return true;
800 else
801 return false;
804 static bool
805 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
807 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
808 if(!sisfb_bridgeisslave(ivideo)) {
809 return sisfbcheckvretracecrt2(ivideo);
812 return sisfbcheckvretracecrt1(ivideo);
815 static u32
816 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
818 u8 idx, reg1, reg2, reg3, reg4;
819 u32 ret = 0;
821 (*vcount) = (*hcount) = 0;
823 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
825 ret |= (FB_VBLANK_HAVE_VSYNC |
826 FB_VBLANK_HAVE_HBLANK |
827 FB_VBLANK_HAVE_VBLANK |
828 FB_VBLANK_HAVE_VCOUNT |
829 FB_VBLANK_HAVE_HCOUNT);
830 switch(ivideo->sisvga_engine) {
831 case SIS_300_VGA: idx = 0x25; break;
832 default:
833 case SIS_315_VGA: idx = 0x30; break;
835 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
836 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
837 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
838 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
839 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
840 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
841 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
842 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
843 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
845 } else if(sisfballowretracecrt1(ivideo)) {
847 ret |= (FB_VBLANK_HAVE_VSYNC |
848 FB_VBLANK_HAVE_VBLANK |
849 FB_VBLANK_HAVE_VCOUNT |
850 FB_VBLANK_HAVE_HCOUNT);
851 reg1 = inSISREG(SISINPSTAT);
852 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
853 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
854 inSISIDXREG(SISCR,0x20,reg1);
855 inSISIDXREG(SISCR,0x1b,reg1);
856 inSISIDXREG(SISCR,0x1c,reg2);
857 inSISIDXREG(SISCR,0x1d,reg3);
858 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
859 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
862 return ret;
865 static int
866 sisfb_myblank(struct sis_video_info *ivideo, int blank)
868 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
869 bool backlight = true;
871 switch(blank) {
872 case FB_BLANK_UNBLANK: /* on */
873 sr01 = 0x00;
874 sr11 = 0x00;
875 sr1f = 0x00;
876 cr63 = 0x00;
877 p2_0 = 0x20;
878 p1_13 = 0x00;
879 backlight = true;
880 break;
881 case FB_BLANK_NORMAL: /* blank */
882 sr01 = 0x20;
883 sr11 = 0x00;
884 sr1f = 0x00;
885 cr63 = 0x00;
886 p2_0 = 0x20;
887 p1_13 = 0x00;
888 backlight = true;
889 break;
890 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
891 sr01 = 0x20;
892 sr11 = 0x08;
893 sr1f = 0x80;
894 cr63 = 0x40;
895 p2_0 = 0x40;
896 p1_13 = 0x80;
897 backlight = false;
898 break;
899 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
900 sr01 = 0x20;
901 sr11 = 0x08;
902 sr1f = 0x40;
903 cr63 = 0x40;
904 p2_0 = 0x80;
905 p1_13 = 0x40;
906 backlight = false;
907 break;
908 case FB_BLANK_POWERDOWN: /* off */
909 sr01 = 0x20;
910 sr11 = 0x08;
911 sr1f = 0xc0;
912 cr63 = 0x40;
913 p2_0 = 0xc0;
914 p1_13 = 0xc0;
915 backlight = false;
916 break;
917 default:
918 return 1;
921 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
923 if( (!ivideo->sisfb_thismonitor.datavalid) ||
924 ((ivideo->sisfb_thismonitor.datavalid) &&
925 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
927 if(ivideo->sisvga_engine == SIS_315_VGA) {
928 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
931 if(!(sisfb_bridgeisslave(ivideo))) {
932 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
933 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
939 if(ivideo->currentvbflags & CRT2_LCD) {
941 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
942 if(backlight) {
943 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
944 } else {
945 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
947 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
948 #ifdef CONFIG_FB_SIS_315
949 if(ivideo->vbflags2 & VB2_CHRONTEL) {
950 if(backlight) {
951 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
952 } else {
953 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
956 #endif
959 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
960 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
961 ((ivideo->sisvga_engine == SIS_315_VGA) &&
962 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
963 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
966 if(ivideo->sisvga_engine == SIS_300_VGA) {
967 if((ivideo->vbflags2 & VB2_30xB) &&
968 (!(ivideo->vbflags2 & VB2_30xBDH))) {
969 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
971 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
972 if((ivideo->vbflags2 & VB2_30xB) &&
973 (!(ivideo->vbflags2 & VB2_30xBDH))) {
974 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
978 } else if(ivideo->currentvbflags & CRT2_VGA) {
980 if(ivideo->vbflags2 & VB2_30xB) {
981 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
986 return 0;
989 /* ------------- Callbacks from init.c/init301.c -------------- */
991 #ifdef CONFIG_FB_SIS_300
992 unsigned int
993 sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
995 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
996 u32 val = 0;
998 pci_read_config_dword(ivideo->nbridge, reg, &val);
999 return (unsigned int)val;
1002 void
1003 sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1005 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1007 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1010 unsigned int
1011 sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1013 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1014 u32 val = 0;
1016 if(!ivideo->lpcdev) return 0;
1018 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1019 return (unsigned int)val;
1021 #endif
1023 #ifdef CONFIG_FB_SIS_315
1024 void
1025 sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1027 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1029 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1032 unsigned int
1033 sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1035 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1036 u16 val = 0;
1038 if(!ivideo->lpcdev) return 0;
1040 pci_read_config_word(ivideo->lpcdev, reg, &val);
1041 return (unsigned int)val;
1043 #endif
1045 /* ----------- FBDev related routines for all series ----------- */
1047 static int
1048 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1050 return (var->bits_per_pixel == 8) ? 256 : 16;
1053 static void
1054 sisfb_set_vparms(struct sis_video_info *ivideo)
1056 switch(ivideo->video_bpp) {
1057 case 8:
1058 ivideo->DstColor = 0x0000;
1059 ivideo->SiS310_AccelDepth = 0x00000000;
1060 ivideo->video_cmap_len = 256;
1061 break;
1062 case 16:
1063 ivideo->DstColor = 0x8000;
1064 ivideo->SiS310_AccelDepth = 0x00010000;
1065 ivideo->video_cmap_len = 16;
1066 break;
1067 case 32:
1068 ivideo->DstColor = 0xC000;
1069 ivideo->SiS310_AccelDepth = 0x00020000;
1070 ivideo->video_cmap_len = 16;
1071 break;
1072 default:
1073 ivideo->video_cmap_len = 16;
1074 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1075 ivideo->accel = 0;
1079 static int
1080 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1082 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1084 if(maxyres > 32767) maxyres = 32767;
1086 return maxyres;
1089 static void
1090 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1092 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1093 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1094 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1095 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1096 ivideo->scrnpitchCRT1 <<= 1;
1101 static void
1102 sisfb_set_pitch(struct sis_video_info *ivideo)
1104 bool isslavemode = false;
1105 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1106 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1108 if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
1110 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1111 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1112 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1113 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1116 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1117 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1118 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1119 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1120 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1124 static void
1125 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1127 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1129 switch(var->bits_per_pixel) {
1130 case 8:
1131 var->red.offset = var->green.offset = var->blue.offset = 0;
1132 var->red.length = var->green.length = var->blue.length = 8;
1133 break;
1134 case 16:
1135 var->red.offset = 11;
1136 var->red.length = 5;
1137 var->green.offset = 5;
1138 var->green.length = 6;
1139 var->blue.offset = 0;
1140 var->blue.length = 5;
1141 var->transp.offset = 0;
1142 var->transp.length = 0;
1143 break;
1144 case 32:
1145 var->red.offset = 16;
1146 var->red.length = 8;
1147 var->green.offset = 8;
1148 var->green.length = 8;
1149 var->blue.offset = 0;
1150 var->blue.length = 8;
1151 var->transp.offset = 24;
1152 var->transp.length = 8;
1153 break;
1157 static int
1158 sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1160 unsigned short modeno = ivideo->mode_no;
1162 /* >=2.6.12's fbcon clears the screen anyway */
1163 modeno |= 0x80;
1165 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1167 sisfb_pre_setmode(ivideo);
1169 if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
1170 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1171 return -EINVAL;
1174 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1176 sisfb_post_setmode(ivideo);
1178 return 0;
1182 static int
1183 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1185 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1186 unsigned int htotal = 0, vtotal = 0;
1187 unsigned int drate = 0, hrate = 0;
1188 int found_mode = 0, ret;
1189 int old_mode;
1190 u32 pixclock;
1192 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1194 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1196 pixclock = var->pixclock;
1198 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1199 vtotal += var->yres;
1200 vtotal <<= 1;
1201 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1202 vtotal += var->yres;
1203 vtotal <<= 2;
1204 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1205 vtotal += var->yres;
1206 vtotal <<= 1;
1207 } else vtotal += var->yres;
1209 if(!(htotal) || !(vtotal)) {
1210 DPRINTK("sisfb: Invalid 'var' information\n");
1211 return -EINVAL;
1214 if(pixclock && htotal && vtotal) {
1215 drate = 1000000000 / pixclock;
1216 hrate = (drate * 1000) / htotal;
1217 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1218 } else {
1219 ivideo->refresh_rate = 60;
1222 old_mode = ivideo->sisfb_mode_idx;
1223 ivideo->sisfb_mode_idx = 0;
1225 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1226 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1227 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1228 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1229 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1230 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1231 found_mode = 1;
1232 break;
1234 ivideo->sisfb_mode_idx++;
1237 if(found_mode) {
1238 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1239 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1240 } else {
1241 ivideo->sisfb_mode_idx = -1;
1244 if(ivideo->sisfb_mode_idx < 0) {
1245 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1246 var->yres, var->bits_per_pixel);
1247 ivideo->sisfb_mode_idx = old_mode;
1248 return -EINVAL;
1251 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1253 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1254 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1255 ivideo->refresh_rate = 60;
1258 if(isactive) {
1259 /* If acceleration to be used? Need to know
1260 * before pre/post_set_mode()
1262 ivideo->accel = 0;
1263 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1264 #ifdef STUPID_ACCELF_TEXT_SHIT
1265 if(var->accel_flags & FB_ACCELF_TEXT) {
1266 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1267 } else {
1268 info->flags |= FBINFO_HWACCEL_DISABLED;
1270 #endif
1271 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1272 #else
1273 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1274 #endif
1276 if((ret = sisfb_set_mode(ivideo, 1))) {
1277 return ret;
1280 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1281 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1282 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1284 sisfb_calc_pitch(ivideo, var);
1285 sisfb_set_pitch(ivideo);
1287 sisfb_set_vparms(ivideo);
1289 ivideo->current_width = ivideo->video_width;
1290 ivideo->current_height = ivideo->video_height;
1291 ivideo->current_bpp = ivideo->video_bpp;
1292 ivideo->current_htotal = htotal;
1293 ivideo->current_vtotal = vtotal;
1294 ivideo->current_linelength = ivideo->video_linelength;
1295 ivideo->current_pixclock = var->pixclock;
1296 ivideo->current_refresh_rate = ivideo->refresh_rate;
1297 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1300 return 0;
1303 static void
1304 sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1306 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1308 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1309 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1310 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1311 if(ivideo->sisvga_engine == SIS_315_VGA) {
1312 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1316 static void
1317 sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1319 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1320 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1321 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1322 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1323 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1324 if(ivideo->sisvga_engine == SIS_315_VGA) {
1325 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1330 static int
1331 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1333 if(var->xoffset > (var->xres_virtual - var->xres)) {
1334 return -EINVAL;
1336 if(var->yoffset > (var->yres_virtual - var->yres)) {
1337 return -EINVAL;
1340 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
1342 /* calculate base bpp dep. */
1343 switch(var->bits_per_pixel) {
1344 case 32:
1345 break;
1346 case 16:
1347 ivideo->current_base >>= 1;
1348 break;
1349 case 8:
1350 default:
1351 ivideo->current_base >>= 2;
1352 break;
1355 ivideo->current_base += (ivideo->video_offset >> 2);
1357 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1358 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1360 return 0;
1363 static int
1364 sisfb_open(struct fb_info *info, int user)
1366 return 0;
1369 static int
1370 sisfb_release(struct fb_info *info, int user)
1372 return 0;
1375 static int
1376 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1377 unsigned transp, struct fb_info *info)
1379 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1381 if(regno >= sisfb_get_cmap_len(&info->var))
1382 return 1;
1384 switch(info->var.bits_per_pixel) {
1385 case 8:
1386 outSISREG(SISDACA, regno);
1387 outSISREG(SISDACD, (red >> 10));
1388 outSISREG(SISDACD, (green >> 10));
1389 outSISREG(SISDACD, (blue >> 10));
1390 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1391 outSISREG(SISDAC2A, regno);
1392 outSISREG(SISDAC2D, (red >> 8));
1393 outSISREG(SISDAC2D, (green >> 8));
1394 outSISREG(SISDAC2D, (blue >> 8));
1396 break;
1397 case 16:
1398 if (regno >= 16)
1399 break;
1401 ((u32 *)(info->pseudo_palette))[regno] =
1402 (red & 0xf800) |
1403 ((green & 0xfc00) >> 5) |
1404 ((blue & 0xf800) >> 11);
1405 break;
1406 case 32:
1407 if (regno >= 16)
1408 break;
1410 red >>= 8;
1411 green >>= 8;
1412 blue >>= 8;
1413 ((u32 *)(info->pseudo_palette))[regno] =
1414 (red << 16) | (green << 8) | (blue);
1415 break;
1417 return 0;
1420 static int
1421 sisfb_set_par(struct fb_info *info)
1423 int err;
1425 if((err = sisfb_do_set_var(&info->var, 1, info)))
1426 return err;
1428 sisfb_get_fix(&info->fix, -1, info);
1430 return 0;
1433 static int
1434 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1436 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1437 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1438 unsigned int drate = 0, hrate = 0, maxyres;
1439 int found_mode = 0;
1440 int refresh_rate, search_idx, tidx;
1441 bool recalc_clock = false;
1442 u32 pixclock;
1444 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1446 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1448 pixclock = var->pixclock;
1450 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1451 vtotal += var->yres;
1452 vtotal <<= 1;
1453 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1454 vtotal += var->yres;
1455 vtotal <<= 2;
1456 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1457 vtotal += var->yres;
1458 vtotal <<= 1;
1459 } else
1460 vtotal += var->yres;
1462 if(!(htotal) || !(vtotal)) {
1463 SISFAIL("sisfb: no valid timing data");
1466 search_idx = 0;
1467 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1468 (sisbios_mode[search_idx].xres <= var->xres) ) {
1469 if( (sisbios_mode[search_idx].xres == var->xres) &&
1470 (sisbios_mode[search_idx].yres == var->yres) &&
1471 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1472 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1473 ivideo->currentvbflags)) > 0) {
1474 found_mode = 1;
1475 search_idx = tidx;
1476 break;
1479 search_idx++;
1482 if(!found_mode) {
1483 search_idx = 0;
1484 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1485 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1486 (var->yres <= sisbios_mode[search_idx].yres) &&
1487 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1488 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1489 ivideo->currentvbflags)) > 0) {
1490 found_mode = 1;
1491 search_idx = tidx;
1492 break;
1495 search_idx++;
1497 if(found_mode) {
1498 printk(KERN_DEBUG
1499 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1500 var->xres, var->yres, var->bits_per_pixel,
1501 sisbios_mode[search_idx].xres,
1502 sisbios_mode[search_idx].yres,
1503 var->bits_per_pixel);
1504 var->xres = sisbios_mode[search_idx].xres;
1505 var->yres = sisbios_mode[search_idx].yres;
1506 } else {
1507 printk(KERN_ERR
1508 "sisfb: Failed to find supported mode near %dx%dx%d\n",
1509 var->xres, var->yres, var->bits_per_pixel);
1510 return -EINVAL;
1514 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1515 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1516 (var->bits_per_pixel == 8) ) {
1517 /* Slave modes on LVDS and 301B-DH */
1518 refresh_rate = 60;
1519 recalc_clock = true;
1520 } else if( (ivideo->current_htotal == htotal) &&
1521 (ivideo->current_vtotal == vtotal) &&
1522 (ivideo->current_pixclock == pixclock) ) {
1523 /* x=x & y=y & c=c -> assume depth change */
1524 drate = 1000000000 / pixclock;
1525 hrate = (drate * 1000) / htotal;
1526 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1527 } else if( ( (ivideo->current_htotal != htotal) ||
1528 (ivideo->current_vtotal != vtotal) ) &&
1529 (ivideo->current_pixclock == var->pixclock) ) {
1530 /* x!=x | y!=y & c=c -> invalid pixclock */
1531 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1532 refresh_rate =
1533 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1534 } else if(ivideo->sisfb_parm_rate != -1) {
1535 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1536 refresh_rate = ivideo->sisfb_parm_rate;
1537 } else {
1538 refresh_rate = 60;
1540 recalc_clock = true;
1541 } else if((pixclock) && (htotal) && (vtotal)) {
1542 drate = 1000000000 / pixclock;
1543 hrate = (drate * 1000) / htotal;
1544 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1545 } else if(ivideo->current_refresh_rate) {
1546 refresh_rate = ivideo->current_refresh_rate;
1547 recalc_clock = true;
1548 } else {
1549 refresh_rate = 60;
1550 recalc_clock = true;
1553 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1555 /* Eventually recalculate timing and clock */
1556 if(recalc_clock) {
1557 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1558 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1559 sisbios_mode[search_idx].mode_no[ivideo->mni],
1560 myrateindex));
1561 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1562 sisbios_mode[search_idx].mode_no[ivideo->mni],
1563 myrateindex, var);
1564 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1565 var->pixclock <<= 1;
1569 if(ivideo->sisfb_thismonitor.datavalid) {
1570 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1571 myrateindex, refresh_rate)) {
1572 printk(KERN_INFO
1573 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1577 /* Adapt RGB settings */
1578 sisfb_bpp_to_var(ivideo, var);
1580 /* Sanity check for offsets */
1581 if(var->xoffset < 0) var->xoffset = 0;
1582 if(var->yoffset < 0) var->yoffset = 0;
1584 if(var->xres > var->xres_virtual)
1585 var->xres_virtual = var->xres;
1587 if(ivideo->sisfb_ypan) {
1588 maxyres = sisfb_calc_maxyres(ivideo, var);
1589 if(ivideo->sisfb_max) {
1590 var->yres_virtual = maxyres;
1591 } else {
1592 if(var->yres_virtual > maxyres) {
1593 var->yres_virtual = maxyres;
1596 if(var->yres_virtual <= var->yres) {
1597 var->yres_virtual = var->yres;
1599 } else {
1600 if(var->yres != var->yres_virtual) {
1601 var->yres_virtual = var->yres;
1603 var->xoffset = 0;
1604 var->yoffset = 0;
1607 /* Truncate offsets to maximum if too high */
1608 if(var->xoffset > var->xres_virtual - var->xres) {
1609 var->xoffset = var->xres_virtual - var->xres - 1;
1612 if(var->yoffset > var->yres_virtual - var->yres) {
1613 var->yoffset = var->yres_virtual - var->yres - 1;
1616 /* Set everything else to 0 */
1617 var->red.msb_right =
1618 var->green.msb_right =
1619 var->blue.msb_right =
1620 var->transp.offset =
1621 var->transp.length =
1622 var->transp.msb_right = 0;
1624 return 0;
1627 static int
1628 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1630 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1631 int err;
1633 if(var->xoffset > (var->xres_virtual - var->xres))
1634 return -EINVAL;
1636 if(var->yoffset > (var->yres_virtual - var->yres))
1637 return -EINVAL;
1639 if(var->vmode & FB_VMODE_YWRAP)
1640 return -EINVAL;
1642 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
1643 var->yoffset + info->var.yres > info->var.yres_virtual)
1644 return -EINVAL;
1646 if((err = sisfb_pan_var(ivideo, var)) < 0)
1647 return err;
1649 info->var.xoffset = var->xoffset;
1650 info->var.yoffset = var->yoffset;
1652 return 0;
1655 static int
1656 sisfb_blank(int blank, struct fb_info *info)
1658 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1660 return sisfb_myblank(ivideo, blank);
1663 /* ----------- FBDev related routines for all series ---------- */
1665 static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1666 unsigned long arg)
1668 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1669 struct sis_memreq sismemreq;
1670 struct fb_vblank sisvbblank;
1671 u32 gpu32 = 0;
1672 #ifndef __user
1673 #define __user
1674 #endif
1675 u32 __user *argp = (u32 __user *)arg;
1677 switch(cmd) {
1678 case FBIO_ALLOC:
1679 if(!capable(CAP_SYS_RAWIO))
1680 return -EPERM;
1682 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1683 return -EFAULT;
1685 sis_malloc(&sismemreq);
1687 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1688 sis_free((u32)sismemreq.offset);
1689 return -EFAULT;
1691 break;
1693 case FBIO_FREE:
1694 if(!capable(CAP_SYS_RAWIO))
1695 return -EPERM;
1697 if(get_user(gpu32, argp))
1698 return -EFAULT;
1700 sis_free(gpu32);
1701 break;
1703 case FBIOGET_VBLANK:
1705 memset(&sisvbblank, 0, sizeof(struct fb_vblank));
1707 sisvbblank.count = 0;
1708 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1710 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1711 return -EFAULT;
1713 break;
1715 case SISFB_GET_INFO_SIZE:
1716 return put_user(sizeof(struct sisfb_info), argp);
1718 case SISFB_GET_INFO_OLD:
1719 if(ivideo->warncount++ < 10)
1720 printk(KERN_INFO
1721 "sisfb: Deprecated ioctl call received - update your application!\n");
1722 case SISFB_GET_INFO: /* For communication with X driver */
1723 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1724 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1725 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1726 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1727 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1728 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1729 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1730 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1731 if(ivideo->modechanged) {
1732 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1733 } else {
1734 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1736 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1737 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1738 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1739 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1740 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1741 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1742 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1743 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1744 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1745 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1746 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1747 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1748 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1749 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1750 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1751 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1752 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1753 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1754 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1755 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1756 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1757 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1758 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1759 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1760 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1761 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1762 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1763 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1765 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1766 sizeof(ivideo->sisfb_infoblock)))
1767 return -EFAULT;
1769 break;
1771 case SISFB_GET_VBRSTATUS_OLD:
1772 if(ivideo->warncount++ < 10)
1773 printk(KERN_INFO
1774 "sisfb: Deprecated ioctl call received - update your application!\n");
1775 case SISFB_GET_VBRSTATUS:
1776 if(sisfb_CheckVBRetrace(ivideo))
1777 return put_user((u32)1, argp);
1778 else
1779 return put_user((u32)0, argp);
1781 case SISFB_GET_AUTOMAXIMIZE_OLD:
1782 if(ivideo->warncount++ < 10)
1783 printk(KERN_INFO
1784 "sisfb: Deprecated ioctl call received - update your application!\n");
1785 case SISFB_GET_AUTOMAXIMIZE:
1786 if(ivideo->sisfb_max)
1787 return put_user((u32)1, argp);
1788 else
1789 return put_user((u32)0, argp);
1791 case SISFB_SET_AUTOMAXIMIZE_OLD:
1792 if(ivideo->warncount++ < 10)
1793 printk(KERN_INFO
1794 "sisfb: Deprecated ioctl call received - update your application!\n");
1795 case SISFB_SET_AUTOMAXIMIZE:
1796 if(get_user(gpu32, argp))
1797 return -EFAULT;
1799 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1800 break;
1802 case SISFB_SET_TVPOSOFFSET:
1803 if(get_user(gpu32, argp))
1804 return -EFAULT;
1806 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1807 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1808 break;
1810 case SISFB_GET_TVPOSOFFSET:
1811 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1812 argp);
1814 case SISFB_COMMAND:
1815 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1816 sizeof(struct sisfb_cmd)))
1817 return -EFAULT;
1819 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1821 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1822 sizeof(struct sisfb_cmd)))
1823 return -EFAULT;
1825 break;
1827 case SISFB_SET_LOCK:
1828 if(get_user(gpu32, argp))
1829 return -EFAULT;
1831 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1832 break;
1834 default:
1835 #ifdef SIS_NEW_CONFIG_COMPAT
1836 return -ENOIOCTLCMD;
1837 #else
1838 return -EINVAL;
1839 #endif
1841 return 0;
1844 static int
1845 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1847 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1849 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1851 strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
1853 mutex_lock(&info->mm_lock);
1854 fix->smem_start = ivideo->video_base + ivideo->video_offset;
1855 fix->smem_len = ivideo->sisfb_mem;
1856 mutex_unlock(&info->mm_lock);
1857 fix->type = FB_TYPE_PACKED_PIXELS;
1858 fix->type_aux = 0;
1859 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1860 fix->xpanstep = 1;
1861 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1862 fix->ywrapstep = 0;
1863 fix->line_length = ivideo->video_linelength;
1864 fix->mmio_start = ivideo->mmio_base;
1865 fix->mmio_len = ivideo->mmio_size;
1866 if(ivideo->sisvga_engine == SIS_300_VGA) {
1867 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1868 } else if((ivideo->chip == SIS_330) ||
1869 (ivideo->chip == SIS_760) ||
1870 (ivideo->chip == SIS_761)) {
1871 fix->accel = FB_ACCEL_SIS_XABRE;
1872 } else if(ivideo->chip == XGI_20) {
1873 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1874 } else if(ivideo->chip >= XGI_40) {
1875 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1876 } else {
1877 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1880 return 0;
1883 /* ---------------- fb_ops structures ----------------- */
1885 static struct fb_ops sisfb_ops = {
1886 .owner = THIS_MODULE,
1887 .fb_open = sisfb_open,
1888 .fb_release = sisfb_release,
1889 .fb_check_var = sisfb_check_var,
1890 .fb_set_par = sisfb_set_par,
1891 .fb_setcolreg = sisfb_setcolreg,
1892 .fb_pan_display = sisfb_pan_display,
1893 .fb_blank = sisfb_blank,
1894 .fb_fillrect = fbcon_sis_fillrect,
1895 .fb_copyarea = fbcon_sis_copyarea,
1896 .fb_imageblit = cfb_imageblit,
1897 .fb_sync = fbcon_sis_sync,
1898 #ifdef SIS_NEW_CONFIG_COMPAT
1899 .fb_compat_ioctl= sisfb_ioctl,
1900 #endif
1901 .fb_ioctl = sisfb_ioctl
1904 /* ---------------- Chip generation dependent routines ---------------- */
1906 static struct pci_dev * __devinit
1907 sisfb_get_northbridge(int basechipid)
1909 struct pci_dev *pdev = NULL;
1910 int nbridgenum, nbridgeidx, i;
1911 static const unsigned short nbridgeids[] = {
1912 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1913 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1914 PCI_DEVICE_ID_SI_730,
1915 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1916 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1917 PCI_DEVICE_ID_SI_651,
1918 PCI_DEVICE_ID_SI_740,
1919 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
1920 PCI_DEVICE_ID_SI_741,
1921 PCI_DEVICE_ID_SI_660,
1922 PCI_DEVICE_ID_SI_760,
1923 PCI_DEVICE_ID_SI_761
1926 switch(basechipid) {
1927 #ifdef CONFIG_FB_SIS_300
1928 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1929 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1930 #endif
1931 #ifdef CONFIG_FB_SIS_315
1932 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1933 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
1934 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
1935 #endif
1936 default: return NULL;
1938 for(i = 0; i < nbridgenum; i++) {
1939 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
1940 nbridgeids[nbridgeidx+i], NULL)))
1941 break;
1943 return pdev;
1946 static int __devinit
1947 sisfb_get_dram_size(struct sis_video_info *ivideo)
1949 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1950 u8 reg;
1951 #endif
1953 ivideo->video_size = 0;
1954 ivideo->UMAsize = ivideo->LFBsize = 0;
1956 switch(ivideo->chip) {
1957 #ifdef CONFIG_FB_SIS_300
1958 case SIS_300:
1959 inSISIDXREG(SISSR, 0x14, reg);
1960 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1961 break;
1962 case SIS_540:
1963 case SIS_630:
1964 case SIS_730:
1965 if(!ivideo->nbridge)
1966 return -1;
1967 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
1968 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1969 break;
1970 #endif
1971 #ifdef CONFIG_FB_SIS_315
1972 case SIS_315H:
1973 case SIS_315PRO:
1974 case SIS_315:
1975 inSISIDXREG(SISSR, 0x14, reg);
1976 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1977 switch((reg >> 2) & 0x03) {
1978 case 0x01:
1979 case 0x03:
1980 ivideo->video_size <<= 1;
1981 break;
1982 case 0x02:
1983 ivideo->video_size += (ivideo->video_size/2);
1985 break;
1986 case SIS_330:
1987 inSISIDXREG(SISSR, 0x14, reg);
1988 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1989 if(reg & 0x0c) ivideo->video_size <<= 1;
1990 break;
1991 case SIS_550:
1992 case SIS_650:
1993 case SIS_740:
1994 inSISIDXREG(SISSR, 0x14, reg);
1995 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
1996 break;
1997 case SIS_661:
1998 case SIS_741:
1999 inSISIDXREG(SISCR, 0x79, reg);
2000 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2001 break;
2002 case SIS_660:
2003 case SIS_760:
2004 case SIS_761:
2005 inSISIDXREG(SISCR, 0x79, reg);
2006 reg = (reg & 0xf0) >> 4;
2007 if(reg) {
2008 ivideo->video_size = (1 << reg) << 20;
2009 ivideo->UMAsize = ivideo->video_size;
2011 inSISIDXREG(SISCR, 0x78, reg);
2012 reg &= 0x30;
2013 if(reg) {
2014 if(reg == 0x10) {
2015 ivideo->LFBsize = (32 << 20);
2016 } else {
2017 ivideo->LFBsize = (64 << 20);
2019 ivideo->video_size += ivideo->LFBsize;
2021 break;
2022 case SIS_340:
2023 case XGI_20:
2024 case XGI_40:
2025 inSISIDXREG(SISSR, 0x14, reg);
2026 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2027 if(ivideo->chip != XGI_20) {
2028 reg = (reg & 0x0c) >> 2;
2029 if(ivideo->revision_id == 2) {
2030 if(reg & 0x01) reg = 0x02;
2031 else reg = 0x00;
2033 if(reg == 0x02) ivideo->video_size <<= 1;
2034 else if(reg == 0x03) ivideo->video_size <<= 2;
2036 break;
2037 #endif
2038 default:
2039 return -1;
2041 return 0;
2044 /* -------------- video bridge device detection --------------- */
2046 static void __devinit
2047 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2049 u8 cr32, temp;
2051 /* No CRT2 on XGI Z7 */
2052 if(ivideo->chip == XGI_20) {
2053 ivideo->sisfb_crt1off = 0;
2054 return;
2057 #ifdef CONFIG_FB_SIS_300
2058 if(ivideo->sisvga_engine == SIS_300_VGA) {
2059 inSISIDXREG(SISSR, 0x17, temp);
2060 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2061 /* PAL/NTSC is stored on SR16 on such machines */
2062 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2063 inSISIDXREG(SISSR, 0x16, temp);
2064 if(temp & 0x20)
2065 ivideo->vbflags |= TV_PAL;
2066 else
2067 ivideo->vbflags |= TV_NTSC;
2071 #endif
2073 inSISIDXREG(SISCR, 0x32, cr32);
2075 if(cr32 & SIS_CRT1) {
2076 ivideo->sisfb_crt1off = 0;
2077 } else {
2078 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2081 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2083 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2084 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2085 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2087 /* Check given parms for hardware compatibility.
2088 * (Cannot do this in the search_xx routines since we don't
2089 * know what hardware we are running on then)
2092 if(ivideo->chip != SIS_550) {
2093 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2096 if(ivideo->sisfb_tvplug != -1) {
2097 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2098 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2099 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2100 ivideo->sisfb_tvplug = -1;
2101 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2105 if(ivideo->sisfb_tvplug != -1) {
2106 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2107 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2108 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2109 ivideo->sisfb_tvplug = -1;
2110 printk(KERN_ERR "sisfb: HiVision not supported\n");
2114 if(ivideo->sisfb_tvstd != -1) {
2115 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2116 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2117 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2118 if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
2119 ivideo->sisfb_tvstd = -1;
2120 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2125 /* Detect/set TV plug & type */
2126 if(ivideo->sisfb_tvplug != -1) {
2127 ivideo->vbflags |= ivideo->sisfb_tvplug;
2128 } else {
2129 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2130 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2131 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2132 else {
2133 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2134 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2138 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2139 if(ivideo->sisfb_tvstd != -1) {
2140 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2141 ivideo->vbflags |= ivideo->sisfb_tvstd;
2143 if(ivideo->vbflags & TV_SCART) {
2144 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2145 ivideo->vbflags |= TV_PAL;
2147 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2148 if(ivideo->sisvga_engine == SIS_300_VGA) {
2149 inSISIDXREG(SISSR, 0x38, temp);
2150 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2151 else ivideo->vbflags |= TV_NTSC;
2152 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2153 inSISIDXREG(SISSR, 0x38, temp);
2154 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2155 else ivideo->vbflags |= TV_NTSC;
2156 } else {
2157 inSISIDXREG(SISCR, 0x79, temp);
2158 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2159 else ivideo->vbflags |= TV_NTSC;
2164 /* Copy forceCRT1 option to CRT1off if option is given */
2165 if(ivideo->sisfb_forcecrt1 != -1) {
2166 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2170 /* ------------------ Sensing routines ------------------ */
2172 static bool __devinit
2173 sisfb_test_DDC1(struct sis_video_info *ivideo)
2175 unsigned short old;
2176 int count = 48;
2178 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2179 do {
2180 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2181 } while(count--);
2182 return (count != -1);
2185 static void __devinit
2186 sisfb_sense_crt1(struct sis_video_info *ivideo)
2188 bool mustwait = false;
2189 u8 sr1F, cr17;
2190 #ifdef CONFIG_FB_SIS_315
2191 u8 cr63=0;
2192 #endif
2193 u16 temp = 0xffff;
2194 int i;
2196 inSISIDXREG(SISSR,0x1F,sr1F);
2197 orSISIDXREG(SISSR,0x1F,0x04);
2198 andSISIDXREG(SISSR,0x1F,0x3F);
2199 if(sr1F & 0xc0) mustwait = true;
2201 #ifdef CONFIG_FB_SIS_315
2202 if(ivideo->sisvga_engine == SIS_315_VGA) {
2203 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2204 cr63 &= 0x40;
2205 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2207 #endif
2209 inSISIDXREG(SISCR,0x17,cr17);
2210 cr17 &= 0x80;
2211 if(!cr17) {
2212 orSISIDXREG(SISCR,0x17,0x80);
2213 mustwait = true;
2214 outSISIDXREG(SISSR, 0x00, 0x01);
2215 outSISIDXREG(SISSR, 0x00, 0x03);
2218 if(mustwait) {
2219 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2222 #ifdef CONFIG_FB_SIS_315
2223 if(ivideo->chip >= SIS_330) {
2224 andSISIDXREG(SISCR,0x32,~0x20);
2225 if(ivideo->chip >= SIS_340) {
2226 outSISIDXREG(SISCR, 0x57, 0x4a);
2227 } else {
2228 outSISIDXREG(SISCR, 0x57, 0x5f);
2230 orSISIDXREG(SISCR, 0x53, 0x02);
2231 while((inSISREG(SISINPSTAT)) & 0x01) break;
2232 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2233 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2234 andSISIDXREG(SISCR, 0x53, 0xfd);
2235 andSISIDXREG(SISCR, 0x57, 0x00);
2237 #endif
2239 if(temp == 0xffff) {
2240 i = 3;
2241 do {
2242 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2243 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2244 } while(((temp == 0) || (temp == 0xffff)) && i--);
2246 if((temp == 0) || (temp == 0xffff)) {
2247 if(sisfb_test_DDC1(ivideo)) temp = 1;
2251 if((temp) && (temp != 0xffff)) {
2252 orSISIDXREG(SISCR,0x32,0x20);
2255 #ifdef CONFIG_FB_SIS_315
2256 if(ivideo->sisvga_engine == SIS_315_VGA) {
2257 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2259 #endif
2261 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2263 outSISIDXREG(SISSR,0x1F,sr1F);
2266 /* Determine and detect attached devices on SiS30x */
2267 static void __devinit
2268 SiS_SenseLCD(struct sis_video_info *ivideo)
2270 unsigned char buffer[256];
2271 unsigned short temp, realcrtno, i;
2272 u8 reg, cr37 = 0, paneltype = 0;
2273 u16 xres, yres;
2275 ivideo->SiS_Pr.PanelSelfDetected = false;
2277 /* LCD detection only for TMDS bridges */
2278 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2279 return;
2280 if(ivideo->vbflags2 & VB2_30xBDH)
2281 return;
2283 /* If LCD already set up by BIOS, skip it */
2284 inSISIDXREG(SISCR, 0x32, reg);
2285 if(reg & 0x08)
2286 return;
2288 realcrtno = 1;
2289 if(ivideo->SiS_Pr.DDCPortMixup)
2290 realcrtno = 0;
2292 /* Check DDC capabilities */
2293 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2294 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2296 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2297 return;
2299 /* Read DDC data */
2300 i = 3; /* Number of retrys */
2301 do {
2302 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2303 ivideo->sisvga_engine, realcrtno, 1,
2304 &buffer[0], ivideo->vbflags2);
2305 } while((temp) && i--);
2307 if(temp)
2308 return;
2310 /* No digital device */
2311 if(!(buffer[0x14] & 0x80))
2312 return;
2314 /* First detailed timing preferred timing? */
2315 if(!(buffer[0x18] & 0x02))
2316 return;
2318 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2319 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2321 switch(xres) {
2322 case 1024:
2323 if(yres == 768)
2324 paneltype = 0x02;
2325 break;
2326 case 1280:
2327 if(yres == 1024)
2328 paneltype = 0x03;
2329 break;
2330 case 1600:
2331 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2332 paneltype = 0x0b;
2333 break;
2336 if(!paneltype)
2337 return;
2339 if(buffer[0x23])
2340 cr37 |= 0x10;
2342 if((buffer[0x47] & 0x18) == 0x18)
2343 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2344 else
2345 cr37 |= 0xc0;
2347 outSISIDXREG(SISCR, 0x36, paneltype);
2348 cr37 &= 0xf1;
2349 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2350 orSISIDXREG(SISCR, 0x32, 0x08);
2352 ivideo->SiS_Pr.PanelSelfDetected = true;
2355 static int __devinit
2356 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2358 int temp, mytest, result, i, j;
2360 for(j = 0; j < 10; j++) {
2361 result = 0;
2362 for(i = 0; i < 3; i++) {
2363 mytest = test;
2364 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2365 temp = (type >> 8) | (mytest & 0x00ff);
2366 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2367 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2368 mytest >>= 8;
2369 mytest &= 0x7f;
2370 inSISIDXREG(SISPART4,0x03,temp);
2371 temp ^= 0x0e;
2372 temp &= mytest;
2373 if(temp == mytest) result++;
2374 #if 1
2375 outSISIDXREG(SISPART4,0x11,0x00);
2376 andSISIDXREG(SISPART4,0x10,0xe0);
2377 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2378 #endif
2380 if((result == 0) || (result >= 2)) break;
2382 return result;
2385 static void __devinit
2386 SiS_Sense30x(struct sis_video_info *ivideo)
2388 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2389 u16 svhs=0, svhs_c=0;
2390 u16 cvbs=0, cvbs_c=0;
2391 u16 vga2=0, vga2_c=0;
2392 int myflag, result;
2393 char stdstr[] = "sisfb: Detected";
2394 char tvstr[] = "TV connected to";
2396 if(ivideo->vbflags2 & VB2_301) {
2397 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2398 inSISIDXREG(SISPART4,0x01,myflag);
2399 if(myflag & 0x04) {
2400 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2402 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2403 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2404 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2405 svhs = 0x0200; cvbs = 0x0100;
2406 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2407 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2408 } else
2409 return;
2411 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2412 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2413 svhs_c = 0x0408; cvbs_c = 0x0808;
2416 biosflag = 2;
2417 if(ivideo->haveXGIROM) {
2418 biosflag = ivideo->bios_abase[0x58] & 0x03;
2419 } else if(ivideo->newrom) {
2420 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2421 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2422 if(ivideo->bios_abase) {
2423 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2427 if(ivideo->chip == SIS_300) {
2428 inSISIDXREG(SISSR,0x3b,myflag);
2429 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2432 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2433 vga2 = vga2_c = 0;
2436 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2437 orSISIDXREG(SISSR,0x1e,0x20);
2439 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2440 if(ivideo->vbflags2 & VB2_30xC) {
2441 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2442 } else {
2443 orSISIDXREG(SISPART4,0x0d,0x04);
2445 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2447 inSISIDXREG(SISPART2,0x00,backupP2_00);
2448 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2450 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2451 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2452 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2455 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2456 SISDoSense(ivideo, 0, 0);
2459 andSISIDXREG(SISCR, 0x32, ~0x14);
2461 if(vga2_c || vga2) {
2462 if(SISDoSense(ivideo, vga2, vga2_c)) {
2463 if(biosflag & 0x01) {
2464 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2465 orSISIDXREG(SISCR, 0x32, 0x04);
2466 } else {
2467 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2468 orSISIDXREG(SISCR, 0x32, 0x10);
2473 andSISIDXREG(SISCR, 0x32, 0x3f);
2475 if(ivideo->vbflags2 & VB2_30xCLV) {
2476 orSISIDXREG(SISPART4,0x0d,0x04);
2479 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2480 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2481 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2482 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2483 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2484 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2485 orSISIDXREG(SISCR,0x32,0x80);
2488 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2491 andSISIDXREG(SISCR, 0x32, ~0x03);
2493 if(!(ivideo->vbflags & TV_YPBPR)) {
2494 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2495 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2496 orSISIDXREG(SISCR, 0x32, 0x02);
2498 if((biosflag & 0x02) || (!result)) {
2499 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2500 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2501 orSISIDXREG(SISCR, 0x32, 0x01);
2506 SISDoSense(ivideo, 0, 0);
2508 outSISIDXREG(SISPART2,0x00,backupP2_00);
2509 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2510 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2512 if(ivideo->vbflags2 & VB2_30xCLV) {
2513 inSISIDXREG(SISPART2,0x00,biosflag);
2514 if(biosflag & 0x20) {
2515 for(myflag = 2; myflag > 0; myflag--) {
2516 biosflag ^= 0x20;
2517 outSISIDXREG(SISPART2,0x00,biosflag);
2522 outSISIDXREG(SISPART2,0x00,backupP2_00);
2525 /* Determine and detect attached TV's on Chrontel */
2526 static void __devinit
2527 SiS_SenseCh(struct sis_video_info *ivideo)
2529 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2530 u8 temp1, temp2;
2531 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2532 #endif
2533 #ifdef CONFIG_FB_SIS_300
2534 unsigned char test[3];
2535 int i;
2536 #endif
2538 if(ivideo->chip < SIS_315H) {
2540 #ifdef CONFIG_FB_SIS_300
2541 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2542 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2543 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2544 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2545 /* See Chrontel TB31 for explanation */
2546 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2547 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2548 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2549 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2551 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2552 if(temp2 != temp1) temp1 = temp2;
2554 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2555 /* Read power status */
2556 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2557 if((temp1 & 0x03) != 0x03) {
2558 /* Power all outputs */
2559 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2560 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2562 /* Sense connected TV devices */
2563 for(i = 0; i < 3; i++) {
2564 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2565 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2566 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2567 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2568 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2569 if(!(temp1 & 0x08)) test[i] = 0x02;
2570 else if(!(temp1 & 0x02)) test[i] = 0x01;
2571 else test[i] = 0;
2572 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2575 if(test[0] == test[1]) temp1 = test[0];
2576 else if(test[0] == test[2]) temp1 = test[0];
2577 else if(test[1] == test[2]) temp1 = test[1];
2578 else {
2579 printk(KERN_INFO
2580 "sisfb: TV detection unreliable - test results varied\n");
2581 temp1 = test[2];
2583 if(temp1 == 0x02) {
2584 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2585 ivideo->vbflags |= TV_SVIDEO;
2586 orSISIDXREG(SISCR, 0x32, 0x02);
2587 andSISIDXREG(SISCR, 0x32, ~0x05);
2588 } else if (temp1 == 0x01) {
2589 printk(KERN_INFO "%s CVBS output\n", stdstr);
2590 ivideo->vbflags |= TV_AVIDEO;
2591 orSISIDXREG(SISCR, 0x32, 0x01);
2592 andSISIDXREG(SISCR, 0x32, ~0x06);
2593 } else {
2594 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2595 andSISIDXREG(SISCR, 0x32, ~0x07);
2597 } else if(temp1 == 0) {
2598 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2599 andSISIDXREG(SISCR, 0x32, ~0x07);
2601 /* Set general purpose IO for Chrontel communication */
2602 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2603 #endif
2605 } else {
2607 #ifdef CONFIG_FB_SIS_315
2608 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2609 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2610 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2611 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2612 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2613 temp2 |= 0x01;
2614 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2615 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2616 temp2 ^= 0x01;
2617 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2618 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2619 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2620 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2621 temp1 = 0;
2622 if(temp2 & 0x02) temp1 |= 0x01;
2623 if(temp2 & 0x10) temp1 |= 0x01;
2624 if(temp2 & 0x04) temp1 |= 0x02;
2625 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2626 switch(temp1) {
2627 case 0x01:
2628 printk(KERN_INFO "%s CVBS output\n", stdstr);
2629 ivideo->vbflags |= TV_AVIDEO;
2630 orSISIDXREG(SISCR, 0x32, 0x01);
2631 andSISIDXREG(SISCR, 0x32, ~0x06);
2632 break;
2633 case 0x02:
2634 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2635 ivideo->vbflags |= TV_SVIDEO;
2636 orSISIDXREG(SISCR, 0x32, 0x02);
2637 andSISIDXREG(SISCR, 0x32, ~0x05);
2638 break;
2639 case 0x04:
2640 printk(KERN_INFO "%s SCART output\n", stdstr);
2641 orSISIDXREG(SISCR, 0x32, 0x04);
2642 andSISIDXREG(SISCR, 0x32, ~0x03);
2643 break;
2644 default:
2645 andSISIDXREG(SISCR, 0x32, ~0x07);
2647 #endif
2651 static void __devinit
2652 sisfb_get_VB_type(struct sis_video_info *ivideo)
2654 char stdstr[] = "sisfb: Detected";
2655 char bridgestr[] = "video bridge";
2656 u8 vb_chipid;
2657 u8 reg;
2659 /* No CRT2 on XGI Z7 */
2660 if(ivideo->chip == XGI_20)
2661 return;
2663 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2664 switch(vb_chipid) {
2665 case 0x01:
2666 inSISIDXREG(SISPART4, 0x01, reg);
2667 if(reg < 0xb0) {
2668 ivideo->vbflags |= VB_301; /* Deprecated */
2669 ivideo->vbflags2 |= VB2_301;
2670 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2671 } else if(reg < 0xc0) {
2672 ivideo->vbflags |= VB_301B; /* Deprecated */
2673 ivideo->vbflags2 |= VB2_301B;
2674 inSISIDXREG(SISPART4,0x23,reg);
2675 if(!(reg & 0x02)) {
2676 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2677 ivideo->vbflags2 |= VB2_30xBDH;
2678 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2679 } else {
2680 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2682 } else if(reg < 0xd0) {
2683 ivideo->vbflags |= VB_301C; /* Deprecated */
2684 ivideo->vbflags2 |= VB2_301C;
2685 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2686 } else if(reg < 0xe0) {
2687 ivideo->vbflags |= VB_301LV; /* Deprecated */
2688 ivideo->vbflags2 |= VB2_301LV;
2689 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2690 } else if(reg <= 0xe1) {
2691 inSISIDXREG(SISPART4,0x39,reg);
2692 if(reg == 0xff) {
2693 ivideo->vbflags |= VB_302LV; /* Deprecated */
2694 ivideo->vbflags2 |= VB2_302LV;
2695 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2696 } else {
2697 ivideo->vbflags |= VB_301C; /* Deprecated */
2698 ivideo->vbflags2 |= VB2_301C;
2699 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2700 #if 0
2701 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2702 ivideo->vbflags2 |= VB2_302ELV;
2703 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2704 #endif
2707 break;
2708 case 0x02:
2709 ivideo->vbflags |= VB_302B; /* Deprecated */
2710 ivideo->vbflags2 |= VB2_302B;
2711 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2712 break;
2715 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2716 inSISIDXREG(SISCR, 0x37, reg);
2717 reg &= SIS_EXTERNAL_CHIP_MASK;
2718 reg >>= 1;
2719 if(ivideo->sisvga_engine == SIS_300_VGA) {
2720 #ifdef CONFIG_FB_SIS_300
2721 switch(reg) {
2722 case SIS_EXTERNAL_CHIP_LVDS:
2723 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2724 ivideo->vbflags2 |= VB2_LVDS;
2725 break;
2726 case SIS_EXTERNAL_CHIP_TRUMPION:
2727 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2728 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2729 break;
2730 case SIS_EXTERNAL_CHIP_CHRONTEL:
2731 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2732 ivideo->vbflags2 |= VB2_CHRONTEL;
2733 break;
2734 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2735 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2736 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2737 break;
2739 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2740 #endif
2741 } else if(ivideo->chip < SIS_661) {
2742 #ifdef CONFIG_FB_SIS_315
2743 switch (reg) {
2744 case SIS310_EXTERNAL_CHIP_LVDS:
2745 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2746 ivideo->vbflags2 |= VB2_LVDS;
2747 break;
2748 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2749 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2750 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2751 break;
2753 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2754 #endif
2755 } else if(ivideo->chip >= SIS_661) {
2756 #ifdef CONFIG_FB_SIS_315
2757 inSISIDXREG(SISCR, 0x38, reg);
2758 reg >>= 5;
2759 switch(reg) {
2760 case 0x02:
2761 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2762 ivideo->vbflags2 |= VB2_LVDS;
2763 break;
2764 case 0x03:
2765 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2766 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2767 break;
2768 case 0x04:
2769 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2770 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2771 break;
2773 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2774 #endif
2776 if(ivideo->vbflags2 & VB2_LVDS) {
2777 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2779 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2780 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2782 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2783 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2785 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2786 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2790 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2791 SiS_SenseLCD(ivideo);
2792 SiS_Sense30x(ivideo);
2793 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2794 SiS_SenseCh(ivideo);
2798 /* ---------- Engine initialization routines ------------ */
2800 static void
2801 sisfb_engine_init(struct sis_video_info *ivideo)
2804 /* Initialize command queue (we use MMIO only) */
2806 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2808 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2809 MMIO_CMD_QUEUE_CAP |
2810 VM_CMD_QUEUE_CAP |
2811 AGP_CMD_QUEUE_CAP);
2813 #ifdef CONFIG_FB_SIS_300
2814 if(ivideo->sisvga_engine == SIS_300_VGA) {
2815 u32 tqueue_pos;
2816 u8 tq_state;
2818 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2820 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2821 tq_state |= 0xf0;
2822 tq_state &= 0xfc;
2823 tq_state |= (u8)(tqueue_pos >> 8);
2824 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2826 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2828 ivideo->caps |= TURBO_QUEUE_CAP;
2830 #endif
2832 #ifdef CONFIG_FB_SIS_315
2833 if(ivideo->sisvga_engine == SIS_315_VGA) {
2834 u32 tempq = 0, templ;
2835 u8 temp;
2837 if(ivideo->chip == XGI_20) {
2838 switch(ivideo->cmdQueueSize) {
2839 case (64 * 1024):
2840 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2841 break;
2842 case (128 * 1024):
2843 default:
2844 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2846 } else {
2847 switch(ivideo->cmdQueueSize) {
2848 case (4 * 1024 * 1024):
2849 temp = SIS_CMD_QUEUE_SIZE_4M;
2850 break;
2851 case (2 * 1024 * 1024):
2852 temp = SIS_CMD_QUEUE_SIZE_2M;
2853 break;
2854 case (1 * 1024 * 1024):
2855 temp = SIS_CMD_QUEUE_SIZE_1M;
2856 break;
2857 default:
2858 case (512 * 1024):
2859 temp = SIS_CMD_QUEUE_SIZE_512k;
2863 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2864 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2866 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2867 /* Must disable dual pipe on XGI_40. Can't do
2868 * this in MMIO mode, because it requires
2869 * setting/clearing a bit in the MMIO fire trigger
2870 * register.
2872 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2874 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2876 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2878 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2879 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2881 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2882 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2884 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2885 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2886 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2887 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2889 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2891 sisfb_syncaccel(ivideo);
2893 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2898 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2899 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2901 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2902 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2904 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2905 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2907 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2909 #endif
2911 ivideo->engineok = 1;
2914 static void __devinit
2915 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2917 u8 reg;
2918 int i;
2920 inSISIDXREG(SISCR, 0x36, reg);
2921 reg &= 0x0f;
2922 if(ivideo->sisvga_engine == SIS_300_VGA) {
2923 ivideo->CRT2LCDType = sis300paneltype[reg];
2924 } else if(ivideo->chip >= SIS_661) {
2925 ivideo->CRT2LCDType = sis661paneltype[reg];
2926 } else {
2927 ivideo->CRT2LCDType = sis310paneltype[reg];
2928 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2929 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2930 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2931 ivideo->CRT2LCDType = LCD_320x240;
2936 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2937 /* For broken BIOSes: Assume 1024x768, RGB18 */
2938 ivideo->CRT2LCDType = LCD_1024x768;
2939 setSISIDXREG(SISCR,0x36,0xf0,0x02);
2940 setSISIDXREG(SISCR,0x37,0xee,0x01);
2941 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2944 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2945 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2946 ivideo->lcdxres = sis_lcd_data[i].xres;
2947 ivideo->lcdyres = sis_lcd_data[i].yres;
2948 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2949 break;
2953 #ifdef CONFIG_FB_SIS_300
2954 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2955 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2956 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2957 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2958 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2959 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2960 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2961 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2962 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2964 #endif
2966 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2967 ivideo->lcdxres, ivideo->lcdyres);
2970 static void __devinit
2971 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2973 #ifdef CONFIG_FB_SIS_300
2974 /* Save the current PanelDelayCompensation if the LCD is currently used */
2975 if(ivideo->sisvga_engine == SIS_300_VGA) {
2976 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2977 int tmp;
2978 inSISIDXREG(SISCR,0x30,tmp);
2979 if(tmp & 0x20) {
2980 /* Currently on LCD? If yes, read current pdc */
2981 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2982 ivideo->detectedpdc &= 0x3c;
2983 if(ivideo->SiS_Pr.PDC == -1) {
2984 /* Let option override detection */
2985 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2987 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2988 ivideo->detectedpdc);
2990 if((ivideo->SiS_Pr.PDC != -1) &&
2991 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2992 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2993 ivideo->SiS_Pr.PDC);
2997 #endif
2999 #ifdef CONFIG_FB_SIS_315
3000 if(ivideo->sisvga_engine == SIS_315_VGA) {
3002 /* Try to find about LCDA */
3003 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3004 int tmp;
3005 inSISIDXREG(SISPART1,0x13,tmp);
3006 if(tmp & 0x04) {
3007 ivideo->SiS_Pr.SiS_UseLCDA = true;
3008 ivideo->detectedlcda = 0x03;
3012 /* Save PDC */
3013 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3014 int tmp;
3015 inSISIDXREG(SISCR,0x30,tmp);
3016 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3017 /* Currently on LCD? If yes, read current pdc */
3018 u8 pdc;
3019 inSISIDXREG(SISPART1,0x2D,pdc);
3020 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3021 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3022 inSISIDXREG(SISPART1,0x35,pdc);
3023 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3024 inSISIDXREG(SISPART1,0x20,pdc);
3025 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3026 if(ivideo->newrom) {
3027 /* New ROM invalidates other PDC resp. */
3028 if(ivideo->detectedlcda != 0xff) {
3029 ivideo->detectedpdc = 0xff;
3030 } else {
3031 ivideo->detectedpdca = 0xff;
3034 if(ivideo->SiS_Pr.PDC == -1) {
3035 if(ivideo->detectedpdc != 0xff) {
3036 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3039 if(ivideo->SiS_Pr.PDCA == -1) {
3040 if(ivideo->detectedpdca != 0xff) {
3041 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3044 if(ivideo->detectedpdc != 0xff) {
3045 printk(KERN_INFO
3046 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3047 ivideo->detectedpdc);
3049 if(ivideo->detectedpdca != 0xff) {
3050 printk(KERN_INFO
3051 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3052 ivideo->detectedpdca);
3056 /* Save EMI */
3057 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3058 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3059 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3060 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3061 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3062 ivideo->SiS_Pr.HaveEMI = true;
3063 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3064 ivideo->SiS_Pr.HaveEMILCD = true;
3069 /* Let user override detected PDCs (all bridges) */
3070 if(ivideo->vbflags2 & VB2_30xBLV) {
3071 if((ivideo->SiS_Pr.PDC != -1) &&
3072 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3073 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3074 ivideo->SiS_Pr.PDC);
3076 if((ivideo->SiS_Pr.PDCA != -1) &&
3077 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3078 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3079 ivideo->SiS_Pr.PDCA);
3084 #endif
3087 /* -------------------- Memory manager routines ---------------------- */
3089 static u32 __devinit
3090 sisfb_getheapstart(struct sis_video_info *ivideo)
3092 u32 ret = ivideo->sisfb_parm_mem * 1024;
3093 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3094 u32 def;
3096 /* Calculate heap start = end of memory for console
3098 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3099 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3101 * On 76x in UMA+LFB mode, the layout is as follows:
3102 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3103 * where the heap is the entire UMA area, eventually
3104 * into the LFB area if the given mem parameter is
3105 * higher than the size of the UMA memory.
3107 * Basically given by "mem" parameter
3109 * maximum = videosize - cmd_queue - hwcursor
3110 * (results in a heap of size 0)
3111 * default = SiS 300: depends on videosize
3112 * SiS 315/330/340/XGI: 32k below max
3115 if(ivideo->sisvga_engine == SIS_300_VGA) {
3116 if(ivideo->video_size > 0x1000000) {
3117 def = 0xc00000;
3118 } else if(ivideo->video_size > 0x800000) {
3119 def = 0x800000;
3120 } else {
3121 def = 0x400000;
3123 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3124 ret = def = 0;
3125 } else {
3126 def = maxoffs - 0x8000;
3129 /* Use default for secondary card for now (FIXME) */
3130 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3131 ret = def;
3133 return ret;
3136 static u32 __devinit
3137 sisfb_getheapsize(struct sis_video_info *ivideo)
3139 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3140 u32 ret = 0;
3142 if(ivideo->UMAsize && ivideo->LFBsize) {
3143 if( (!ivideo->sisfb_parm_mem) ||
3144 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3145 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3146 ret = ivideo->UMAsize;
3147 max -= ivideo->UMAsize;
3148 } else {
3149 ret = max - (ivideo->sisfb_parm_mem * 1024);
3150 max = ivideo->sisfb_parm_mem * 1024;
3152 ivideo->video_offset = ret;
3153 ivideo->sisfb_mem = max;
3154 } else {
3155 ret = max - ivideo->heapstart;
3156 ivideo->sisfb_mem = ivideo->heapstart;
3159 return ret;
3162 static int __devinit
3163 sisfb_heap_init(struct sis_video_info *ivideo)
3165 struct SIS_OH *poh;
3167 ivideo->video_offset = 0;
3168 if(ivideo->sisfb_parm_mem) {
3169 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3170 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3171 ivideo->sisfb_parm_mem = 0;
3175 ivideo->heapstart = sisfb_getheapstart(ivideo);
3176 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3178 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3179 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3181 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3182 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3184 ivideo->sisfb_heap.vinfo = ivideo;
3186 ivideo->sisfb_heap.poha_chain = NULL;
3187 ivideo->sisfb_heap.poh_freelist = NULL;
3189 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3190 if(poh == NULL)
3191 return 1;
3193 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3194 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3195 poh->size = ivideo->sisfb_heap_size;
3196 poh->offset = ivideo->heapstart;
3198 ivideo->sisfb_heap.oh_free.poh_next = poh;
3199 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3200 ivideo->sisfb_heap.oh_free.size = 0;
3201 ivideo->sisfb_heap.max_freesize = poh->size;
3203 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3204 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3205 ivideo->sisfb_heap.oh_used.size = SENTINEL;
3207 if(ivideo->cardnumber == 0) {
3208 /* For the first card, make this heap the "global" one
3209 * for old DRM (which could handle only one card)
3211 sisfb_heap = &ivideo->sisfb_heap;
3214 return 0;
3217 static struct SIS_OH *
3218 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3220 struct SIS_OHALLOC *poha;
3221 struct SIS_OH *poh;
3222 unsigned long cOhs;
3223 int i;
3225 if(memheap->poh_freelist == NULL) {
3226 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3227 if(!poha)
3228 return NULL;
3230 poha->poha_next = memheap->poha_chain;
3231 memheap->poha_chain = poha;
3233 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3235 poh = &poha->aoh[0];
3236 for(i = cOhs - 1; i != 0; i--) {
3237 poh->poh_next = poh + 1;
3238 poh = poh + 1;
3241 poh->poh_next = NULL;
3242 memheap->poh_freelist = &poha->aoh[0];
3245 poh = memheap->poh_freelist;
3246 memheap->poh_freelist = poh->poh_next;
3248 return poh;
3251 static struct SIS_OH *
3252 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3254 struct SIS_OH *pohThis;
3255 struct SIS_OH *pohRoot;
3256 int bAllocated = 0;
3258 if(size > memheap->max_freesize) {
3259 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3260 (unsigned int) size / 1024);
3261 return NULL;
3264 pohThis = memheap->oh_free.poh_next;
3266 while(pohThis != &memheap->oh_free) {
3267 if(size <= pohThis->size) {
3268 bAllocated = 1;
3269 break;
3271 pohThis = pohThis->poh_next;
3274 if(!bAllocated) {
3275 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3276 (unsigned int) size / 1024);
3277 return NULL;
3280 if(size == pohThis->size) {
3281 pohRoot = pohThis;
3282 sisfb_delete_node(pohThis);
3283 } else {
3284 pohRoot = sisfb_poh_new_node(memheap);
3285 if(pohRoot == NULL)
3286 return NULL;
3288 pohRoot->offset = pohThis->offset;
3289 pohRoot->size = size;
3291 pohThis->offset += size;
3292 pohThis->size -= size;
3295 memheap->max_freesize -= size;
3297 pohThis = &memheap->oh_used;
3298 sisfb_insert_node(pohThis, pohRoot);
3300 return pohRoot;
3303 static void
3304 sisfb_delete_node(struct SIS_OH *poh)
3306 poh->poh_prev->poh_next = poh->poh_next;
3307 poh->poh_next->poh_prev = poh->poh_prev;
3310 static void
3311 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3313 struct SIS_OH *pohTemp = pohList->poh_next;
3315 pohList->poh_next = poh;
3316 pohTemp->poh_prev = poh;
3318 poh->poh_prev = pohList;
3319 poh->poh_next = pohTemp;
3322 static struct SIS_OH *
3323 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3325 struct SIS_OH *pohThis;
3326 struct SIS_OH *poh_freed;
3327 struct SIS_OH *poh_prev;
3328 struct SIS_OH *poh_next;
3329 u32 ulUpper;
3330 u32 ulLower;
3331 int foundNode = 0;
3333 poh_freed = memheap->oh_used.poh_next;
3335 while(poh_freed != &memheap->oh_used) {
3336 if(poh_freed->offset == base) {
3337 foundNode = 1;
3338 break;
3341 poh_freed = poh_freed->poh_next;
3344 if(!foundNode)
3345 return NULL;
3347 memheap->max_freesize += poh_freed->size;
3349 poh_prev = poh_next = NULL;
3350 ulUpper = poh_freed->offset + poh_freed->size;
3351 ulLower = poh_freed->offset;
3353 pohThis = memheap->oh_free.poh_next;
3355 while(pohThis != &memheap->oh_free) {
3356 if(pohThis->offset == ulUpper) {
3357 poh_next = pohThis;
3358 } else if((pohThis->offset + pohThis->size) == ulLower) {
3359 poh_prev = pohThis;
3361 pohThis = pohThis->poh_next;
3364 sisfb_delete_node(poh_freed);
3366 if(poh_prev && poh_next) {
3367 poh_prev->size += (poh_freed->size + poh_next->size);
3368 sisfb_delete_node(poh_next);
3369 sisfb_free_node(memheap, poh_freed);
3370 sisfb_free_node(memheap, poh_next);
3371 return poh_prev;
3374 if(poh_prev) {
3375 poh_prev->size += poh_freed->size;
3376 sisfb_free_node(memheap, poh_freed);
3377 return poh_prev;
3380 if(poh_next) {
3381 poh_next->size += poh_freed->size;
3382 poh_next->offset = poh_freed->offset;
3383 sisfb_free_node(memheap, poh_freed);
3384 return poh_next;
3387 sisfb_insert_node(&memheap->oh_free, poh_freed);
3389 return poh_freed;
3392 static void
3393 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3395 if(poh == NULL)
3396 return;
3398 poh->poh_next = memheap->poh_freelist;
3399 memheap->poh_freelist = poh;
3402 static void
3403 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3405 struct SIS_OH *poh = NULL;
3407 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3408 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3410 if(poh == NULL) {
3411 req->offset = req->size = 0;
3412 DPRINTK("sisfb: Video RAM allocation failed\n");
3413 } else {
3414 req->offset = poh->offset;
3415 req->size = poh->size;
3416 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3417 (poh->offset + ivideo->video_vbase));
3421 void
3422 sis_malloc(struct sis_memreq *req)
3424 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3426 if(&ivideo->sisfb_heap == sisfb_heap)
3427 sis_int_malloc(ivideo, req);
3428 else
3429 req->offset = req->size = 0;
3432 void
3433 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3435 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3437 sis_int_malloc(ivideo, req);
3440 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3442 static void
3443 sis_int_free(struct sis_video_info *ivideo, u32 base)
3445 struct SIS_OH *poh;
3447 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3448 return;
3450 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3452 if(poh == NULL) {
3453 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3454 (unsigned int) base);
3458 void
3459 sis_free(u32 base)
3461 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3463 sis_int_free(ivideo, base);
3466 void
3467 sis_free_new(struct pci_dev *pdev, u32 base)
3469 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3471 sis_int_free(ivideo, base);
3474 /* --------------------- SetMode routines ------------------------- */
3476 static void
3477 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3479 u8 cr30, cr31;
3481 /* Check if MMIO and engines are enabled,
3482 * and sync in case they are. Can't use
3483 * ivideo->accel here, as this might have
3484 * been changed before this is called.
3486 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3487 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3488 /* MMIO and 2D/3D engine enabled? */
3489 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3490 #ifdef CONFIG_FB_SIS_300
3491 if(ivideo->sisvga_engine == SIS_300_VGA) {
3492 /* Don't care about TurboQueue. It's
3493 * enough to know that the engines
3494 * are enabled
3496 sisfb_syncaccel(ivideo);
3498 #endif
3499 #ifdef CONFIG_FB_SIS_315
3500 if(ivideo->sisvga_engine == SIS_315_VGA) {
3501 /* Check that any queue mode is
3502 * enabled, and that the queue
3503 * is not in the state of "reset"
3505 inSISIDXREG(SISSR, 0x26, cr30);
3506 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3507 sisfb_syncaccel(ivideo);
3510 #endif
3514 static void
3515 sisfb_pre_setmode(struct sis_video_info *ivideo)
3517 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3518 int tvregnum = 0;
3520 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3522 outSISIDXREG(SISSR, 0x05, 0x86);
3524 inSISIDXREG(SISCR, 0x31, cr31);
3525 cr31 &= ~0x60;
3526 cr31 |= 0x04;
3528 cr33 = ivideo->rate_idx & 0x0F;
3530 #ifdef CONFIG_FB_SIS_315
3531 if(ivideo->sisvga_engine == SIS_315_VGA) {
3532 if(ivideo->chip >= SIS_661) {
3533 inSISIDXREG(SISCR, 0x38, cr38);
3534 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3535 } else {
3536 tvregnum = 0x38;
3537 inSISIDXREG(SISCR, tvregnum, cr38);
3538 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3541 #endif
3542 #ifdef CONFIG_FB_SIS_300
3543 if(ivideo->sisvga_engine == SIS_300_VGA) {
3544 tvregnum = 0x35;
3545 inSISIDXREG(SISCR, tvregnum, cr38);
3547 #endif
3549 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3550 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
3551 ivideo->curFSTN = ivideo->curDSTN = 0;
3553 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3555 case CRT2_TV:
3556 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3557 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3558 #ifdef CONFIG_FB_SIS_315
3559 if(ivideo->chip >= SIS_661) {
3560 cr38 |= 0x04;
3561 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3562 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3563 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3564 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3565 cr35 &= ~0x01;
3566 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3567 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3568 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3569 cr38 |= 0x08;
3570 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3571 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3572 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3573 cr31 &= ~0x01;
3574 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3576 #endif
3577 } else if((ivideo->vbflags & TV_HIVISION) &&
3578 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3579 if(ivideo->chip >= SIS_661) {
3580 cr38 |= 0x04;
3581 cr35 |= 0x60;
3582 } else {
3583 cr30 |= 0x80;
3585 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3586 cr31 |= 0x01;
3587 cr35 |= 0x01;
3588 ivideo->currentvbflags |= TV_HIVISION;
3589 } else if(ivideo->vbflags & TV_SCART) {
3590 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3591 cr31 |= 0x01;
3592 cr35 |= 0x01;
3593 ivideo->currentvbflags |= TV_SCART;
3594 } else {
3595 if(ivideo->vbflags & TV_SVIDEO) {
3596 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3597 ivideo->currentvbflags |= TV_SVIDEO;
3599 if(ivideo->vbflags & TV_AVIDEO) {
3600 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3601 ivideo->currentvbflags |= TV_AVIDEO;
3604 cr31 |= SIS_DRIVER_MODE;
3606 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3607 if(ivideo->vbflags & TV_PAL) {
3608 cr31 |= 0x01; cr35 |= 0x01;
3609 ivideo->currentvbflags |= TV_PAL;
3610 if(ivideo->vbflags & TV_PALM) {
3611 cr38 |= 0x40; cr35 |= 0x04;
3612 ivideo->currentvbflags |= TV_PALM;
3613 } else if(ivideo->vbflags & TV_PALN) {
3614 cr38 |= 0x80; cr35 |= 0x08;
3615 ivideo->currentvbflags |= TV_PALN;
3617 } else {
3618 cr31 &= ~0x01; cr35 &= ~0x01;
3619 ivideo->currentvbflags |= TV_NTSC;
3620 if(ivideo->vbflags & TV_NTSCJ) {
3621 cr38 |= 0x40; cr35 |= 0x02;
3622 ivideo->currentvbflags |= TV_NTSCJ;
3626 break;
3628 case CRT2_LCD:
3629 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3630 cr31 |= SIS_DRIVER_MODE;
3631 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3632 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3633 ivideo->curFSTN = ivideo->sisfb_fstn;
3634 ivideo->curDSTN = ivideo->sisfb_dstn;
3635 break;
3637 case CRT2_VGA:
3638 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3639 cr31 |= SIS_DRIVER_MODE;
3640 if(ivideo->sisfb_nocrt2rate) {
3641 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3642 } else {
3643 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3645 break;
3647 default: /* disable CRT2 */
3648 cr30 = 0x00;
3649 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3652 outSISIDXREG(SISCR, 0x30, cr30);
3653 outSISIDXREG(SISCR, 0x33, cr33);
3655 if(ivideo->chip >= SIS_661) {
3656 #ifdef CONFIG_FB_SIS_315
3657 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3658 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3659 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3660 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3661 #endif
3662 } else if(ivideo->chip != SIS_300) {
3663 outSISIDXREG(SISCR, tvregnum, cr38);
3665 outSISIDXREG(SISCR, 0x31, cr31);
3667 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3669 sisfb_check_engine_and_sync(ivideo);
3672 /* Fix SR11 for 661 and later */
3673 #ifdef CONFIG_FB_SIS_315
3674 static void
3675 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3677 u8 tmpreg;
3679 if(ivideo->chip >= SIS_661) {
3680 inSISIDXREG(SISSR,0x11,tmpreg);
3681 if(tmpreg & 0x20) {
3682 inSISIDXREG(SISSR,0x3e,tmpreg);
3683 tmpreg = (tmpreg + 1) & 0xff;
3684 outSISIDXREG(SISSR,0x3e,tmpreg);
3685 inSISIDXREG(SISSR,0x11,tmpreg);
3687 if(tmpreg & 0xf0) {
3688 andSISIDXREG(SISSR,0x11,0x0f);
3692 #endif
3694 static void
3695 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3697 if(val > 32) val = 32;
3698 if(val < -32) val = -32;
3699 ivideo->tvxpos = val;
3701 if(ivideo->sisfblocked) return;
3702 if(!ivideo->modechanged) return;
3704 if(ivideo->currentvbflags & CRT2_TV) {
3706 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3708 int x = ivideo->tvx;
3710 switch(ivideo->chronteltype) {
3711 case 1:
3712 x += val;
3713 if(x < 0) x = 0;
3714 outSISIDXREG(SISSR,0x05,0x86);
3715 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3716 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3717 break;
3718 case 2:
3719 /* Not supported by hardware */
3720 break;
3723 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3725 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3726 unsigned short temp;
3728 p2_1f = ivideo->p2_1f;
3729 p2_20 = ivideo->p2_20;
3730 p2_2b = ivideo->p2_2b;
3731 p2_42 = ivideo->p2_42;
3732 p2_43 = ivideo->p2_43;
3734 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3735 temp += (val * 2);
3736 p2_1f = temp & 0xff;
3737 p2_20 = (temp & 0xf00) >> 4;
3738 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3739 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3740 temp += (val * 2);
3741 p2_43 = temp & 0xff;
3742 p2_42 = (temp & 0xf00) >> 4;
3743 outSISIDXREG(SISPART2,0x1f,p2_1f);
3744 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3745 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3746 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3747 outSISIDXREG(SISPART2,0x43,p2_43);
3752 static void
3753 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3755 if(val > 32) val = 32;
3756 if(val < -32) val = -32;
3757 ivideo->tvypos = val;
3759 if(ivideo->sisfblocked) return;
3760 if(!ivideo->modechanged) return;
3762 if(ivideo->currentvbflags & CRT2_TV) {
3764 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3766 int y = ivideo->tvy;
3768 switch(ivideo->chronteltype) {
3769 case 1:
3770 y -= val;
3771 if(y < 0) y = 0;
3772 outSISIDXREG(SISSR,0x05,0x86);
3773 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3774 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3775 break;
3776 case 2:
3777 /* Not supported by hardware */
3778 break;
3781 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3783 char p2_01, p2_02;
3784 val /= 2;
3785 p2_01 = ivideo->p2_01;
3786 p2_02 = ivideo->p2_02;
3788 p2_01 += val;
3789 p2_02 += val;
3790 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3791 while((p2_01 <= 0) || (p2_02 <= 0)) {
3792 p2_01 += 2;
3793 p2_02 += 2;
3796 outSISIDXREG(SISPART2,0x01,p2_01);
3797 outSISIDXREG(SISPART2,0x02,p2_02);
3802 static void
3803 sisfb_post_setmode(struct sis_video_info *ivideo)
3805 bool crt1isoff = false;
3806 bool doit = true;
3807 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3808 u8 reg;
3809 #endif
3810 #ifdef CONFIG_FB_SIS_315
3811 u8 reg1;
3812 #endif
3814 outSISIDXREG(SISSR, 0x05, 0x86);
3816 #ifdef CONFIG_FB_SIS_315
3817 sisfb_fixup_SR11(ivideo);
3818 #endif
3820 /* Now we actually HAVE changed the display mode */
3821 ivideo->modechanged = 1;
3823 /* We can't switch off CRT1 if bridge is in slave mode */
3824 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3825 if(sisfb_bridgeisslave(ivideo)) doit = false;
3826 } else
3827 ivideo->sisfb_crt1off = 0;
3829 #ifdef CONFIG_FB_SIS_300
3830 if(ivideo->sisvga_engine == SIS_300_VGA) {
3831 if((ivideo->sisfb_crt1off) && (doit)) {
3832 crt1isoff = true;
3833 reg = 0x00;
3834 } else {
3835 crt1isoff = false;
3836 reg = 0x80;
3838 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3840 #endif
3841 #ifdef CONFIG_FB_SIS_315
3842 if(ivideo->sisvga_engine == SIS_315_VGA) {
3843 if((ivideo->sisfb_crt1off) && (doit)) {
3844 crt1isoff = true;
3845 reg = 0x40;
3846 reg1 = 0xc0;
3847 } else {
3848 crt1isoff = false;
3849 reg = 0x00;
3850 reg1 = 0x00;
3852 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3853 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3855 #endif
3857 if(crt1isoff) {
3858 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3859 ivideo->currentvbflags |= VB_SINGLE_MODE;
3860 } else {
3861 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3862 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3863 ivideo->currentvbflags |= VB_MIRROR_MODE;
3864 } else {
3865 ivideo->currentvbflags |= VB_SINGLE_MODE;
3869 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3871 if(ivideo->currentvbflags & CRT2_TV) {
3872 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3873 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3874 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3875 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3876 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3877 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3878 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3879 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3880 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3881 if(ivideo->chronteltype == 1) {
3882 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3883 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3884 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3885 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3890 if(ivideo->tvxpos) {
3891 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3893 if(ivideo->tvypos) {
3894 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3897 /* Eventually sync engines */
3898 sisfb_check_engine_and_sync(ivideo);
3900 /* (Re-)Initialize chip engines */
3901 if(ivideo->accel) {
3902 sisfb_engine_init(ivideo);
3903 } else {
3904 ivideo->engineok = 0;
3908 static int
3909 sisfb_reset_mode(struct sis_video_info *ivideo)
3911 if(sisfb_set_mode(ivideo, 0))
3912 return 1;
3914 sisfb_set_pitch(ivideo);
3915 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3916 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3918 return 0;
3921 static void
3922 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3924 int mycrt1off;
3926 switch(sisfb_command->sisfb_cmd) {
3927 case SISFB_CMD_GETVBFLAGS:
3928 if(!ivideo->modechanged) {
3929 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3930 } else {
3931 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3932 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3933 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
3935 break;
3936 case SISFB_CMD_SWITCHCRT1:
3937 /* arg[0]: 0 = off, 1 = on, 99 = query */
3938 if(!ivideo->modechanged) {
3939 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3940 } else if(sisfb_command->sisfb_arg[0] == 99) {
3941 /* Query */
3942 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3943 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3944 } else if(ivideo->sisfblocked) {
3945 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3946 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3947 (sisfb_command->sisfb_arg[0] == 0)) {
3948 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3949 } else {
3950 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3951 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3952 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3953 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3954 ivideo->sisfb_crt1off = mycrt1off;
3955 if(sisfb_reset_mode(ivideo)) {
3956 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
3959 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3961 break;
3962 /* more to come */
3963 default:
3964 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3965 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3966 sisfb_command->sisfb_cmd);
3970 #ifndef MODULE
3971 static int __init sisfb_setup(char *options)
3973 char *this_opt;
3975 sisfb_setdefaultparms();
3977 if(!options || !(*options))
3978 return 0;
3980 while((this_opt = strsep(&options, ",")) != NULL) {
3982 if(!(*this_opt)) continue;
3984 if(!strnicmp(this_opt, "off", 3)) {
3985 sisfb_off = 1;
3986 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3987 /* Need to check crt2 type first for fstn/dstn */
3988 sisfb_search_crt2type(this_opt + 14);
3989 } else if(!strnicmp(this_opt, "tvmode:",7)) {
3990 sisfb_search_tvstd(this_opt + 7);
3991 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3992 sisfb_search_tvstd(this_opt + 11);
3993 } else if(!strnicmp(this_opt, "mode:", 5)) {
3994 sisfb_search_mode(this_opt + 5, false);
3995 } else if(!strnicmp(this_opt, "vesa:", 5)) {
3996 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
3997 } else if(!strnicmp(this_opt, "rate:", 5)) {
3998 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
3999 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4000 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4001 } else if(!strnicmp(this_opt, "mem:",4)) {
4002 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4003 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4004 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4005 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4006 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4007 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4008 sisfb_accel = 0;
4009 } else if(!strnicmp(this_opt, "accel", 5)) {
4010 sisfb_accel = -1;
4011 } else if(!strnicmp(this_opt, "noypan", 6)) {
4012 sisfb_ypan = 0;
4013 } else if(!strnicmp(this_opt, "ypan", 4)) {
4014 sisfb_ypan = -1;
4015 } else if(!strnicmp(this_opt, "nomax", 5)) {
4016 sisfb_max = 0;
4017 } else if(!strnicmp(this_opt, "max", 3)) {
4018 sisfb_max = -1;
4019 } else if(!strnicmp(this_opt, "userom:", 7)) {
4020 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4021 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4022 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4023 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4024 sisfb_nocrt2rate = 1;
4025 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4026 unsigned long temp = 2;
4027 temp = simple_strtoul(this_opt + 9, NULL, 0);
4028 if((temp == 0) || (temp == 1)) {
4029 sisfb_scalelcd = temp ^ 1;
4031 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4032 int temp = 0;
4033 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4034 if((temp >= -32) && (temp <= 32)) {
4035 sisfb_tvxposoffset = temp;
4037 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4038 int temp = 0;
4039 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4040 if((temp >= -32) && (temp <= 32)) {
4041 sisfb_tvyposoffset = temp;
4043 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4044 sisfb_search_specialtiming(this_opt + 14);
4045 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4046 int temp = 4;
4047 temp = simple_strtoul(this_opt + 7, NULL, 0);
4048 if((temp >= 0) && (temp <= 3)) {
4049 sisfb_lvdshl = temp;
4051 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4052 sisfb_search_mode(this_opt, true);
4053 #if !defined(__i386__) && !defined(__x86_64__)
4054 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4055 sisfb_resetcard = 1;
4056 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4057 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4058 #endif
4059 } else {
4060 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4065 return 0;
4067 #endif
4069 static int __devinit
4070 sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
4072 void __iomem *rom;
4073 int romptr;
4075 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4076 return 0;
4078 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4079 if(romptr > (0x10000 - 8))
4080 return 0;
4082 rom = rom_base + romptr;
4084 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4085 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4086 return 0;
4088 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4089 return 0;
4091 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4092 return 0;
4094 return 1;
4097 static unsigned char * __devinit
4098 sisfb_find_rom(struct pci_dev *pdev)
4100 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4101 void __iomem *rom_base;
4102 unsigned char *myrombase = NULL;
4103 u32 temp;
4104 size_t romsize;
4106 /* First, try the official pci ROM functions (except
4107 * on integrated chipsets which have no ROM).
4110 if(!ivideo->nbridge) {
4112 if((rom_base = pci_map_rom(pdev, &romsize))) {
4114 if(sisfb_check_rom(rom_base, ivideo)) {
4116 if((myrombase = vmalloc(65536))) {
4117 memcpy_fromio(myrombase, rom_base,
4118 (romsize > 65536) ? 65536 : romsize);
4121 pci_unmap_rom(pdev, rom_base);
4125 if(myrombase) return myrombase;
4127 /* Otherwise do it the conventional way. */
4129 #if defined(__i386__) || defined(__x86_64__)
4131 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4133 rom_base = ioremap(temp, 65536);
4134 if(!rom_base)
4135 continue;
4137 if(!sisfb_check_rom(rom_base, ivideo)) {
4138 iounmap(rom_base);
4139 continue;
4142 if((myrombase = vmalloc(65536)))
4143 memcpy_fromio(myrombase, rom_base, 65536);
4145 iounmap(rom_base);
4146 break;
4150 #else
4152 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4153 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4154 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4156 rom_base = ioremap(ivideo->video_base, 65536);
4157 if(rom_base) {
4158 if(sisfb_check_rom(rom_base, ivideo)) {
4159 if((myrombase = vmalloc(65536)))
4160 memcpy_fromio(myrombase, rom_base, 65536);
4162 iounmap(rom_base);
4165 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4167 #endif
4169 return myrombase;
4172 static void __devinit
4173 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4174 unsigned int min)
4176 if (*mapsize < (min << 20))
4177 return;
4179 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4181 if(!ivideo->video_vbase) {
4182 printk(KERN_ERR
4183 "sisfb: Unable to map maximum video RAM for size detection\n");
4184 (*mapsize) >>= 1;
4185 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4186 (*mapsize) >>= 1;
4187 if((*mapsize) < (min << 20))
4188 break;
4190 if(ivideo->video_vbase) {
4191 printk(KERN_ERR
4192 "sisfb: Video RAM size detection limited to %dMB\n",
4193 (int)((*mapsize) >> 20));
4198 #ifdef CONFIG_FB_SIS_300
4199 static int __devinit
4200 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4202 void __iomem *FBAddress = ivideo->video_vbase;
4203 unsigned short temp;
4204 unsigned char reg;
4205 int i, j;
4207 andSISIDXREG(SISSR, 0x15, 0xFB);
4208 orSISIDXREG(SISSR, 0x15, 0x04);
4209 outSISIDXREG(SISSR, 0x13, 0x00);
4210 outSISIDXREG(SISSR, 0x14, 0xBF);
4212 for(i = 0; i < 2; i++) {
4213 temp = 0x1234;
4214 for(j = 0; j < 4; j++) {
4215 writew(temp, FBAddress);
4216 if(readw(FBAddress) == temp)
4217 break;
4218 orSISIDXREG(SISSR, 0x3c, 0x01);
4219 inSISIDXREG(SISSR, 0x05, reg);
4220 inSISIDXREG(SISSR, 0x05, reg);
4221 andSISIDXREG(SISSR, 0x3c, 0xfe);
4222 inSISIDXREG(SISSR, 0x05, reg);
4223 inSISIDXREG(SISSR, 0x05, reg);
4224 temp++;
4228 writel(0x01234567L, FBAddress);
4229 writel(0x456789ABL, (FBAddress + 4));
4230 writel(0x89ABCDEFL, (FBAddress + 8));
4231 writel(0xCDEF0123L, (FBAddress + 12));
4233 inSISIDXREG(SISSR, 0x3b, reg);
4234 if(reg & 0x01) {
4235 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4236 return 4; /* Channel A 128bit */
4239 if(readl((FBAddress + 4)) == 0x456789ABL)
4240 return 2; /* Channel B 64bit */
4242 return 1; /* 32bit */
4245 static int __devinit
4246 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4247 int PseudoRankCapacity, int PseudoAdrPinCount,
4248 unsigned int mapsize)
4250 void __iomem *FBAddr = ivideo->video_vbase;
4251 unsigned short sr14;
4252 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4253 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4254 static const unsigned short SiS_DRAMType[17][5] = {
4255 {0x0C,0x0A,0x02,0x40,0x39},
4256 {0x0D,0x0A,0x01,0x40,0x48},
4257 {0x0C,0x09,0x02,0x20,0x35},
4258 {0x0D,0x09,0x01,0x20,0x44},
4259 {0x0C,0x08,0x02,0x10,0x31},
4260 {0x0D,0x08,0x01,0x10,0x40},
4261 {0x0C,0x0A,0x01,0x20,0x34},
4262 {0x0C,0x09,0x01,0x08,0x32},
4263 {0x0B,0x08,0x02,0x08,0x21},
4264 {0x0C,0x08,0x01,0x08,0x30},
4265 {0x0A,0x08,0x02,0x04,0x11},
4266 {0x0B,0x0A,0x01,0x10,0x28},
4267 {0x09,0x08,0x02,0x02,0x01},
4268 {0x0B,0x09,0x01,0x08,0x24},
4269 {0x0B,0x08,0x01,0x04,0x20},
4270 {0x0A,0x08,0x01,0x02,0x10},
4271 {0x09,0x08,0x01,0x01,0x00}
4274 for(k = 0; k <= 16; k++) {
4276 RankCapacity = buswidth * SiS_DRAMType[k][3];
4278 if(RankCapacity != PseudoRankCapacity)
4279 continue;
4281 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4282 continue;
4284 BankNumHigh = RankCapacity * 16 * iteration - 1;
4285 if(iteration == 3) { /* Rank No */
4286 BankNumMid = RankCapacity * 16 - 1;
4287 } else {
4288 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4291 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4292 PhysicalAdrHigh = BankNumHigh;
4293 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4294 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4296 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4297 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4298 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4299 if(buswidth == 4) sr14 |= 0x80;
4300 else if(buswidth == 2) sr14 |= 0x40;
4301 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4302 outSISIDXREG(SISSR, 0x14, sr14);
4304 BankNumHigh <<= 16;
4305 BankNumMid <<= 16;
4307 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4308 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4309 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4310 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4311 continue;
4313 /* Write data */
4314 writew(((unsigned short)PhysicalAdrHigh),
4315 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4316 writew(((unsigned short)BankNumMid),
4317 (FBAddr + BankNumMid + PhysicalAdrHigh));
4318 writew(((unsigned short)PhysicalAdrHalfPage),
4319 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4320 writew(((unsigned short)PhysicalAdrOtherPage),
4321 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4323 /* Read data */
4324 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4325 return 1;
4328 return 0;
4331 static void __devinit
4332 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4334 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4335 int i, j, buswidth;
4336 int PseudoRankCapacity, PseudoAdrPinCount;
4338 buswidth = sisfb_post_300_buswidth(ivideo);
4340 for(i = 6; i >= 0; i--) {
4341 PseudoRankCapacity = 1 << i;
4342 for(j = 4; j >= 1; j--) {
4343 PseudoAdrPinCount = 15 - j;
4344 if((PseudoRankCapacity * j) <= 64) {
4345 if(sisfb_post_300_rwtest(ivideo,
4347 buswidth,
4348 PseudoRankCapacity,
4349 PseudoAdrPinCount,
4350 mapsize))
4351 return;
4357 static void __devinit
4358 sisfb_post_sis300(struct pci_dev *pdev)
4360 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4361 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4362 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4363 u16 index, rindex, memtype = 0;
4364 unsigned int mapsize;
4366 if(!ivideo->SiS_Pr.UseROM)
4367 bios = NULL;
4369 outSISIDXREG(SISSR, 0x05, 0x86);
4371 if(bios) {
4372 if(bios[0x52] & 0x80) {
4373 memtype = bios[0x52];
4374 } else {
4375 inSISIDXREG(SISSR, 0x3a, memtype);
4377 memtype &= 0x07;
4380 v3 = 0x80; v6 = 0x80;
4381 if(ivideo->revision_id <= 0x13) {
4382 v1 = 0x44; v2 = 0x42;
4383 v4 = 0x44; v5 = 0x42;
4384 } else {
4385 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4386 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4387 if(bios) {
4388 index = memtype * 5;
4389 rindex = index + 0x54;
4390 v1 = bios[rindex++];
4391 v2 = bios[rindex++];
4392 v3 = bios[rindex++];
4393 rindex = index + 0x7c;
4394 v4 = bios[rindex++];
4395 v5 = bios[rindex++];
4396 v6 = bios[rindex++];
4399 outSISIDXREG(SISSR, 0x28, v1);
4400 outSISIDXREG(SISSR, 0x29, v2);
4401 outSISIDXREG(SISSR, 0x2a, v3);
4402 outSISIDXREG(SISSR, 0x2e, v4);
4403 outSISIDXREG(SISSR, 0x2f, v5);
4404 outSISIDXREG(SISSR, 0x30, v6);
4406 v1 = 0x10;
4407 if(bios)
4408 v1 = bios[0xa4];
4409 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4411 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4413 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4414 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4415 if(bios) {
4416 memtype += 0xa5;
4417 v1 = bios[memtype];
4418 v2 = bios[memtype + 8];
4419 v3 = bios[memtype + 16];
4420 v4 = bios[memtype + 24];
4421 v5 = bios[memtype + 32];
4422 v6 = bios[memtype + 40];
4423 v7 = bios[memtype + 48];
4424 v8 = bios[memtype + 56];
4426 if(ivideo->revision_id >= 0x80)
4427 v3 &= 0xfd;
4428 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4429 outSISIDXREG(SISSR, 0x16, v2);
4430 outSISIDXREG(SISSR, 0x17, v3);
4431 outSISIDXREG(SISSR, 0x18, v4);
4432 outSISIDXREG(SISSR, 0x19, v5);
4433 outSISIDXREG(SISSR, 0x1a, v6);
4434 outSISIDXREG(SISSR, 0x1b, v7);
4435 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4436 andSISIDXREG(SISSR, 0x15 ,0xfb);
4437 orSISIDXREG(SISSR, 0x15, 0x04);
4438 if(bios) {
4439 if(bios[0x53] & 0x02) {
4440 orSISIDXREG(SISSR, 0x19, 0x20);
4443 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4444 if(ivideo->revision_id >= 0x80)
4445 v1 |= 0x01;
4446 outSISIDXREG(SISSR, 0x1f, v1);
4447 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4448 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4449 if(bios) {
4450 v1 = bios[0xe8];
4451 v2 = bios[0xe9];
4452 v3 = bios[0xea];
4454 outSISIDXREG(SISSR, 0x23, v1);
4455 outSISIDXREG(SISSR, 0x24, v2);
4456 outSISIDXREG(SISSR, 0x25, v3);
4457 outSISIDXREG(SISSR, 0x21, 0x84);
4458 outSISIDXREG(SISSR, 0x22, 0x00);
4459 outSISIDXREG(SISCR, 0x37, 0x00);
4460 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4461 outSISIDXREG(SISPART1, 0x00, 0x00);
4462 v1 = 0x40; v2 = 0x11;
4463 if(bios) {
4464 v1 = bios[0xec];
4465 v2 = bios[0xeb];
4467 outSISIDXREG(SISPART1, 0x02, v1);
4469 if(ivideo->revision_id >= 0x80)
4470 v2 &= ~0x01;
4472 inSISIDXREG(SISPART4, 0x00, reg);
4473 if((reg == 1) || (reg == 2)) {
4474 outSISIDXREG(SISCR, 0x37, 0x02);
4475 outSISIDXREG(SISPART2, 0x00, 0x1c);
4476 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4477 if(ivideo->SiS_Pr.UseROM) {
4478 v4 = bios[0xf5];
4479 v5 = bios[0xf6];
4480 v6 = bios[0xf7];
4482 outSISIDXREG(SISPART4, 0x0d, v4);
4483 outSISIDXREG(SISPART4, 0x0e, v5);
4484 outSISIDXREG(SISPART4, 0x10, v6);
4485 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4486 inSISIDXREG(SISPART4, 0x01, reg);
4487 if(reg >= 0xb0) {
4488 inSISIDXREG(SISPART4, 0x23, reg);
4489 reg &= 0x20;
4490 reg <<= 1;
4491 outSISIDXREG(SISPART4, 0x23, reg);
4493 } else {
4494 v2 &= ~0x10;
4496 outSISIDXREG(SISSR, 0x32, v2);
4498 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4500 inSISIDXREG(SISSR, 0x16, reg);
4501 reg &= 0xc3;
4502 outSISIDXREG(SISCR, 0x35, reg);
4503 outSISIDXREG(SISCR, 0x83, 0x00);
4504 #if !defined(__i386__) && !defined(__x86_64__)
4505 if(sisfb_videoram) {
4506 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4507 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4508 outSISIDXREG(SISSR, 0x14, reg);
4509 } else {
4510 #endif
4511 /* Need to map max FB size for finding out about RAM size */
4512 mapsize = ivideo->video_size;
4513 sisfb_post_map_vram(ivideo, &mapsize, 4);
4515 if(ivideo->video_vbase) {
4516 sisfb_post_300_ramsize(pdev, mapsize);
4517 iounmap(ivideo->video_vbase);
4518 } else {
4519 printk(KERN_DEBUG
4520 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4521 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4522 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4524 #if !defined(__i386__) && !defined(__x86_64__)
4526 #endif
4527 if(bios) {
4528 v1 = bios[0xe6];
4529 v2 = bios[0xe7];
4530 } else {
4531 inSISIDXREG(SISSR, 0x3a, reg);
4532 if((reg & 0x30) == 0x30) {
4533 v1 = 0x04; /* PCI */
4534 v2 = 0x92;
4535 } else {
4536 v1 = 0x14; /* AGP */
4537 v2 = 0xb2;
4540 outSISIDXREG(SISSR, 0x21, v1);
4541 outSISIDXREG(SISSR, 0x22, v2);
4543 /* Sense CRT1 */
4544 sisfb_sense_crt1(ivideo);
4546 /* Set default mode, don't clear screen */
4547 ivideo->SiS_Pr.SiS_UseOEM = false;
4548 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4549 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
4550 ivideo->curFSTN = ivideo->curDSTN = 0;
4551 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4552 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4554 outSISIDXREG(SISSR, 0x05, 0x86);
4556 /* Display off */
4557 orSISIDXREG(SISSR, 0x01, 0x20);
4559 /* Save mode number in CR34 */
4560 outSISIDXREG(SISCR, 0x34, 0x2e);
4562 /* Let everyone know what the current mode is */
4563 ivideo->modeprechange = 0x2e;
4565 #endif
4567 #ifdef CONFIG_FB_SIS_315
4568 #if 0
4569 static void __devinit
4570 sisfb_post_sis315330(struct pci_dev *pdev)
4572 /* TODO */
4574 #endif
4576 static void __devinit
4577 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4579 unsigned int i;
4580 u8 reg;
4582 for(i = 0; i <= (delay * 10 * 36); i++) {
4583 inSISIDXREG(SISSR, 0x05, reg);
4584 reg++;
4588 static int __devinit
4589 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4590 unsigned short pcivendor)
4592 struct pci_dev *pdev = NULL;
4593 unsigned short temp;
4594 int ret = 0;
4596 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
4597 temp = pdev->vendor;
4598 if(temp == pcivendor) {
4599 ret = 1;
4600 pci_dev_put(pdev);
4601 break;
4605 return ret;
4608 static int __devinit
4609 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4610 unsigned int enda, unsigned int mapsize)
4612 unsigned int pos;
4613 int i;
4615 writel(0, ivideo->video_vbase);
4617 for(i = starta; i <= enda; i++) {
4618 pos = 1 << i;
4619 if(pos < mapsize)
4620 writel(pos, ivideo->video_vbase + pos);
4623 sisfb_post_xgi_delay(ivideo, 150);
4625 if(readl(ivideo->video_vbase) != 0)
4626 return 0;
4628 for(i = starta; i <= enda; i++) {
4629 pos = 1 << i;
4630 if(pos < mapsize) {
4631 if(readl(ivideo->video_vbase + pos) != pos)
4632 return 0;
4633 } else
4634 return 0;
4637 return 1;
4640 static void __devinit
4641 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4643 unsigned int buswidth, ranksize, channelab, mapsize;
4644 int i, j, k, l;
4645 u8 reg, sr14;
4646 static const u8 dramsr13[12 * 5] = {
4647 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4648 0x02, 0x0e, 0x0a, 0x40, 0x59,
4649 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4650 0x02, 0x0e, 0x09, 0x20, 0x55,
4651 0x02, 0x0d, 0x0a, 0x20, 0x49,
4652 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4653 0x02, 0x0e, 0x08, 0x10, 0x51,
4654 0x02, 0x0d, 0x09, 0x10, 0x45,
4655 0x02, 0x0c, 0x0a, 0x10, 0x39,
4656 0x02, 0x0d, 0x08, 0x08, 0x41,
4657 0x02, 0x0c, 0x09, 0x08, 0x35,
4658 0x02, 0x0c, 0x08, 0x04, 0x31
4660 static const u8 dramsr13_4[4 * 5] = {
4661 0x02, 0x0d, 0x09, 0x40, 0x45,
4662 0x02, 0x0c, 0x09, 0x20, 0x35,
4663 0x02, 0x0c, 0x08, 0x10, 0x31,
4664 0x02, 0x0b, 0x08, 0x08, 0x21
4667 /* Enable linear mode, disable 0xa0000 address decoding */
4668 /* We disable a0000 address decoding, because
4669 * - if running on x86, if the card is disabled, it means
4670 * that another card is in the system. We don't want
4671 * to interphere with that primary card's textmode.
4672 * - if running on non-x86, there usually is no VGA window
4673 * at a0000.
4675 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4677 /* Need to map max FB size for finding out about RAM size */
4678 mapsize = ivideo->video_size;
4679 sisfb_post_map_vram(ivideo, &mapsize, 32);
4681 if(!ivideo->video_vbase) {
4682 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4683 outSISIDXREG(SISSR, 0x13, 0x35);
4684 outSISIDXREG(SISSR, 0x14, 0x41);
4685 /* TODO */
4686 return;
4689 /* Non-interleaving */
4690 outSISIDXREG(SISSR, 0x15, 0x00);
4691 /* No tiling */
4692 outSISIDXREG(SISSR, 0x1c, 0x00);
4694 if(ivideo->chip == XGI_20) {
4696 channelab = 1;
4697 inSISIDXREG(SISCR, 0x97, reg);
4698 if(!(reg & 0x01)) { /* Single 32/16 */
4699 buswidth = 32;
4700 outSISIDXREG(SISSR, 0x13, 0xb1);
4701 outSISIDXREG(SISSR, 0x14, 0x52);
4702 sisfb_post_xgi_delay(ivideo, 1);
4703 sr14 = 0x02;
4704 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4705 goto bail_out;
4707 outSISIDXREG(SISSR, 0x13, 0x31);
4708 outSISIDXREG(SISSR, 0x14, 0x42);
4709 sisfb_post_xgi_delay(ivideo, 1);
4710 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4711 goto bail_out;
4713 buswidth = 16;
4714 outSISIDXREG(SISSR, 0x13, 0xb1);
4715 outSISIDXREG(SISSR, 0x14, 0x41);
4716 sisfb_post_xgi_delay(ivideo, 1);
4717 sr14 = 0x01;
4718 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4719 goto bail_out;
4720 else
4721 outSISIDXREG(SISSR, 0x13, 0x31);
4722 } else { /* Dual 16/8 */
4723 buswidth = 16;
4724 outSISIDXREG(SISSR, 0x13, 0xb1);
4725 outSISIDXREG(SISSR, 0x14, 0x41);
4726 sisfb_post_xgi_delay(ivideo, 1);
4727 sr14 = 0x01;
4728 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4729 goto bail_out;
4731 outSISIDXREG(SISSR, 0x13, 0x31);
4732 outSISIDXREG(SISSR, 0x14, 0x31);
4733 sisfb_post_xgi_delay(ivideo, 1);
4734 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4735 goto bail_out;
4737 buswidth = 8;
4738 outSISIDXREG(SISSR, 0x13, 0xb1);
4739 outSISIDXREG(SISSR, 0x14, 0x30);
4740 sisfb_post_xgi_delay(ivideo, 1);
4741 sr14 = 0x00;
4742 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4743 goto bail_out;
4744 else
4745 outSISIDXREG(SISSR, 0x13, 0x31);
4748 } else { /* XGI_40 */
4750 inSISIDXREG(SISCR, 0x97, reg);
4751 if(!(reg & 0x10)) {
4752 inSISIDXREG(SISSR, 0x39, reg);
4753 reg >>= 1;
4756 if(reg & 0x01) { /* DDRII */
4757 buswidth = 32;
4758 if(ivideo->revision_id == 2) {
4759 channelab = 2;
4760 outSISIDXREG(SISSR, 0x13, 0xa1);
4761 outSISIDXREG(SISSR, 0x14, 0x44);
4762 sr14 = 0x04;
4763 sisfb_post_xgi_delay(ivideo, 1);
4764 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4765 goto bail_out;
4767 outSISIDXREG(SISSR, 0x13, 0x21);
4768 outSISIDXREG(SISSR, 0x14, 0x34);
4769 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4770 goto bail_out;
4772 channelab = 1;
4773 outSISIDXREG(SISSR, 0x13, 0xa1);
4774 outSISIDXREG(SISSR, 0x14, 0x40);
4775 sr14 = 0x00;
4776 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4777 goto bail_out;
4779 outSISIDXREG(SISSR, 0x13, 0x21);
4780 outSISIDXREG(SISSR, 0x14, 0x30);
4781 } else {
4782 channelab = 3;
4783 outSISIDXREG(SISSR, 0x13, 0xa1);
4784 outSISIDXREG(SISSR, 0x14, 0x4c);
4785 sr14 = 0x0c;
4786 sisfb_post_xgi_delay(ivideo, 1);
4787 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4788 goto bail_out;
4790 channelab = 2;
4791 outSISIDXREG(SISSR, 0x14, 0x48);
4792 sisfb_post_xgi_delay(ivideo, 1);
4793 sr14 = 0x08;
4794 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4795 goto bail_out;
4797 outSISIDXREG(SISSR, 0x13, 0x21);
4798 outSISIDXREG(SISSR, 0x14, 0x3c);
4799 sr14 = 0x0c;
4801 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4802 channelab = 3;
4803 } else {
4804 channelab = 2;
4805 outSISIDXREG(SISSR, 0x14, 0x38);
4806 sr14 = 0x08;
4809 sisfb_post_xgi_delay(ivideo, 1);
4811 } else { /* DDR */
4813 buswidth = 64;
4814 if(ivideo->revision_id == 2) {
4815 channelab = 1;
4816 outSISIDXREG(SISSR, 0x13, 0xa1);
4817 outSISIDXREG(SISSR, 0x14, 0x52);
4818 sisfb_post_xgi_delay(ivideo, 1);
4819 sr14 = 0x02;
4820 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4821 goto bail_out;
4823 outSISIDXREG(SISSR, 0x13, 0x21);
4824 outSISIDXREG(SISSR, 0x14, 0x42);
4825 } else {
4826 channelab = 2;
4827 outSISIDXREG(SISSR, 0x13, 0xa1);
4828 outSISIDXREG(SISSR, 0x14, 0x5a);
4829 sisfb_post_xgi_delay(ivideo, 1);
4830 sr14 = 0x0a;
4831 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4832 goto bail_out;
4834 outSISIDXREG(SISSR, 0x13, 0x21);
4835 outSISIDXREG(SISSR, 0x14, 0x4a);
4837 sisfb_post_xgi_delay(ivideo, 1);
4842 bail_out:
4843 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4844 sisfb_post_xgi_delay(ivideo, 1);
4846 j = (ivideo->chip == XGI_20) ? 5 : 9;
4847 k = (ivideo->chip == XGI_20) ? 12 : 4;
4849 for(i = 0; i < k; i++) {
4851 reg = (ivideo->chip == XGI_20) ?
4852 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4853 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4854 sisfb_post_xgi_delay(ivideo, 50);
4856 ranksize = (ivideo->chip == XGI_20) ?
4857 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4859 inSISIDXREG(SISSR, 0x13, reg);
4860 if(reg & 0x80) ranksize <<= 1;
4862 if(ivideo->chip == XGI_20) {
4863 if(buswidth == 16) ranksize <<= 1;
4864 else if(buswidth == 32) ranksize <<= 2;
4865 } else {
4866 if(buswidth == 64) ranksize <<= 1;
4869 reg = 0;
4870 l = channelab;
4871 if(l == 3) l = 4;
4872 if((ranksize * l) <= 256) {
4873 while((ranksize >>= 1)) reg += 0x10;
4876 if(!reg) continue;
4878 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4879 sisfb_post_xgi_delay(ivideo, 1);
4881 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4882 break;
4885 iounmap(ivideo->video_vbase);
4888 static void __devinit
4889 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4891 u8 v1, v2, v3;
4892 int index;
4893 static const u8 cs90[8 * 3] = {
4894 0x16, 0x01, 0x01,
4895 0x3e, 0x03, 0x01,
4896 0x7c, 0x08, 0x01,
4897 0x79, 0x06, 0x01,
4898 0x29, 0x01, 0x81,
4899 0x5c, 0x23, 0x01,
4900 0x5c, 0x23, 0x01,
4901 0x5c, 0x23, 0x01
4903 static const u8 csb8[8 * 3] = {
4904 0x5c, 0x23, 0x01,
4905 0x29, 0x01, 0x01,
4906 0x7c, 0x08, 0x01,
4907 0x79, 0x06, 0x01,
4908 0x29, 0x01, 0x81,
4909 0x5c, 0x23, 0x01,
4910 0x5c, 0x23, 0x01,
4911 0x5c, 0x23, 0x01
4914 regb = 0; /* ! */
4916 index = regb * 3;
4917 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4918 if(ivideo->haveXGIROM) {
4919 v1 = ivideo->bios_abase[0x90 + index];
4920 v2 = ivideo->bios_abase[0x90 + index + 1];
4921 v3 = ivideo->bios_abase[0x90 + index + 2];
4923 outSISIDXREG(SISSR, 0x28, v1);
4924 outSISIDXREG(SISSR, 0x29, v2);
4925 outSISIDXREG(SISSR, 0x2a, v3);
4926 sisfb_post_xgi_delay(ivideo, 0x43);
4927 sisfb_post_xgi_delay(ivideo, 0x43);
4928 sisfb_post_xgi_delay(ivideo, 0x43);
4929 index = regb * 3;
4930 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4931 if(ivideo->haveXGIROM) {
4932 v1 = ivideo->bios_abase[0xb8 + index];
4933 v2 = ivideo->bios_abase[0xb8 + index + 1];
4934 v3 = ivideo->bios_abase[0xb8 + index + 2];
4936 outSISIDXREG(SISSR, 0x2e, v1);
4937 outSISIDXREG(SISSR, 0x2f, v2);
4938 outSISIDXREG(SISSR, 0x30, v3);
4939 sisfb_post_xgi_delay(ivideo, 0x43);
4940 sisfb_post_xgi_delay(ivideo, 0x43);
4941 sisfb_post_xgi_delay(ivideo, 0x43);
4944 static int __devinit
4945 sisfb_post_xgi(struct pci_dev *pdev)
4947 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4948 unsigned char *bios = ivideo->bios_abase;
4949 struct pci_dev *mypdev = NULL;
4950 const u8 *ptr, *ptr2;
4951 u8 v1, v2, v3, v4, v5, reg, ramtype;
4952 u32 rega, regb, regd;
4953 int i, j, k, index;
4954 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4955 static const u8 cs76[2] = { 0xa3, 0xfb };
4956 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4957 static const u8 cs158[8] = {
4958 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4960 static const u8 cs160[8] = {
4961 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4963 static const u8 cs168[8] = {
4964 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4966 static const u8 cs128[3 * 8] = {
4967 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4968 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4969 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4971 static const u8 cs148[2 * 8] = {
4972 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4973 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4975 static const u8 cs31a[8 * 4] = {
4976 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
4977 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
4978 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4979 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4981 static const u8 cs33a[8 * 4] = {
4982 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4983 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4984 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4985 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4987 static const u8 cs45a[8 * 2] = {
4988 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
4989 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4991 static const u8 cs170[7 * 8] = {
4992 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4993 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4994 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
4995 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4996 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
4997 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
4998 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5000 static const u8 cs1a8[3 * 8] = {
5001 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5002 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5003 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5005 static const u8 cs100[2 * 8] = {
5006 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5007 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5010 /* VGA enable */
5011 reg = inSISREG(SISVGAENABLE) | 0x01;
5012 outSISREG(SISVGAENABLE, reg);
5014 /* Misc */
5015 reg = inSISREG(SISMISCR) | 0x01;
5016 outSISREG(SISMISCW, reg);
5018 /* Unlock SR */
5019 outSISIDXREG(SISSR, 0x05, 0x86);
5020 inSISIDXREG(SISSR, 0x05, reg);
5021 if(reg != 0xa1)
5022 return 0;
5024 /* Clear some regs */
5025 for(i = 0; i < 0x22; i++) {
5026 if(0x06 + i == 0x20) continue;
5027 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5029 for(i = 0; i < 0x0b; i++) {
5030 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5032 for(i = 0; i < 0x10; i++) {
5033 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5036 ptr = cs78;
5037 if(ivideo->haveXGIROM) {
5038 ptr = (const u8 *)&bios[0x78];
5040 for(i = 0; i < 3; i++) {
5041 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5044 ptr = cs76;
5045 if(ivideo->haveXGIROM) {
5046 ptr = (const u8 *)&bios[0x76];
5048 for(i = 0; i < 2; i++) {
5049 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5052 v1 = 0x18; v2 = 0x00;
5053 if(ivideo->haveXGIROM) {
5054 v1 = bios[0x74];
5055 v2 = bios[0x75];
5057 outSISIDXREG(SISSR, 0x07, v1);
5058 outSISIDXREG(SISSR, 0x11, 0x0f);
5059 outSISIDXREG(SISSR, 0x1f, v2);
5060 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5061 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5062 outSISIDXREG(SISSR, 0x27, 0x74);
5064 ptr = cs7b;
5065 if(ivideo->haveXGIROM) {
5066 ptr = (const u8 *)&bios[0x7b];
5068 for(i = 0; i < 3; i++) {
5069 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5072 if(ivideo->chip == XGI_40) {
5073 if(ivideo->revision_id == 2) {
5074 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5076 outSISIDXREG(SISCR, 0x7d, 0xfe);
5077 outSISIDXREG(SISCR, 0x7e, 0x0f);
5079 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5080 andSISIDXREG(SISCR, 0x58, 0xd7);
5081 inSISIDXREG(SISCR, 0xcb, reg);
5082 if(reg & 0x20) {
5083 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5087 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5088 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5090 if(ivideo->chip == XGI_20) {
5091 outSISIDXREG(SISSR, 0x36, 0x70);
5092 } else {
5093 outSISIDXREG(SISVID, 0x00, 0x86);
5094 outSISIDXREG(SISVID, 0x32, 0x00);
5095 outSISIDXREG(SISVID, 0x30, 0x00);
5096 outSISIDXREG(SISVID, 0x32, 0x01);
5097 outSISIDXREG(SISVID, 0x30, 0x00);
5098 andSISIDXREG(SISVID, 0x2f, 0xdf);
5099 andSISIDXREG(SISCAP, 0x00, 0x3f);
5101 outSISIDXREG(SISPART1, 0x2f, 0x01);
5102 outSISIDXREG(SISPART1, 0x00, 0x00);
5103 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5104 outSISIDXREG(SISPART1, 0x2e, 0x08);
5105 andSISIDXREG(SISPART1, 0x35, 0x7f);
5106 andSISIDXREG(SISPART1, 0x50, 0xfe);
5108 inSISIDXREG(SISPART4, 0x00, reg);
5109 if(reg == 1 || reg == 2) {
5110 outSISIDXREG(SISPART2, 0x00, 0x1c);
5111 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5112 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5113 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5114 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5116 inSISIDXREG(SISPART4, 0x01, reg);
5117 if((reg & 0xf0) >= 0xb0) {
5118 inSISIDXREG(SISPART4, 0x23, reg);
5119 if(reg & 0x20) reg |= 0x40;
5120 outSISIDXREG(SISPART4, 0x23, reg);
5121 reg = (reg & 0x20) ? 0x02 : 0x00;
5122 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5126 v1 = bios[0x77];
5128 inSISIDXREG(SISSR, 0x3b, reg);
5129 if(reg & 0x02) {
5130 inSISIDXREG(SISSR, 0x3a, reg);
5131 v2 = (reg & 0x30) >> 3;
5132 if(!(v2 & 0x04)) v2 ^= 0x02;
5133 inSISIDXREG(SISSR, 0x39, reg);
5134 if(reg & 0x80) v2 |= 0x80;
5135 v2 |= 0x01;
5137 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5138 pci_dev_put(mypdev);
5139 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5140 v2 &= 0xf9;
5141 v2 |= 0x08;
5142 v1 &= 0xfe;
5143 } else {
5144 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
5145 if(!mypdev)
5146 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
5147 if(!mypdev)
5148 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
5149 if(mypdev) {
5150 pci_read_config_dword(mypdev, 0x94, &regd);
5151 regd &= 0xfffffeff;
5152 pci_write_config_dword(mypdev, 0x94, regd);
5153 v1 &= 0xfe;
5154 pci_dev_put(mypdev);
5155 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5156 v1 &= 0xfe;
5157 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5158 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5159 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5160 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5161 if((v2 & 0x06) == 4)
5162 v2 ^= 0x06;
5163 v2 |= 0x08;
5166 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5168 outSISIDXREG(SISSR, 0x22, v1);
5170 if(ivideo->revision_id == 2) {
5171 inSISIDXREG(SISSR, 0x3b, v1);
5172 inSISIDXREG(SISSR, 0x3a, v2);
5173 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5174 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5175 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5177 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
5178 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5179 * of nforce 2 ROM
5181 if(0)
5182 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5183 pci_dev_put(mypdev);
5187 v1 = 0x30;
5188 inSISIDXREG(SISSR, 0x3b, reg);
5189 inSISIDXREG(SISCR, 0x5f, v2);
5190 if((!(reg & 0x02)) && (v2 & 0x0e))
5191 v1 |= 0x08;
5192 outSISIDXREG(SISSR, 0x27, v1);
5194 if(bios[0x64] & 0x01) {
5195 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5198 v1 = bios[0x4f7];
5199 pci_read_config_dword(pdev, 0x50, &regd);
5200 regd = (regd >> 20) & 0x0f;
5201 if(regd == 1) {
5202 v1 &= 0xfc;
5203 orSISIDXREG(SISCR, 0x5f, 0x08);
5205 outSISIDXREG(SISCR, 0x48, v1);
5207 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5208 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5209 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5210 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5211 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5212 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5213 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5214 outSISIDXREG(SISCR, 0x74, 0xd0);
5215 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5216 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5217 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5218 v1 = bios[0x501];
5219 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
5220 v1 = 0xf0;
5221 pci_dev_put(mypdev);
5223 outSISIDXREG(SISCR, 0x77, v1);
5226 /* RAM type */
5228 regb = 0; /* ! */
5230 v1 = 0xff;
5231 if(ivideo->haveXGIROM) {
5232 v1 = bios[0x140 + regb];
5234 outSISIDXREG(SISCR, 0x6d, v1);
5236 ptr = cs128;
5237 if(ivideo->haveXGIROM) {
5238 ptr = (const u8 *)&bios[0x128];
5240 for(i = 0, j = 0; i < 3; i++, j += 8) {
5241 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5244 ptr = cs31a;
5245 ptr2 = cs33a;
5246 if(ivideo->haveXGIROM) {
5247 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5248 ptr = (const u8 *)&bios[index];
5249 ptr2 = (const u8 *)&bios[index + 0x20];
5251 for(i = 0; i < 2; i++) {
5252 if(i == 0) {
5253 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5254 rega = 0x6b;
5255 } else {
5256 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5257 rega = 0x6e;
5259 reg = 0x00;
5260 for(j = 0; j < 16; j++) {
5261 reg &= 0xf3;
5262 if(regd & 0x01) reg |= 0x04;
5263 if(regd & 0x02) reg |= 0x08;
5264 regd >>= 2;
5265 outSISIDXREG(SISCR, rega, reg);
5266 inSISIDXREG(SISCR, rega, reg);
5267 inSISIDXREG(SISCR, rega, reg);
5268 reg += 0x10;
5272 andSISIDXREG(SISCR, 0x6e, 0xfc);
5274 ptr = NULL;
5275 if(ivideo->haveXGIROM) {
5276 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5277 ptr = (const u8 *)&bios[index];
5279 for(i = 0; i < 4; i++) {
5280 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5281 reg = 0x00;
5282 for(j = 0; j < 2; j++) {
5283 regd = 0;
5284 if(ptr) {
5285 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5286 ptr += 4;
5288 /* reg = 0x00; */
5289 for(k = 0; k < 16; k++) {
5290 reg &= 0xfc;
5291 if(regd & 0x01) reg |= 0x01;
5292 if(regd & 0x02) reg |= 0x02;
5293 regd >>= 2;
5294 outSISIDXREG(SISCR, 0x6f, reg);
5295 inSISIDXREG(SISCR, 0x6f, reg);
5296 inSISIDXREG(SISCR, 0x6f, reg);
5297 reg += 0x08;
5302 ptr = cs148;
5303 if(ivideo->haveXGIROM) {
5304 ptr = (const u8 *)&bios[0x148];
5306 for(i = 0, j = 0; i < 2; i++, j += 8) {
5307 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5310 andSISIDXREG(SISCR, 0x89, 0x8f);
5312 ptr = cs45a;
5313 if(ivideo->haveXGIROM) {
5314 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5315 ptr = (const u8 *)&bios[index];
5317 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5318 reg = 0x80;
5319 for(i = 0; i < 5; i++) {
5320 reg &= 0xfc;
5321 if(regd & 0x01) reg |= 0x01;
5322 if(regd & 0x02) reg |= 0x02;
5323 regd >>= 2;
5324 outSISIDXREG(SISCR, 0x89, reg);
5325 inSISIDXREG(SISCR, 0x89, reg);
5326 inSISIDXREG(SISCR, 0x89, reg);
5327 reg += 0x10;
5330 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5331 if(ivideo->haveXGIROM) {
5332 v1 = bios[0x118 + regb];
5333 v2 = bios[0xf8 + regb];
5334 v3 = bios[0x120 + regb];
5335 v4 = bios[0x1ca];
5337 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5338 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5339 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5340 outSISIDXREG(SISCR, 0x41, v2);
5342 ptr = cs170;
5343 if(ivideo->haveXGIROM) {
5344 ptr = (const u8 *)&bios[0x170];
5346 for(i = 0, j = 0; i < 7; i++, j += 8) {
5347 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5350 outSISIDXREG(SISCR, 0x59, v3);
5352 ptr = cs1a8;
5353 if(ivideo->haveXGIROM) {
5354 ptr = (const u8 *)&bios[0x1a8];
5356 for(i = 0, j = 0; i < 3; i++, j += 8) {
5357 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5360 ptr = cs100;
5361 if(ivideo->haveXGIROM) {
5362 ptr = (const u8 *)&bios[0x100];
5364 for(i = 0, j = 0; i < 2; i++, j += 8) {
5365 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5368 outSISIDXREG(SISCR, 0xcf, v4);
5370 outSISIDXREG(SISCR, 0x83, 0x09);
5371 outSISIDXREG(SISCR, 0x87, 0x00);
5373 if(ivideo->chip == XGI_40) {
5374 if( (ivideo->revision_id == 1) ||
5375 (ivideo->revision_id == 2) ) {
5376 outSISIDXREG(SISCR, 0x8c, 0x87);
5380 outSISIDXREG(SISSR, 0x17, 0x00);
5381 outSISIDXREG(SISSR, 0x1a, 0x87);
5383 if(ivideo->chip == XGI_20) {
5384 outSISIDXREG(SISSR, 0x15, 0x00);
5385 outSISIDXREG(SISSR, 0x1c, 0x00);
5388 ramtype = 0x00; v1 = 0x10;
5389 if(ivideo->haveXGIROM) {
5390 ramtype = bios[0x62];
5391 v1 = bios[0x1d2];
5393 if(!(ramtype & 0x80)) {
5394 if(ivideo->chip == XGI_20) {
5395 outSISIDXREG(SISCR, 0x97, v1);
5396 inSISIDXREG(SISCR, 0x97, reg);
5397 if(reg & 0x10) {
5398 ramtype = (reg & 0x01) << 1;
5400 } else {
5401 inSISIDXREG(SISSR, 0x39, reg);
5402 ramtype = reg & 0x02;
5403 if(!(ramtype)) {
5404 inSISIDXREG(SISSR, 0x3a, reg);
5405 ramtype = (reg >> 1) & 0x01;
5409 ramtype &= 0x07;
5411 regb = 0; /* ! */
5413 switch(ramtype) {
5414 case 0:
5415 sisfb_post_xgi_setclocks(ivideo, regb);
5416 if((ivideo->chip == XGI_20) ||
5417 (ivideo->revision_id == 1) ||
5418 (ivideo->revision_id == 2)) {
5419 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5420 if(ivideo->haveXGIROM) {
5421 v1 = bios[regb + 0x158];
5422 v2 = bios[regb + 0x160];
5423 v3 = bios[regb + 0x168];
5425 outSISIDXREG(SISCR, 0x82, v1);
5426 outSISIDXREG(SISCR, 0x85, v2);
5427 outSISIDXREG(SISCR, 0x86, v3);
5428 } else {
5429 outSISIDXREG(SISCR, 0x82, 0x88);
5430 outSISIDXREG(SISCR, 0x86, 0x00);
5431 inSISIDXREG(SISCR, 0x86, reg);
5432 outSISIDXREG(SISCR, 0x86, 0x88);
5433 inSISIDXREG(SISCR, 0x86, reg);
5434 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5435 outSISIDXREG(SISCR, 0x82, 0x77);
5436 outSISIDXREG(SISCR, 0x85, 0x00);
5437 inSISIDXREG(SISCR, 0x85, reg);
5438 outSISIDXREG(SISCR, 0x85, 0x88);
5439 inSISIDXREG(SISCR, 0x85, reg);
5440 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5441 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5443 if(ivideo->chip == XGI_40) {
5444 outSISIDXREG(SISCR, 0x97, 0x00);
5446 outSISIDXREG(SISCR, 0x98, 0x01);
5447 outSISIDXREG(SISCR, 0x9a, 0x02);
5449 outSISIDXREG(SISSR, 0x18, 0x01);
5450 if((ivideo->chip == XGI_20) ||
5451 (ivideo->revision_id == 2)) {
5452 outSISIDXREG(SISSR, 0x19, 0x40);
5453 } else {
5454 outSISIDXREG(SISSR, 0x19, 0x20);
5456 outSISIDXREG(SISSR, 0x16, 0x00);
5457 outSISIDXREG(SISSR, 0x16, 0x80);
5458 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5459 sisfb_post_xgi_delay(ivideo, 0x43);
5460 sisfb_post_xgi_delay(ivideo, 0x43);
5461 sisfb_post_xgi_delay(ivideo, 0x43);
5462 outSISIDXREG(SISSR, 0x18, 0x00);
5463 if((ivideo->chip == XGI_20) ||
5464 (ivideo->revision_id == 2)) {
5465 outSISIDXREG(SISSR, 0x19, 0x40);
5466 } else {
5467 outSISIDXREG(SISSR, 0x19, 0x20);
5469 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5470 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5472 outSISIDXREG(SISSR, 0x16, 0x00);
5473 outSISIDXREG(SISSR, 0x16, 0x80);
5474 sisfb_post_xgi_delay(ivideo, 4);
5475 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5476 if(ivideo->haveXGIROM) {
5477 v1 = bios[0xf0];
5478 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5479 v2 = bios[index];
5480 v3 = bios[index + 1];
5481 v4 = bios[index + 2];
5482 v5 = bios[index + 3];
5484 outSISIDXREG(SISSR, 0x18, v1);
5485 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5486 outSISIDXREG(SISSR, 0x16, v2);
5487 outSISIDXREG(SISSR, 0x16, v3);
5488 sisfb_post_xgi_delay(ivideo, 0x43);
5489 outSISIDXREG(SISSR, 0x1b, 0x03);
5490 sisfb_post_xgi_delay(ivideo, 0x22);
5491 outSISIDXREG(SISSR, 0x18, v1);
5492 outSISIDXREG(SISSR, 0x19, 0x00);
5493 outSISIDXREG(SISSR, 0x16, v4);
5494 outSISIDXREG(SISSR, 0x16, v5);
5495 outSISIDXREG(SISSR, 0x1b, 0x00);
5496 break;
5497 case 1:
5498 outSISIDXREG(SISCR, 0x82, 0x77);
5499 outSISIDXREG(SISCR, 0x86, 0x00);
5500 inSISIDXREG(SISCR, 0x86, reg);
5501 outSISIDXREG(SISCR, 0x86, 0x88);
5502 inSISIDXREG(SISCR, 0x86, reg);
5503 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5504 if(ivideo->haveXGIROM) {
5505 v1 = bios[regb + 0x168];
5506 v2 = bios[regb + 0x160];
5507 v3 = bios[regb + 0x158];
5509 outSISIDXREG(SISCR, 0x86, v1);
5510 outSISIDXREG(SISCR, 0x82, 0x77);
5511 outSISIDXREG(SISCR, 0x85, 0x00);
5512 inSISIDXREG(SISCR, 0x85, reg);
5513 outSISIDXREG(SISCR, 0x85, 0x88);
5514 inSISIDXREG(SISCR, 0x85, reg);
5515 outSISIDXREG(SISCR, 0x85, v2);
5516 outSISIDXREG(SISCR, 0x82, v3);
5517 outSISIDXREG(SISCR, 0x98, 0x01);
5518 outSISIDXREG(SISCR, 0x9a, 0x02);
5520 outSISIDXREG(SISSR, 0x28, 0x64);
5521 outSISIDXREG(SISSR, 0x29, 0x63);
5522 sisfb_post_xgi_delay(ivideo, 15);
5523 outSISIDXREG(SISSR, 0x18, 0x00);
5524 outSISIDXREG(SISSR, 0x19, 0x20);
5525 outSISIDXREG(SISSR, 0x16, 0x00);
5526 outSISIDXREG(SISSR, 0x16, 0x80);
5527 outSISIDXREG(SISSR, 0x18, 0xc5);
5528 outSISIDXREG(SISSR, 0x19, 0x23);
5529 outSISIDXREG(SISSR, 0x16, 0x00);
5530 outSISIDXREG(SISSR, 0x16, 0x80);
5531 sisfb_post_xgi_delay(ivideo, 1);
5532 outSISIDXREG(SISCR, 0x97,0x11);
5533 sisfb_post_xgi_setclocks(ivideo, regb);
5534 sisfb_post_xgi_delay(ivideo, 0x46);
5535 outSISIDXREG(SISSR, 0x18, 0xc5);
5536 outSISIDXREG(SISSR, 0x19, 0x23);
5537 outSISIDXREG(SISSR, 0x16, 0x00);
5538 outSISIDXREG(SISSR, 0x16, 0x80);
5539 sisfb_post_xgi_delay(ivideo, 1);
5540 outSISIDXREG(SISSR, 0x1b, 0x04);
5541 sisfb_post_xgi_delay(ivideo, 1);
5542 outSISIDXREG(SISSR, 0x1b, 0x00);
5543 sisfb_post_xgi_delay(ivideo, 1);
5544 v1 = 0x31;
5545 if(ivideo->haveXGIROM) {
5546 v1 = bios[0xf0];
5548 outSISIDXREG(SISSR, 0x18, v1);
5549 outSISIDXREG(SISSR, 0x19, 0x06);
5550 outSISIDXREG(SISSR, 0x16, 0x04);
5551 outSISIDXREG(SISSR, 0x16, 0x84);
5552 sisfb_post_xgi_delay(ivideo, 1);
5553 break;
5554 default:
5555 sisfb_post_xgi_setclocks(ivideo, regb);
5556 if((ivideo->chip == XGI_40) &&
5557 ((ivideo->revision_id == 1) ||
5558 (ivideo->revision_id == 2))) {
5559 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5560 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5561 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5562 } else {
5563 outSISIDXREG(SISCR, 0x82, 0x88);
5564 outSISIDXREG(SISCR, 0x86, 0x00);
5565 inSISIDXREG(SISCR, 0x86, reg);
5566 outSISIDXREG(SISCR, 0x86, 0x88);
5567 outSISIDXREG(SISCR, 0x82, 0x77);
5568 outSISIDXREG(SISCR, 0x85, 0x00);
5569 inSISIDXREG(SISCR, 0x85, reg);
5570 outSISIDXREG(SISCR, 0x85, 0x88);
5571 inSISIDXREG(SISCR, 0x85, reg);
5572 v1 = cs160[regb]; v2 = cs158[regb];
5573 if(ivideo->haveXGIROM) {
5574 v1 = bios[regb + 0x160];
5575 v2 = bios[regb + 0x158];
5577 outSISIDXREG(SISCR, 0x85, v1);
5578 outSISIDXREG(SISCR, 0x82, v2);
5580 if(ivideo->chip == XGI_40) {
5581 outSISIDXREG(SISCR, 0x97, 0x11);
5583 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5584 outSISIDXREG(SISCR, 0x98, 0x01);
5585 } else {
5586 outSISIDXREG(SISCR, 0x98, 0x03);
5588 outSISIDXREG(SISCR, 0x9a, 0x02);
5590 if(ivideo->chip == XGI_40) {
5591 outSISIDXREG(SISSR, 0x18, 0x01);
5592 } else {
5593 outSISIDXREG(SISSR, 0x18, 0x00);
5595 outSISIDXREG(SISSR, 0x19, 0x40);
5596 outSISIDXREG(SISSR, 0x16, 0x00);
5597 outSISIDXREG(SISSR, 0x16, 0x80);
5598 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5599 sisfb_post_xgi_delay(ivideo, 0x43);
5600 sisfb_post_xgi_delay(ivideo, 0x43);
5601 sisfb_post_xgi_delay(ivideo, 0x43);
5602 outSISIDXREG(SISSR, 0x18, 0x00);
5603 outSISIDXREG(SISSR, 0x19, 0x40);
5604 outSISIDXREG(SISSR, 0x16, 0x00);
5605 outSISIDXREG(SISSR, 0x16, 0x80);
5607 sisfb_post_xgi_delay(ivideo, 4);
5608 v1 = 0x31;
5609 if(ivideo->haveXGIROM) {
5610 v1 = bios[0xf0];
5612 outSISIDXREG(SISSR, 0x18, v1);
5613 outSISIDXREG(SISSR, 0x19, 0x01);
5614 if(ivideo->chip == XGI_40) {
5615 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5616 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5617 } else {
5618 outSISIDXREG(SISSR, 0x16, 0x05);
5619 outSISIDXREG(SISSR, 0x16, 0x85);
5621 sisfb_post_xgi_delay(ivideo, 0x43);
5622 if(ivideo->chip == XGI_40) {
5623 outSISIDXREG(SISSR, 0x1b, 0x01);
5624 } else {
5625 outSISIDXREG(SISSR, 0x1b, 0x03);
5627 sisfb_post_xgi_delay(ivideo, 0x22);
5628 outSISIDXREG(SISSR, 0x18, v1);
5629 outSISIDXREG(SISSR, 0x19, 0x00);
5630 if(ivideo->chip == XGI_40) {
5631 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5632 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5633 } else {
5634 outSISIDXREG(SISSR, 0x16, 0x05);
5635 outSISIDXREG(SISSR, 0x16, 0x85);
5637 outSISIDXREG(SISSR, 0x1b, 0x00);
5640 regb = 0; /* ! */
5641 v1 = 0x03;
5642 if(ivideo->haveXGIROM) {
5643 v1 = bios[0x110 + regb];
5645 outSISIDXREG(SISSR, 0x1b, v1);
5647 /* RAM size */
5648 v1 = 0x00; v2 = 0x00;
5649 if(ivideo->haveXGIROM) {
5650 v1 = bios[0x62];
5651 v2 = bios[0x63];
5653 regb = 0; /* ! */
5654 regd = 1 << regb;
5655 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5657 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5658 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5660 } else {
5662 /* Set default mode, don't clear screen */
5663 ivideo->SiS_Pr.SiS_UseOEM = false;
5664 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5665 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5666 ivideo->curFSTN = ivideo->curDSTN = 0;
5667 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5668 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5670 outSISIDXREG(SISSR, 0x05, 0x86);
5672 /* Disable read-cache */
5673 andSISIDXREG(SISSR, 0x21, 0xdf);
5674 sisfb_post_xgi_ramsize(ivideo);
5675 /* Enable read-cache */
5676 orSISIDXREG(SISSR, 0x21, 0x20);
5680 #if 0
5681 printk(KERN_DEBUG "-----------------\n");
5682 for(i = 0; i < 0xff; i++) {
5683 inSISIDXREG(SISCR, i, reg);
5684 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5686 for(i = 0; i < 0x40; i++) {
5687 inSISIDXREG(SISSR, i, reg);
5688 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5690 printk(KERN_DEBUG "-----------------\n");
5691 #endif
5693 /* Sense CRT1 */
5694 if(ivideo->chip == XGI_20) {
5695 orSISIDXREG(SISCR, 0x32, 0x20);
5696 } else {
5697 inSISIDXREG(SISPART4, 0x00, reg);
5698 if((reg == 1) || (reg == 2)) {
5699 sisfb_sense_crt1(ivideo);
5700 } else {
5701 orSISIDXREG(SISCR, 0x32, 0x20);
5705 /* Set default mode, don't clear screen */
5706 ivideo->SiS_Pr.SiS_UseOEM = false;
5707 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5708 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5709 ivideo->curFSTN = ivideo->curDSTN = 0;
5710 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5712 outSISIDXREG(SISSR, 0x05, 0x86);
5714 /* Display off */
5715 orSISIDXREG(SISSR, 0x01, 0x20);
5717 /* Save mode number in CR34 */
5718 outSISIDXREG(SISCR, 0x34, 0x2e);
5720 /* Let everyone know what the current mode is */
5721 ivideo->modeprechange = 0x2e;
5723 if(ivideo->chip == XGI_40) {
5724 inSISIDXREG(SISCR, 0xca, reg);
5725 inSISIDXREG(SISCR, 0xcc, v1);
5726 if((reg & 0x10) && (!(v1 & 0x04))) {
5727 printk(KERN_ERR
5728 "sisfb: Please connect power to the card.\n");
5729 return 0;
5733 return 1;
5735 #endif
5737 static int __devinit
5738 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5740 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5741 struct sis_video_info *ivideo = NULL;
5742 struct fb_info *sis_fb_info = NULL;
5743 u16 reg16;
5744 u8 reg;
5745 int i, ret;
5747 if(sisfb_off)
5748 return -ENXIO;
5750 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5751 if(!sis_fb_info)
5752 return -ENOMEM;
5754 ivideo = (struct sis_video_info *)sis_fb_info->par;
5755 ivideo->memyselfandi = sis_fb_info;
5757 ivideo->sisfb_id = SISFB_ID;
5759 if(card_list == NULL) {
5760 ivideo->cardnumber = 0;
5761 } else {
5762 struct sis_video_info *countvideo = card_list;
5763 ivideo->cardnumber = 1;
5764 while((countvideo = countvideo->next) != NULL)
5765 ivideo->cardnumber++;
5768 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5770 ivideo->warncount = 0;
5771 ivideo->chip_id = pdev->device;
5772 ivideo->chip_vendor = pdev->vendor;
5773 ivideo->revision_id = pdev->revision;
5774 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5775 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
5776 ivideo->sisvga_enabled = reg16 & 0x01;
5777 ivideo->pcibus = pdev->bus->number;
5778 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5779 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5780 ivideo->subsysvendor = pdev->subsystem_vendor;
5781 ivideo->subsysdevice = pdev->subsystem_device;
5783 #ifndef MODULE
5784 if(sisfb_mode_idx == -1) {
5785 sisfb_get_vga_mode_from_kernel();
5787 #endif
5789 ivideo->chip = chipinfo->chip;
5790 ivideo->sisvga_engine = chipinfo->vgaengine;
5791 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5792 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5793 ivideo->mni = chipinfo->mni;
5795 ivideo->detectedpdc = 0xff;
5796 ivideo->detectedpdca = 0xff;
5797 ivideo->detectedlcda = 0xff;
5799 ivideo->sisfb_thismonitor.datavalid = false;
5801 ivideo->current_base = 0;
5803 ivideo->engineok = 0;
5805 ivideo->sisfb_was_boot_device = 0;
5807 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5808 if(ivideo->sisvga_enabled)
5809 ivideo->sisfb_was_boot_device = 1;
5810 else {
5811 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5812 "but marked as boot video device ???\n");
5813 printk(KERN_DEBUG "sisfb: I will not accept this "
5814 "as the primary VGA device\n");
5818 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5819 ivideo->sisfb_accel = sisfb_accel;
5820 ivideo->sisfb_ypan = sisfb_ypan;
5821 ivideo->sisfb_max = sisfb_max;
5822 ivideo->sisfb_userom = sisfb_userom;
5823 ivideo->sisfb_useoem = sisfb_useoem;
5824 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5825 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5826 ivideo->sisfb_crt1off = sisfb_crt1off;
5827 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5828 ivideo->sisfb_crt2type = sisfb_crt2type;
5829 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5830 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5831 ivideo->sisfb_dstn = sisfb_dstn;
5832 ivideo->sisfb_fstn = sisfb_fstn;
5833 ivideo->sisfb_tvplug = sisfb_tvplug;
5834 ivideo->sisfb_tvstd = sisfb_tvstd;
5835 ivideo->tvxpos = sisfb_tvxposoffset;
5836 ivideo->tvypos = sisfb_tvyposoffset;
5837 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5838 ivideo->refresh_rate = 0;
5839 if(ivideo->sisfb_parm_rate != -1) {
5840 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5843 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5844 ivideo->SiS_Pr.CenterScreen = -1;
5845 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5846 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5848 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5849 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5850 ivideo->SiS_Pr.SiS_ChSW = false;
5851 ivideo->SiS_Pr.SiS_UseLCDA = false;
5852 ivideo->SiS_Pr.HaveEMI = false;
5853 ivideo->SiS_Pr.HaveEMILCD = false;
5854 ivideo->SiS_Pr.OverruleEMI = false;
5855 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
5856 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5857 ivideo->SiS_Pr.PDC = -1;
5858 ivideo->SiS_Pr.PDCA = -1;
5859 ivideo->SiS_Pr.DDCPortMixup = false;
5860 #ifdef CONFIG_FB_SIS_315
5861 if(ivideo->chip >= SIS_330) {
5862 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5863 if(ivideo->chip >= SIS_661) {
5864 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
5867 #endif
5869 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5871 pci_set_drvdata(pdev, ivideo);
5873 /* Patch special cases */
5874 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5875 switch(ivideo->nbridge->device) {
5876 #ifdef CONFIG_FB_SIS_300
5877 case PCI_DEVICE_ID_SI_730:
5878 ivideo->chip = SIS_730;
5879 strcpy(ivideo->myid, "SiS 730");
5880 break;
5881 #endif
5882 #ifdef CONFIG_FB_SIS_315
5883 case PCI_DEVICE_ID_SI_651:
5884 /* ivideo->chip is ok */
5885 strcpy(ivideo->myid, "SiS 651");
5886 break;
5887 case PCI_DEVICE_ID_SI_740:
5888 ivideo->chip = SIS_740;
5889 strcpy(ivideo->myid, "SiS 740");
5890 break;
5891 case PCI_DEVICE_ID_SI_661:
5892 ivideo->chip = SIS_661;
5893 strcpy(ivideo->myid, "SiS 661");
5894 break;
5895 case PCI_DEVICE_ID_SI_741:
5896 ivideo->chip = SIS_741;
5897 strcpy(ivideo->myid, "SiS 741");
5898 break;
5899 case PCI_DEVICE_ID_SI_760:
5900 ivideo->chip = SIS_760;
5901 strcpy(ivideo->myid, "SiS 760");
5902 break;
5903 case PCI_DEVICE_ID_SI_761:
5904 ivideo->chip = SIS_761;
5905 strcpy(ivideo->myid, "SiS 761");
5906 break;
5907 #endif
5908 default:
5909 break;
5913 ivideo->SiS_Pr.ChipType = ivideo->chip;
5915 ivideo->SiS_Pr.ivideo = (void *)ivideo;
5917 #ifdef CONFIG_FB_SIS_315
5918 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5919 (ivideo->SiS_Pr.ChipType == SIS_315)) {
5920 ivideo->SiS_Pr.ChipType = SIS_315H;
5922 #endif
5924 if(!ivideo->sisvga_enabled) {
5925 if(pci_enable_device(pdev)) {
5926 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
5927 pci_set_drvdata(pdev, NULL);
5928 framebuffer_release(sis_fb_info);
5929 return -EIO;
5933 ivideo->video_base = pci_resource_start(pdev, 0);
5934 ivideo->video_size = pci_resource_len(pdev, 0);
5935 ivideo->mmio_base = pci_resource_start(pdev, 1);
5936 ivideo->mmio_size = pci_resource_len(pdev, 1);
5937 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
5938 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
5940 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
5942 #ifdef CONFIG_FB_SIS_300
5943 /* Find PCI systems for Chrontel/GPIO communication setup */
5944 if(ivideo->chip == SIS_630) {
5945 i = 0;
5946 do {
5947 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5948 mychswtable[i].subsysCard == ivideo->subsysdevice) {
5949 ivideo->SiS_Pr.SiS_ChSW = true;
5950 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5951 "requiring Chrontel/GPIO setup\n",
5952 mychswtable[i].vendorName,
5953 mychswtable[i].cardName);
5954 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
5955 break;
5957 i++;
5958 } while(mychswtable[i].subsysVendor != 0);
5960 #endif
5962 #ifdef CONFIG_FB_SIS_315
5963 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
5964 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
5966 #endif
5968 outSISIDXREG(SISSR, 0x05, 0x86);
5970 if( (!ivideo->sisvga_enabled)
5971 #if !defined(__i386__) && !defined(__x86_64__)
5972 || (sisfb_resetcard)
5973 #endif
5975 for(i = 0x30; i <= 0x3f; i++) {
5976 outSISIDXREG(SISCR, i, 0x00);
5980 /* Find out about current video mode */
5981 ivideo->modeprechange = 0x03;
5982 inSISIDXREG(SISCR, 0x34, reg);
5983 if(reg & 0x7f) {
5984 ivideo->modeprechange = reg & 0x7f;
5985 } else if(ivideo->sisvga_enabled) {
5986 #if defined(__i386__) || defined(__x86_64__)
5987 unsigned char __iomem *tt = ioremap(0x400, 0x100);
5988 if(tt) {
5989 ivideo->modeprechange = readb(tt + 0x49);
5990 iounmap(tt);
5992 #endif
5995 /* Search and copy ROM image */
5996 ivideo->bios_abase = NULL;
5997 ivideo->SiS_Pr.VirtualRomBase = NULL;
5998 ivideo->SiS_Pr.UseROM = false;
5999 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
6000 if(ivideo->sisfb_userom) {
6001 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6002 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6003 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
6004 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6005 ivideo->SiS_Pr.UseROM ? "" : "not ");
6006 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6007 ivideo->SiS_Pr.UseROM = false;
6008 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
6009 if( (ivideo->revision_id == 2) &&
6010 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6011 ivideo->SiS_Pr.DDCPortMixup = true;
6014 } else {
6015 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6018 /* Find systems for special custom timing */
6019 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6020 sisfb_detect_custom_timing(ivideo);
6023 /* POST card in case this has not been done by the BIOS */
6024 if( (!ivideo->sisvga_enabled)
6025 #if !defined(__i386__) && !defined(__x86_64__)
6026 || (sisfb_resetcard)
6027 #endif
6029 #ifdef CONFIG_FB_SIS_300
6030 if(ivideo->sisvga_engine == SIS_300_VGA) {
6031 if(ivideo->chip == SIS_300) {
6032 sisfb_post_sis300(pdev);
6033 ivideo->sisfb_can_post = 1;
6036 #endif
6038 #ifdef CONFIG_FB_SIS_315
6039 if(ivideo->sisvga_engine == SIS_315_VGA) {
6040 int result = 1;
6041 /* if((ivideo->chip == SIS_315H) ||
6042 (ivideo->chip == SIS_315) ||
6043 (ivideo->chip == SIS_315PRO) ||
6044 (ivideo->chip == SIS_330)) {
6045 sisfb_post_sis315330(pdev);
6046 } else */ if(ivideo->chip == XGI_20) {
6047 result = sisfb_post_xgi(pdev);
6048 ivideo->sisfb_can_post = 1;
6049 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6050 result = sisfb_post_xgi(pdev);
6051 ivideo->sisfb_can_post = 1;
6052 } else {
6053 printk(KERN_INFO "sisfb: Card is not "
6054 "POSTed and sisfb can't do this either.\n");
6056 if(!result) {
6057 printk(KERN_ERR "sisfb: Failed to POST card\n");
6058 ret = -ENODEV;
6059 goto error_3;
6062 #endif
6065 ivideo->sisfb_card_posted = 1;
6067 /* Find out about RAM size */
6068 if(sisfb_get_dram_size(ivideo)) {
6069 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6070 ret = -ENODEV;
6071 goto error_3;
6075 /* Enable PCI addressing and MMIO */
6076 if((ivideo->sisfb_mode_idx < 0) ||
6077 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6078 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6079 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6080 /* Enable 2D accelerator engine */
6081 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6084 if(sisfb_pdc != 0xff) {
6085 if(ivideo->sisvga_engine == SIS_300_VGA)
6086 sisfb_pdc &= 0x3c;
6087 else
6088 sisfb_pdc &= 0x1f;
6089 ivideo->SiS_Pr.PDC = sisfb_pdc;
6091 #ifdef CONFIG_FB_SIS_315
6092 if(ivideo->sisvga_engine == SIS_315_VGA) {
6093 if(sisfb_pdca != 0xff)
6094 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6096 #endif
6098 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6099 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6100 (int)(ivideo->video_size >> 20));
6101 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6102 ret = -ENODEV;
6103 goto error_3;
6106 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6107 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6108 ret = -ENODEV;
6109 goto error_2;
6112 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6113 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6114 if(!ivideo->video_vbase) {
6115 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6116 ret = -ENODEV;
6117 goto error_1;
6120 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6121 if(!ivideo->mmio_vbase) {
6122 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6123 ret = -ENODEV;
6124 error_0: iounmap(ivideo->video_vbase);
6125 error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6126 error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6127 error_3: vfree(ivideo->bios_abase);
6128 if(ivideo->lpcdev)
6129 pci_dev_put(ivideo->lpcdev);
6130 if(ivideo->nbridge)
6131 pci_dev_put(ivideo->nbridge);
6132 pci_set_drvdata(pdev, NULL);
6133 if(!ivideo->sisvga_enabled)
6134 pci_disable_device(pdev);
6135 framebuffer_release(sis_fb_info);
6136 return ret;
6139 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6140 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6142 if(ivideo->video_offset) {
6143 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6144 ivideo->video_offset / 1024);
6147 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6148 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6151 /* Determine the size of the command queue */
6152 if(ivideo->sisvga_engine == SIS_300_VGA) {
6153 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6154 } else {
6155 if(ivideo->chip == XGI_20) {
6156 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6157 } else {
6158 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6162 /* Engines are no longer initialized here; this is
6163 * now done after the first mode-switch (if the
6164 * submitted var has its acceleration flags set).
6167 /* Calculate the base of the (unused) hw cursor */
6168 ivideo->hwcursor_vbase = ivideo->video_vbase
6169 + ivideo->video_size
6170 - ivideo->cmdQueueSize
6171 - ivideo->hwcursor_size;
6172 ivideo->caps |= HW_CURSOR_CAP;
6174 /* Initialize offscreen memory manager */
6175 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6176 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6179 /* Used for clearing the screen only, therefore respect our mem limit */
6180 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6181 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6183 ivideo->mtrr = -1;
6185 ivideo->vbflags = 0;
6186 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6187 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6188 ivideo->defmodeidx = DEFAULT_MODE;
6190 ivideo->newrom = 0;
6191 if(ivideo->chip < XGI_20) {
6192 if(ivideo->bios_abase) {
6193 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6197 if((ivideo->sisfb_mode_idx < 0) ||
6198 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6200 sisfb_sense_crt1(ivideo);
6202 sisfb_get_VB_type(ivideo);
6204 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6205 sisfb_detect_VB_connect(ivideo);
6208 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6210 /* Decide on which CRT2 device to use */
6211 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6212 if(ivideo->sisfb_crt2type != -1) {
6213 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6214 (ivideo->vbflags & CRT2_LCD)) {
6215 ivideo->currentvbflags |= CRT2_LCD;
6216 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6217 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6219 } else {
6220 /* Chrontel 700x TV detection often unreliable, therefore
6221 * use a different default order on such machines
6223 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6224 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6225 if(ivideo->vbflags & CRT2_LCD)
6226 ivideo->currentvbflags |= CRT2_LCD;
6227 else if(ivideo->vbflags & CRT2_TV)
6228 ivideo->currentvbflags |= CRT2_TV;
6229 else if(ivideo->vbflags & CRT2_VGA)
6230 ivideo->currentvbflags |= CRT2_VGA;
6231 } else {
6232 if(ivideo->vbflags & CRT2_TV)
6233 ivideo->currentvbflags |= CRT2_TV;
6234 else if(ivideo->vbflags & CRT2_LCD)
6235 ivideo->currentvbflags |= CRT2_LCD;
6236 else if(ivideo->vbflags & CRT2_VGA)
6237 ivideo->currentvbflags |= CRT2_VGA;
6242 if(ivideo->vbflags & CRT2_LCD) {
6243 sisfb_detect_lcd_type(ivideo);
6246 sisfb_save_pdc_emi(ivideo);
6248 if(!ivideo->sisfb_crt1off) {
6249 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6250 } else {
6251 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6252 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6253 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6257 if(ivideo->sisfb_mode_idx >= 0) {
6258 int bu = ivideo->sisfb_mode_idx;
6259 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6260 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6261 if(bu != ivideo->sisfb_mode_idx) {
6262 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6263 sisbios_mode[bu].xres,
6264 sisbios_mode[bu].yres,
6265 sisbios_mode[bu].bpp);
6269 if(ivideo->sisfb_mode_idx < 0) {
6270 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6271 case CRT2_LCD:
6272 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6273 break;
6274 case CRT2_TV:
6275 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6276 break;
6277 default:
6278 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6279 break;
6283 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6285 if(ivideo->refresh_rate != 0) {
6286 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6287 ivideo->sisfb_mode_idx);
6290 if(ivideo->rate_idx == 0) {
6291 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6292 ivideo->refresh_rate = 60;
6295 if(ivideo->sisfb_thismonitor.datavalid) {
6296 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6297 ivideo->sisfb_mode_idx,
6298 ivideo->rate_idx,
6299 ivideo->refresh_rate)) {
6300 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6301 "exceeds monitor specs!\n");
6305 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6306 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6307 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6309 sisfb_set_vparms(ivideo);
6311 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6312 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6313 ivideo->refresh_rate);
6315 /* Set up the default var according to chosen default display mode */
6316 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6317 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6318 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6320 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6322 ivideo->default_var.pixclock = (u32) (1000000000 /
6323 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6325 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6326 ivideo->rate_idx, &ivideo->default_var)) {
6327 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6328 ivideo->default_var.pixclock <<= 1;
6332 if(ivideo->sisfb_ypan) {
6333 /* Maximize regardless of sisfb_max at startup */
6334 ivideo->default_var.yres_virtual =
6335 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6336 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6337 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6341 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6343 ivideo->accel = 0;
6344 if(ivideo->sisfb_accel) {
6345 ivideo->accel = -1;
6346 #ifdef STUPID_ACCELF_TEXT_SHIT
6347 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6348 #endif
6350 sisfb_initaccel(ivideo);
6352 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6353 sis_fb_info->flags = FBINFO_DEFAULT |
6354 FBINFO_HWACCEL_YPAN |
6355 FBINFO_HWACCEL_XPAN |
6356 FBINFO_HWACCEL_COPYAREA |
6357 FBINFO_HWACCEL_FILLRECT |
6358 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6359 #else
6360 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6361 #endif
6362 sis_fb_info->var = ivideo->default_var;
6363 sis_fb_info->fix = ivideo->sisfb_fix;
6364 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6365 sis_fb_info->fbops = &sisfb_ops;
6366 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6368 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6370 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6372 #ifdef CONFIG_MTRR
6373 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6374 MTRR_TYPE_WRCOMB, 1);
6375 if(ivideo->mtrr < 0) {
6376 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6378 #endif
6380 if(register_framebuffer(sis_fb_info) < 0) {
6381 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6382 ret = -EINVAL;
6383 iounmap(ivideo->mmio_vbase);
6384 goto error_0;
6387 ivideo->registered = 1;
6389 /* Enlist us */
6390 ivideo->next = card_list;
6391 card_list = ivideo;
6393 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6394 ivideo->sisfb_accel ? "enabled" : "disabled",
6395 ivideo->sisfb_ypan ?
6396 (ivideo->sisfb_max ? "enabled (auto-max)" :
6397 "enabled (no auto-max)") :
6398 "disabled");
6401 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6402 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6404 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6406 } /* if mode = "none" */
6408 return 0;
6411 /*****************************************************/
6412 /* PCI DEVICE HANDLING */
6413 /*****************************************************/
6415 static void __devexit sisfb_remove(struct pci_dev *pdev)
6417 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6418 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6419 int registered = ivideo->registered;
6420 int modechanged = ivideo->modechanged;
6422 /* Unmap */
6423 iounmap(ivideo->mmio_vbase);
6424 iounmap(ivideo->video_vbase);
6426 /* Release mem regions */
6427 release_mem_region(ivideo->video_base, ivideo->video_size);
6428 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6430 vfree(ivideo->bios_abase);
6432 if(ivideo->lpcdev)
6433 pci_dev_put(ivideo->lpcdev);
6435 if(ivideo->nbridge)
6436 pci_dev_put(ivideo->nbridge);
6438 #ifdef CONFIG_MTRR
6439 /* Release MTRR region */
6440 if(ivideo->mtrr >= 0)
6441 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6442 #endif
6444 pci_set_drvdata(pdev, NULL);
6446 /* If device was disabled when starting, disable
6447 * it when quitting.
6449 if(!ivideo->sisvga_enabled)
6450 pci_disable_device(pdev);
6452 /* Unregister the framebuffer */
6453 if(ivideo->registered) {
6454 unregister_framebuffer(sis_fb_info);
6455 framebuffer_release(sis_fb_info);
6458 /* OK, our ivideo is gone for good from here. */
6460 /* TODO: Restore the initial mode
6461 * This sounds easy but is as good as impossible
6462 * on many machines with SiS chip and video bridge
6463 * since text modes are always set up differently
6464 * from machine to machine. Depends on the type
6465 * of integration between chipset and bridge.
6467 if(registered && modechanged)
6468 printk(KERN_INFO
6469 "sisfb: Restoring of text mode not supported yet\n");
6472 static struct pci_driver sisfb_driver = {
6473 .name = "sisfb",
6474 .id_table = sisfb_pci_table,
6475 .probe = sisfb_probe,
6476 .remove = __devexit_p(sisfb_remove)
6479 static int __init sisfb_init(void)
6481 #ifndef MODULE
6482 char *options = NULL;
6484 if(fb_get_options("sisfb", &options))
6485 return -ENODEV;
6487 sisfb_setup(options);
6488 #endif
6489 return pci_register_driver(&sisfb_driver);
6492 #ifndef MODULE
6493 module_init(sisfb_init);
6494 #endif
6496 /*****************************************************/
6497 /* MODULE */
6498 /*****************************************************/
6500 #ifdef MODULE
6502 static char *mode = NULL;
6503 static int vesa = -1;
6504 static unsigned int rate = 0;
6505 static unsigned int crt1off = 1;
6506 static unsigned int mem = 0;
6507 static char *forcecrt2type = NULL;
6508 static int forcecrt1 = -1;
6509 static int pdc = -1;
6510 static int pdc1 = -1;
6511 static int noaccel = -1;
6512 static int noypan = -1;
6513 static int nomax = -1;
6514 static int userom = -1;
6515 static int useoem = -1;
6516 static char *tvstandard = NULL;
6517 static int nocrt2rate = 0;
6518 static int scalelcd = -1;
6519 static char *specialtiming = NULL;
6520 static int lvdshl = -1;
6521 static int tvxposoffset = 0, tvyposoffset = 0;
6522 #if !defined(__i386__) && !defined(__x86_64__)
6523 static int resetcard = 0;
6524 static int videoram = 0;
6525 #endif
6527 static int __init sisfb_init_module(void)
6529 sisfb_setdefaultparms();
6531 if(rate)
6532 sisfb_parm_rate = rate;
6534 if((scalelcd == 0) || (scalelcd == 1))
6535 sisfb_scalelcd = scalelcd ^ 1;
6537 /* Need to check crt2 type first for fstn/dstn */
6539 if(forcecrt2type)
6540 sisfb_search_crt2type(forcecrt2type);
6542 if(tvstandard)
6543 sisfb_search_tvstd(tvstandard);
6545 if(mode)
6546 sisfb_search_mode(mode, false);
6547 else if(vesa != -1)
6548 sisfb_search_vesamode(vesa, false);
6550 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6552 sisfb_forcecrt1 = forcecrt1;
6553 if(forcecrt1 == 1)
6554 sisfb_crt1off = 0;
6555 else if(forcecrt1 == 0)
6556 sisfb_crt1off = 1;
6558 if(noaccel == 1)
6559 sisfb_accel = 0;
6560 else if(noaccel == 0)
6561 sisfb_accel = 1;
6563 if(noypan == 1)
6564 sisfb_ypan = 0;
6565 else if(noypan == 0)
6566 sisfb_ypan = 1;
6568 if(nomax == 1)
6569 sisfb_max = 0;
6570 else if(nomax == 0)
6571 sisfb_max = 1;
6573 if(mem)
6574 sisfb_parm_mem = mem;
6576 if(userom != -1)
6577 sisfb_userom = userom;
6579 if(useoem != -1)
6580 sisfb_useoem = useoem;
6582 if(pdc != -1)
6583 sisfb_pdc = (pdc & 0x7f);
6585 if(pdc1 != -1)
6586 sisfb_pdca = (pdc1 & 0x1f);
6588 sisfb_nocrt2rate = nocrt2rate;
6590 if(specialtiming)
6591 sisfb_search_specialtiming(specialtiming);
6593 if((lvdshl >= 0) && (lvdshl <= 3))
6594 sisfb_lvdshl = lvdshl;
6596 sisfb_tvxposoffset = tvxposoffset;
6597 sisfb_tvyposoffset = tvyposoffset;
6599 #if !defined(__i386__) && !defined(__x86_64__)
6600 sisfb_resetcard = (resetcard) ? 1 : 0;
6601 if(videoram)
6602 sisfb_videoram = videoram;
6603 #endif
6605 return sisfb_init();
6608 static void __exit sisfb_remove_module(void)
6610 pci_unregister_driver(&sisfb_driver);
6611 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6614 module_init(sisfb_init_module);
6615 module_exit(sisfb_remove_module);
6617 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6618 MODULE_LICENSE("GPL");
6619 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6621 module_param(mem, int, 0);
6622 module_param(noaccel, int, 0);
6623 module_param(noypan, int, 0);
6624 module_param(nomax, int, 0);
6625 module_param(userom, int, 0);
6626 module_param(useoem, int, 0);
6627 module_param(mode, charp, 0);
6628 module_param(vesa, int, 0);
6629 module_param(rate, int, 0);
6630 module_param(forcecrt1, int, 0);
6631 module_param(forcecrt2type, charp, 0);
6632 module_param(scalelcd, int, 0);
6633 module_param(pdc, int, 0);
6634 module_param(pdc1, int, 0);
6635 module_param(specialtiming, charp, 0);
6636 module_param(lvdshl, int, 0);
6637 module_param(tvstandard, charp, 0);
6638 module_param(tvxposoffset, int, 0);
6639 module_param(tvyposoffset, int, 0);
6640 module_param(nocrt2rate, int, 0);
6641 #if !defined(__i386__) && !defined(__x86_64__)
6642 module_param(resetcard, int, 0);
6643 module_param(videoram, int, 0);
6644 #endif
6646 MODULE_PARM_DESC(mem,
6647 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6648 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6649 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6650 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6651 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6652 "The value is to be specified without 'KB'.\n");
6654 MODULE_PARM_DESC(noaccel,
6655 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6656 "(default: 0)\n");
6658 MODULE_PARM_DESC(noypan,
6659 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6660 "will be performed by redrawing the screen. (default: 0)\n");
6662 MODULE_PARM_DESC(nomax,
6663 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
6664 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6665 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6666 "enable the user to positively specify a virtual Y size of the screen using\n"
6667 "fbset. (default: 0)\n");
6669 MODULE_PARM_DESC(mode,
6670 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6671 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
6672 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6673 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6675 MODULE_PARM_DESC(vesa,
6676 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6677 "0x117 (default: 0x0103)\n");
6679 MODULE_PARM_DESC(rate,
6680 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6681 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6682 "will be ignored (default: 60)\n");
6684 MODULE_PARM_DESC(forcecrt1,
6685 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6686 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6687 "0=CRT1 OFF) (default: [autodetected])\n");
6689 MODULE_PARM_DESC(forcecrt2type,
6690 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6691 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6692 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6693 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6694 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6695 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6696 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6697 "depends on the very hardware in use. (default: [autodetected])\n");
6699 MODULE_PARM_DESC(scalelcd,
6700 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6701 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6702 "show black bars around the image, TMDS panels will probably do the scaling\n"
6703 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6705 MODULE_PARM_DESC(pdc,
6706 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
6707 "should detect this correctly in most cases; however, sometimes this is not\n"
6708 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
6709 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6710 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6711 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
6713 #ifdef CONFIG_FB_SIS_315
6714 MODULE_PARM_DESC(pdc1,
6715 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
6716 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6717 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6718 "implemented yet.\n");
6719 #endif
6721 MODULE_PARM_DESC(specialtiming,
6722 "\nPlease refer to documentation for more information on this option.\n");
6724 MODULE_PARM_DESC(lvdshl,
6725 "\nPlease refer to documentation for more information on this option.\n");
6727 MODULE_PARM_DESC(tvstandard,
6728 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6729 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6731 MODULE_PARM_DESC(tvxposoffset,
6732 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6733 "Default: 0\n");
6735 MODULE_PARM_DESC(tvyposoffset,
6736 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6737 "Default: 0\n");
6739 MODULE_PARM_DESC(nocrt2rate,
6740 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6741 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6743 #if !defined(__i386__) && !defined(__x86_64__)
6744 #ifdef CONFIG_FB_SIS_300
6745 MODULE_PARM_DESC(resetcard,
6746 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
6747 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6748 "currently). Default: 0\n");
6750 MODULE_PARM_DESC(videoram,
6751 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6752 "some non-x86 architectures where the memory auto detection fails. Only\n"
6753 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
6754 #endif
6755 #endif
6757 #endif /* /MODULE */
6759 /* _GPL only for new symbols. */
6760 EXPORT_SYMBOL(sis_malloc);
6761 EXPORT_SYMBOL(sis_free);
6762 EXPORT_SYMBOL_GPL(sis_malloc_new);
6763 EXPORT_SYMBOL_GPL(sis_free_new);