drivers/video/sis/sis_main.c: prevent reading uninitialized stack memory
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / video / sis / sis_main.c
blobe1836d7140a8cd10938d36f32a50fd8fa5b2581e
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 strcpy(fix->id, ivideo->myid);
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 #ifdef CONFIG_FB_SOFT_CURSOR
1898 .fb_cursor = soft_cursor,
1899 #endif
1900 .fb_sync = fbcon_sis_sync,
1901 #ifdef SIS_NEW_CONFIG_COMPAT
1902 .fb_compat_ioctl= sisfb_ioctl,
1903 #endif
1904 .fb_ioctl = sisfb_ioctl
1907 /* ---------------- Chip generation dependent routines ---------------- */
1909 static struct pci_dev * __devinit
1910 sisfb_get_northbridge(int basechipid)
1912 struct pci_dev *pdev = NULL;
1913 int nbridgenum, nbridgeidx, i;
1914 static const unsigned short nbridgeids[] = {
1915 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1916 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1917 PCI_DEVICE_ID_SI_730,
1918 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1919 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1920 PCI_DEVICE_ID_SI_651,
1921 PCI_DEVICE_ID_SI_740,
1922 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
1923 PCI_DEVICE_ID_SI_741,
1924 PCI_DEVICE_ID_SI_660,
1925 PCI_DEVICE_ID_SI_760,
1926 PCI_DEVICE_ID_SI_761
1929 switch(basechipid) {
1930 #ifdef CONFIG_FB_SIS_300
1931 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1932 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1933 #endif
1934 #ifdef CONFIG_FB_SIS_315
1935 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1936 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
1937 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
1938 #endif
1939 default: return NULL;
1941 for(i = 0; i < nbridgenum; i++) {
1942 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
1943 nbridgeids[nbridgeidx+i], NULL)))
1944 break;
1946 return pdev;
1949 static int __devinit
1950 sisfb_get_dram_size(struct sis_video_info *ivideo)
1952 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1953 u8 reg;
1954 #endif
1956 ivideo->video_size = 0;
1957 ivideo->UMAsize = ivideo->LFBsize = 0;
1959 switch(ivideo->chip) {
1960 #ifdef CONFIG_FB_SIS_300
1961 case SIS_300:
1962 inSISIDXREG(SISSR, 0x14, reg);
1963 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1964 break;
1965 case SIS_540:
1966 case SIS_630:
1967 case SIS_730:
1968 if(!ivideo->nbridge)
1969 return -1;
1970 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
1971 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1972 break;
1973 #endif
1974 #ifdef CONFIG_FB_SIS_315
1975 case SIS_315H:
1976 case SIS_315PRO:
1977 case SIS_315:
1978 inSISIDXREG(SISSR, 0x14, reg);
1979 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1980 switch((reg >> 2) & 0x03) {
1981 case 0x01:
1982 case 0x03:
1983 ivideo->video_size <<= 1;
1984 break;
1985 case 0x02:
1986 ivideo->video_size += (ivideo->video_size/2);
1988 break;
1989 case SIS_330:
1990 inSISIDXREG(SISSR, 0x14, reg);
1991 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1992 if(reg & 0x0c) ivideo->video_size <<= 1;
1993 break;
1994 case SIS_550:
1995 case SIS_650:
1996 case SIS_740:
1997 inSISIDXREG(SISSR, 0x14, reg);
1998 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
1999 break;
2000 case SIS_661:
2001 case SIS_741:
2002 inSISIDXREG(SISCR, 0x79, reg);
2003 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2004 break;
2005 case SIS_660:
2006 case SIS_760:
2007 case SIS_761:
2008 inSISIDXREG(SISCR, 0x79, reg);
2009 reg = (reg & 0xf0) >> 4;
2010 if(reg) {
2011 ivideo->video_size = (1 << reg) << 20;
2012 ivideo->UMAsize = ivideo->video_size;
2014 inSISIDXREG(SISCR, 0x78, reg);
2015 reg &= 0x30;
2016 if(reg) {
2017 if(reg == 0x10) {
2018 ivideo->LFBsize = (32 << 20);
2019 } else {
2020 ivideo->LFBsize = (64 << 20);
2022 ivideo->video_size += ivideo->LFBsize;
2024 break;
2025 case SIS_340:
2026 case XGI_20:
2027 case XGI_40:
2028 inSISIDXREG(SISSR, 0x14, reg);
2029 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2030 if(ivideo->chip != XGI_20) {
2031 reg = (reg & 0x0c) >> 2;
2032 if(ivideo->revision_id == 2) {
2033 if(reg & 0x01) reg = 0x02;
2034 else reg = 0x00;
2036 if(reg == 0x02) ivideo->video_size <<= 1;
2037 else if(reg == 0x03) ivideo->video_size <<= 2;
2039 break;
2040 #endif
2041 default:
2042 return -1;
2044 return 0;
2047 /* -------------- video bridge device detection --------------- */
2049 static void __devinit
2050 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2052 u8 cr32, temp;
2054 /* No CRT2 on XGI Z7 */
2055 if(ivideo->chip == XGI_20) {
2056 ivideo->sisfb_crt1off = 0;
2057 return;
2060 #ifdef CONFIG_FB_SIS_300
2061 if(ivideo->sisvga_engine == SIS_300_VGA) {
2062 inSISIDXREG(SISSR, 0x17, temp);
2063 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2064 /* PAL/NTSC is stored on SR16 on such machines */
2065 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2066 inSISIDXREG(SISSR, 0x16, temp);
2067 if(temp & 0x20)
2068 ivideo->vbflags |= TV_PAL;
2069 else
2070 ivideo->vbflags |= TV_NTSC;
2074 #endif
2076 inSISIDXREG(SISCR, 0x32, cr32);
2078 if(cr32 & SIS_CRT1) {
2079 ivideo->sisfb_crt1off = 0;
2080 } else {
2081 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2084 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2086 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2087 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2088 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2090 /* Check given parms for hardware compatibility.
2091 * (Cannot do this in the search_xx routines since we don't
2092 * know what hardware we are running on then)
2095 if(ivideo->chip != SIS_550) {
2096 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2099 if(ivideo->sisfb_tvplug != -1) {
2100 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2101 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2102 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2103 ivideo->sisfb_tvplug = -1;
2104 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2108 if(ivideo->sisfb_tvplug != -1) {
2109 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2110 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2111 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2112 ivideo->sisfb_tvplug = -1;
2113 printk(KERN_ERR "sisfb: HiVision not supported\n");
2117 if(ivideo->sisfb_tvstd != -1) {
2118 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2119 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2120 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2121 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2122 ivideo->sisfb_tvstd = -1;
2123 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2128 /* Detect/set TV plug & type */
2129 if(ivideo->sisfb_tvplug != -1) {
2130 ivideo->vbflags |= ivideo->sisfb_tvplug;
2131 } else {
2132 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2133 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2134 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2135 else {
2136 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2137 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2141 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2142 if(ivideo->sisfb_tvstd != -1) {
2143 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2144 ivideo->vbflags |= ivideo->sisfb_tvstd;
2146 if(ivideo->vbflags & TV_SCART) {
2147 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2148 ivideo->vbflags |= TV_PAL;
2150 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2151 if(ivideo->sisvga_engine == SIS_300_VGA) {
2152 inSISIDXREG(SISSR, 0x38, temp);
2153 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2154 else ivideo->vbflags |= TV_NTSC;
2155 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2156 inSISIDXREG(SISSR, 0x38, temp);
2157 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2158 else ivideo->vbflags |= TV_NTSC;
2159 } else {
2160 inSISIDXREG(SISCR, 0x79, temp);
2161 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2162 else ivideo->vbflags |= TV_NTSC;
2167 /* Copy forceCRT1 option to CRT1off if option is given */
2168 if(ivideo->sisfb_forcecrt1 != -1) {
2169 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2173 /* ------------------ Sensing routines ------------------ */
2175 static bool __devinit
2176 sisfb_test_DDC1(struct sis_video_info *ivideo)
2178 unsigned short old;
2179 int count = 48;
2181 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2182 do {
2183 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2184 } while(count--);
2185 return (count != -1);
2188 static void __devinit
2189 sisfb_sense_crt1(struct sis_video_info *ivideo)
2191 bool mustwait = false;
2192 u8 sr1F, cr17;
2193 #ifdef CONFIG_FB_SIS_315
2194 u8 cr63=0;
2195 #endif
2196 u16 temp = 0xffff;
2197 int i;
2199 inSISIDXREG(SISSR,0x1F,sr1F);
2200 orSISIDXREG(SISSR,0x1F,0x04);
2201 andSISIDXREG(SISSR,0x1F,0x3F);
2202 if(sr1F & 0xc0) mustwait = true;
2204 #ifdef CONFIG_FB_SIS_315
2205 if(ivideo->sisvga_engine == SIS_315_VGA) {
2206 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2207 cr63 &= 0x40;
2208 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2210 #endif
2212 inSISIDXREG(SISCR,0x17,cr17);
2213 cr17 &= 0x80;
2214 if(!cr17) {
2215 orSISIDXREG(SISCR,0x17,0x80);
2216 mustwait = true;
2217 outSISIDXREG(SISSR, 0x00, 0x01);
2218 outSISIDXREG(SISSR, 0x00, 0x03);
2221 if(mustwait) {
2222 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2225 #ifdef CONFIG_FB_SIS_315
2226 if(ivideo->chip >= SIS_330) {
2227 andSISIDXREG(SISCR,0x32,~0x20);
2228 if(ivideo->chip >= SIS_340) {
2229 outSISIDXREG(SISCR, 0x57, 0x4a);
2230 } else {
2231 outSISIDXREG(SISCR, 0x57, 0x5f);
2233 orSISIDXREG(SISCR, 0x53, 0x02);
2234 while((inSISREG(SISINPSTAT)) & 0x01) break;
2235 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2236 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2237 andSISIDXREG(SISCR, 0x53, 0xfd);
2238 andSISIDXREG(SISCR, 0x57, 0x00);
2240 #endif
2242 if(temp == 0xffff) {
2243 i = 3;
2244 do {
2245 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2246 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2247 } while(((temp == 0) || (temp == 0xffff)) && i--);
2249 if((temp == 0) || (temp == 0xffff)) {
2250 if(sisfb_test_DDC1(ivideo)) temp = 1;
2254 if((temp) && (temp != 0xffff)) {
2255 orSISIDXREG(SISCR,0x32,0x20);
2258 #ifdef CONFIG_FB_SIS_315
2259 if(ivideo->sisvga_engine == SIS_315_VGA) {
2260 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2262 #endif
2264 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2266 outSISIDXREG(SISSR,0x1F,sr1F);
2269 /* Determine and detect attached devices on SiS30x */
2270 static void __devinit
2271 SiS_SenseLCD(struct sis_video_info *ivideo)
2273 unsigned char buffer[256];
2274 unsigned short temp, realcrtno, i;
2275 u8 reg, cr37 = 0, paneltype = 0;
2276 u16 xres, yres;
2278 ivideo->SiS_Pr.PanelSelfDetected = false;
2280 /* LCD detection only for TMDS bridges */
2281 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2282 return;
2283 if(ivideo->vbflags2 & VB2_30xBDH)
2284 return;
2286 /* If LCD already set up by BIOS, skip it */
2287 inSISIDXREG(SISCR, 0x32, reg);
2288 if(reg & 0x08)
2289 return;
2291 realcrtno = 1;
2292 if(ivideo->SiS_Pr.DDCPortMixup)
2293 realcrtno = 0;
2295 /* Check DDC capabilities */
2296 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2297 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2299 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2300 return;
2302 /* Read DDC data */
2303 i = 3; /* Number of retrys */
2304 do {
2305 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2306 ivideo->sisvga_engine, realcrtno, 1,
2307 &buffer[0], ivideo->vbflags2);
2308 } while((temp) && i--);
2310 if(temp)
2311 return;
2313 /* No digital device */
2314 if(!(buffer[0x14] & 0x80))
2315 return;
2317 /* First detailed timing preferred timing? */
2318 if(!(buffer[0x18] & 0x02))
2319 return;
2321 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2322 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2324 switch(xres) {
2325 case 1024:
2326 if(yres == 768)
2327 paneltype = 0x02;
2328 break;
2329 case 1280:
2330 if(yres == 1024)
2331 paneltype = 0x03;
2332 break;
2333 case 1600:
2334 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2335 paneltype = 0x0b;
2336 break;
2339 if(!paneltype)
2340 return;
2342 if(buffer[0x23])
2343 cr37 |= 0x10;
2345 if((buffer[0x47] & 0x18) == 0x18)
2346 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2347 else
2348 cr37 |= 0xc0;
2350 outSISIDXREG(SISCR, 0x36, paneltype);
2351 cr37 &= 0xf1;
2352 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2353 orSISIDXREG(SISCR, 0x32, 0x08);
2355 ivideo->SiS_Pr.PanelSelfDetected = true;
2358 static int __devinit
2359 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2361 int temp, mytest, result, i, j;
2363 for(j = 0; j < 10; j++) {
2364 result = 0;
2365 for(i = 0; i < 3; i++) {
2366 mytest = test;
2367 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2368 temp = (type >> 8) | (mytest & 0x00ff);
2369 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2370 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2371 mytest >>= 8;
2372 mytest &= 0x7f;
2373 inSISIDXREG(SISPART4,0x03,temp);
2374 temp ^= 0x0e;
2375 temp &= mytest;
2376 if(temp == mytest) result++;
2377 #if 1
2378 outSISIDXREG(SISPART4,0x11,0x00);
2379 andSISIDXREG(SISPART4,0x10,0xe0);
2380 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2381 #endif
2383 if((result == 0) || (result >= 2)) break;
2385 return result;
2388 static void __devinit
2389 SiS_Sense30x(struct sis_video_info *ivideo)
2391 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2392 u16 svhs=0, svhs_c=0;
2393 u16 cvbs=0, cvbs_c=0;
2394 u16 vga2=0, vga2_c=0;
2395 int myflag, result;
2396 char stdstr[] = "sisfb: Detected";
2397 char tvstr[] = "TV connected to";
2399 if(ivideo->vbflags2 & VB2_301) {
2400 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2401 inSISIDXREG(SISPART4,0x01,myflag);
2402 if(myflag & 0x04) {
2403 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2405 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2406 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2407 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2408 svhs = 0x0200; cvbs = 0x0100;
2409 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2410 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2411 } else
2412 return;
2414 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2415 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2416 svhs_c = 0x0408; cvbs_c = 0x0808;
2419 biosflag = 2;
2420 if(ivideo->haveXGIROM) {
2421 biosflag = ivideo->bios_abase[0x58] & 0x03;
2422 } else if(ivideo->newrom) {
2423 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2424 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2425 if(ivideo->bios_abase) {
2426 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2430 if(ivideo->chip == SIS_300) {
2431 inSISIDXREG(SISSR,0x3b,myflag);
2432 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2435 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2436 vga2 = vga2_c = 0;
2439 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2440 orSISIDXREG(SISSR,0x1e,0x20);
2442 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2443 if(ivideo->vbflags2 & VB2_30xC) {
2444 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2445 } else {
2446 orSISIDXREG(SISPART4,0x0d,0x04);
2448 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2450 inSISIDXREG(SISPART2,0x00,backupP2_00);
2451 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2453 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2454 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2455 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2458 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2459 SISDoSense(ivideo, 0, 0);
2462 andSISIDXREG(SISCR, 0x32, ~0x14);
2464 if(vga2_c || vga2) {
2465 if(SISDoSense(ivideo, vga2, vga2_c)) {
2466 if(biosflag & 0x01) {
2467 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2468 orSISIDXREG(SISCR, 0x32, 0x04);
2469 } else {
2470 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2471 orSISIDXREG(SISCR, 0x32, 0x10);
2476 andSISIDXREG(SISCR, 0x32, 0x3f);
2478 if(ivideo->vbflags2 & VB2_30xCLV) {
2479 orSISIDXREG(SISPART4,0x0d,0x04);
2482 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2483 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2484 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2485 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2486 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2487 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2488 orSISIDXREG(SISCR,0x32,0x80);
2491 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2494 andSISIDXREG(SISCR, 0x32, ~0x03);
2496 if(!(ivideo->vbflags & TV_YPBPR)) {
2497 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2498 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2499 orSISIDXREG(SISCR, 0x32, 0x02);
2501 if((biosflag & 0x02) || (!result)) {
2502 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2503 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2504 orSISIDXREG(SISCR, 0x32, 0x01);
2509 SISDoSense(ivideo, 0, 0);
2511 outSISIDXREG(SISPART2,0x00,backupP2_00);
2512 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2513 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2515 if(ivideo->vbflags2 & VB2_30xCLV) {
2516 inSISIDXREG(SISPART2,0x00,biosflag);
2517 if(biosflag & 0x20) {
2518 for(myflag = 2; myflag > 0; myflag--) {
2519 biosflag ^= 0x20;
2520 outSISIDXREG(SISPART2,0x00,biosflag);
2525 outSISIDXREG(SISPART2,0x00,backupP2_00);
2528 /* Determine and detect attached TV's on Chrontel */
2529 static void __devinit
2530 SiS_SenseCh(struct sis_video_info *ivideo)
2532 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2533 u8 temp1, temp2;
2534 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2535 #endif
2536 #ifdef CONFIG_FB_SIS_300
2537 unsigned char test[3];
2538 int i;
2539 #endif
2541 if(ivideo->chip < SIS_315H) {
2543 #ifdef CONFIG_FB_SIS_300
2544 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2545 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2546 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2547 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2548 /* See Chrontel TB31 for explanation */
2549 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2550 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2551 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2552 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2554 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2555 if(temp2 != temp1) temp1 = temp2;
2557 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2558 /* Read power status */
2559 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2560 if((temp1 & 0x03) != 0x03) {
2561 /* Power all outputs */
2562 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2563 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2565 /* Sense connected TV devices */
2566 for(i = 0; i < 3; i++) {
2567 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2568 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2569 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2570 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2571 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2572 if(!(temp1 & 0x08)) test[i] = 0x02;
2573 else if(!(temp1 & 0x02)) test[i] = 0x01;
2574 else test[i] = 0;
2575 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2578 if(test[0] == test[1]) temp1 = test[0];
2579 else if(test[0] == test[2]) temp1 = test[0];
2580 else if(test[1] == test[2]) temp1 = test[1];
2581 else {
2582 printk(KERN_INFO
2583 "sisfb: TV detection unreliable - test results varied\n");
2584 temp1 = test[2];
2586 if(temp1 == 0x02) {
2587 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2588 ivideo->vbflags |= TV_SVIDEO;
2589 orSISIDXREG(SISCR, 0x32, 0x02);
2590 andSISIDXREG(SISCR, 0x32, ~0x05);
2591 } else if (temp1 == 0x01) {
2592 printk(KERN_INFO "%s CVBS output\n", stdstr);
2593 ivideo->vbflags |= TV_AVIDEO;
2594 orSISIDXREG(SISCR, 0x32, 0x01);
2595 andSISIDXREG(SISCR, 0x32, ~0x06);
2596 } else {
2597 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2598 andSISIDXREG(SISCR, 0x32, ~0x07);
2600 } else if(temp1 == 0) {
2601 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2602 andSISIDXREG(SISCR, 0x32, ~0x07);
2604 /* Set general purpose IO for Chrontel communication */
2605 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2606 #endif
2608 } else {
2610 #ifdef CONFIG_FB_SIS_315
2611 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2612 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2613 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2614 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2615 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2616 temp2 |= 0x01;
2617 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2618 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2619 temp2 ^= 0x01;
2620 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2621 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2622 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2623 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2624 temp1 = 0;
2625 if(temp2 & 0x02) temp1 |= 0x01;
2626 if(temp2 & 0x10) temp1 |= 0x01;
2627 if(temp2 & 0x04) temp1 |= 0x02;
2628 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2629 switch(temp1) {
2630 case 0x01:
2631 printk(KERN_INFO "%s CVBS output\n", stdstr);
2632 ivideo->vbflags |= TV_AVIDEO;
2633 orSISIDXREG(SISCR, 0x32, 0x01);
2634 andSISIDXREG(SISCR, 0x32, ~0x06);
2635 break;
2636 case 0x02:
2637 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2638 ivideo->vbflags |= TV_SVIDEO;
2639 orSISIDXREG(SISCR, 0x32, 0x02);
2640 andSISIDXREG(SISCR, 0x32, ~0x05);
2641 break;
2642 case 0x04:
2643 printk(KERN_INFO "%s SCART output\n", stdstr);
2644 orSISIDXREG(SISCR, 0x32, 0x04);
2645 andSISIDXREG(SISCR, 0x32, ~0x03);
2646 break;
2647 default:
2648 andSISIDXREG(SISCR, 0x32, ~0x07);
2650 #endif
2654 static void __devinit
2655 sisfb_get_VB_type(struct sis_video_info *ivideo)
2657 char stdstr[] = "sisfb: Detected";
2658 char bridgestr[] = "video bridge";
2659 u8 vb_chipid;
2660 u8 reg;
2662 /* No CRT2 on XGI Z7 */
2663 if(ivideo->chip == XGI_20)
2664 return;
2666 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2667 switch(vb_chipid) {
2668 case 0x01:
2669 inSISIDXREG(SISPART4, 0x01, reg);
2670 if(reg < 0xb0) {
2671 ivideo->vbflags |= VB_301; /* Deprecated */
2672 ivideo->vbflags2 |= VB2_301;
2673 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2674 } else if(reg < 0xc0) {
2675 ivideo->vbflags |= VB_301B; /* Deprecated */
2676 ivideo->vbflags2 |= VB2_301B;
2677 inSISIDXREG(SISPART4,0x23,reg);
2678 if(!(reg & 0x02)) {
2679 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2680 ivideo->vbflags2 |= VB2_30xBDH;
2681 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2682 } else {
2683 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2685 } else if(reg < 0xd0) {
2686 ivideo->vbflags |= VB_301C; /* Deprecated */
2687 ivideo->vbflags2 |= VB2_301C;
2688 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2689 } else if(reg < 0xe0) {
2690 ivideo->vbflags |= VB_301LV; /* Deprecated */
2691 ivideo->vbflags2 |= VB2_301LV;
2692 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2693 } else if(reg <= 0xe1) {
2694 inSISIDXREG(SISPART4,0x39,reg);
2695 if(reg == 0xff) {
2696 ivideo->vbflags |= VB_302LV; /* Deprecated */
2697 ivideo->vbflags2 |= VB2_302LV;
2698 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2699 } else {
2700 ivideo->vbflags |= VB_301C; /* Deprecated */
2701 ivideo->vbflags2 |= VB2_301C;
2702 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2703 #if 0
2704 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2705 ivideo->vbflags2 |= VB2_302ELV;
2706 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2707 #endif
2710 break;
2711 case 0x02:
2712 ivideo->vbflags |= VB_302B; /* Deprecated */
2713 ivideo->vbflags2 |= VB2_302B;
2714 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2715 break;
2718 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2719 inSISIDXREG(SISCR, 0x37, reg);
2720 reg &= SIS_EXTERNAL_CHIP_MASK;
2721 reg >>= 1;
2722 if(ivideo->sisvga_engine == SIS_300_VGA) {
2723 #ifdef CONFIG_FB_SIS_300
2724 switch(reg) {
2725 case SIS_EXTERNAL_CHIP_LVDS:
2726 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2727 ivideo->vbflags2 |= VB2_LVDS;
2728 break;
2729 case SIS_EXTERNAL_CHIP_TRUMPION:
2730 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2731 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2732 break;
2733 case SIS_EXTERNAL_CHIP_CHRONTEL:
2734 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2735 ivideo->vbflags2 |= VB2_CHRONTEL;
2736 break;
2737 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2738 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2739 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2740 break;
2742 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2743 #endif
2744 } else if(ivideo->chip < SIS_661) {
2745 #ifdef CONFIG_FB_SIS_315
2746 switch (reg) {
2747 case SIS310_EXTERNAL_CHIP_LVDS:
2748 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2749 ivideo->vbflags2 |= VB2_LVDS;
2750 break;
2751 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2752 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2753 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2754 break;
2756 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2757 #endif
2758 } else if(ivideo->chip >= SIS_661) {
2759 #ifdef CONFIG_FB_SIS_315
2760 inSISIDXREG(SISCR, 0x38, reg);
2761 reg >>= 5;
2762 switch(reg) {
2763 case 0x02:
2764 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2765 ivideo->vbflags2 |= VB2_LVDS;
2766 break;
2767 case 0x03:
2768 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2769 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2770 break;
2771 case 0x04:
2772 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2773 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2774 break;
2776 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2777 #endif
2779 if(ivideo->vbflags2 & VB2_LVDS) {
2780 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2782 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2783 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2785 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2786 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2788 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2789 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2793 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2794 SiS_SenseLCD(ivideo);
2795 SiS_Sense30x(ivideo);
2796 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2797 SiS_SenseCh(ivideo);
2801 /* ---------- Engine initialization routines ------------ */
2803 static void
2804 sisfb_engine_init(struct sis_video_info *ivideo)
2807 /* Initialize command queue (we use MMIO only) */
2809 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2811 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2812 MMIO_CMD_QUEUE_CAP |
2813 VM_CMD_QUEUE_CAP |
2814 AGP_CMD_QUEUE_CAP);
2816 #ifdef CONFIG_FB_SIS_300
2817 if(ivideo->sisvga_engine == SIS_300_VGA) {
2818 u32 tqueue_pos;
2819 u8 tq_state;
2821 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2823 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2824 tq_state |= 0xf0;
2825 tq_state &= 0xfc;
2826 tq_state |= (u8)(tqueue_pos >> 8);
2827 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2829 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2831 ivideo->caps |= TURBO_QUEUE_CAP;
2833 #endif
2835 #ifdef CONFIG_FB_SIS_315
2836 if(ivideo->sisvga_engine == SIS_315_VGA) {
2837 u32 tempq = 0, templ;
2838 u8 temp;
2840 if(ivideo->chip == XGI_20) {
2841 switch(ivideo->cmdQueueSize) {
2842 case (64 * 1024):
2843 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2844 break;
2845 case (128 * 1024):
2846 default:
2847 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2849 } else {
2850 switch(ivideo->cmdQueueSize) {
2851 case (4 * 1024 * 1024):
2852 temp = SIS_CMD_QUEUE_SIZE_4M;
2853 break;
2854 case (2 * 1024 * 1024):
2855 temp = SIS_CMD_QUEUE_SIZE_2M;
2856 break;
2857 case (1 * 1024 * 1024):
2858 temp = SIS_CMD_QUEUE_SIZE_1M;
2859 break;
2860 default:
2861 case (512 * 1024):
2862 temp = SIS_CMD_QUEUE_SIZE_512k;
2866 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2867 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2869 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2870 /* Must disable dual pipe on XGI_40. Can't do
2871 * this in MMIO mode, because it requires
2872 * setting/clearing a bit in the MMIO fire trigger
2873 * register.
2875 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2877 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2879 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2881 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2882 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2884 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2885 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2887 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2888 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2889 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2890 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2892 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2894 sisfb_syncaccel(ivideo);
2896 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2901 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2902 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2904 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2905 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2907 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2908 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2910 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2912 #endif
2914 ivideo->engineok = 1;
2917 static void __devinit
2918 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2920 u8 reg;
2921 int i;
2923 inSISIDXREG(SISCR, 0x36, reg);
2924 reg &= 0x0f;
2925 if(ivideo->sisvga_engine == SIS_300_VGA) {
2926 ivideo->CRT2LCDType = sis300paneltype[reg];
2927 } else if(ivideo->chip >= SIS_661) {
2928 ivideo->CRT2LCDType = sis661paneltype[reg];
2929 } else {
2930 ivideo->CRT2LCDType = sis310paneltype[reg];
2931 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2932 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2933 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2934 ivideo->CRT2LCDType = LCD_320x240;
2939 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2940 /* For broken BIOSes: Assume 1024x768, RGB18 */
2941 ivideo->CRT2LCDType = LCD_1024x768;
2942 setSISIDXREG(SISCR,0x36,0xf0,0x02);
2943 setSISIDXREG(SISCR,0x37,0xee,0x01);
2944 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2947 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2948 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2949 ivideo->lcdxres = sis_lcd_data[i].xres;
2950 ivideo->lcdyres = sis_lcd_data[i].yres;
2951 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2952 break;
2956 #ifdef CONFIG_FB_SIS_300
2957 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2958 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2959 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2960 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2961 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2962 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2963 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2964 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2965 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2967 #endif
2969 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2970 ivideo->lcdxres, ivideo->lcdyres);
2973 static void __devinit
2974 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2976 #ifdef CONFIG_FB_SIS_300
2977 /* Save the current PanelDelayCompensation if the LCD is currently used */
2978 if(ivideo->sisvga_engine == SIS_300_VGA) {
2979 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2980 int tmp;
2981 inSISIDXREG(SISCR,0x30,tmp);
2982 if(tmp & 0x20) {
2983 /* Currently on LCD? If yes, read current pdc */
2984 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2985 ivideo->detectedpdc &= 0x3c;
2986 if(ivideo->SiS_Pr.PDC == -1) {
2987 /* Let option override detection */
2988 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2990 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2991 ivideo->detectedpdc);
2993 if((ivideo->SiS_Pr.PDC != -1) &&
2994 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2995 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2996 ivideo->SiS_Pr.PDC);
3000 #endif
3002 #ifdef CONFIG_FB_SIS_315
3003 if(ivideo->sisvga_engine == SIS_315_VGA) {
3005 /* Try to find about LCDA */
3006 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3007 int tmp;
3008 inSISIDXREG(SISPART1,0x13,tmp);
3009 if(tmp & 0x04) {
3010 ivideo->SiS_Pr.SiS_UseLCDA = true;
3011 ivideo->detectedlcda = 0x03;
3015 /* Save PDC */
3016 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3017 int tmp;
3018 inSISIDXREG(SISCR,0x30,tmp);
3019 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3020 /* Currently on LCD? If yes, read current pdc */
3021 u8 pdc;
3022 inSISIDXREG(SISPART1,0x2D,pdc);
3023 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3024 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3025 inSISIDXREG(SISPART1,0x35,pdc);
3026 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3027 inSISIDXREG(SISPART1,0x20,pdc);
3028 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3029 if(ivideo->newrom) {
3030 /* New ROM invalidates other PDC resp. */
3031 if(ivideo->detectedlcda != 0xff) {
3032 ivideo->detectedpdc = 0xff;
3033 } else {
3034 ivideo->detectedpdca = 0xff;
3037 if(ivideo->SiS_Pr.PDC == -1) {
3038 if(ivideo->detectedpdc != 0xff) {
3039 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3042 if(ivideo->SiS_Pr.PDCA == -1) {
3043 if(ivideo->detectedpdca != 0xff) {
3044 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3047 if(ivideo->detectedpdc != 0xff) {
3048 printk(KERN_INFO
3049 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3050 ivideo->detectedpdc);
3052 if(ivideo->detectedpdca != 0xff) {
3053 printk(KERN_INFO
3054 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3055 ivideo->detectedpdca);
3059 /* Save EMI */
3060 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3061 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3062 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3063 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3064 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3065 ivideo->SiS_Pr.HaveEMI = true;
3066 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3067 ivideo->SiS_Pr.HaveEMILCD = true;
3072 /* Let user override detected PDCs (all bridges) */
3073 if(ivideo->vbflags2 & VB2_30xBLV) {
3074 if((ivideo->SiS_Pr.PDC != -1) &&
3075 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3076 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3077 ivideo->SiS_Pr.PDC);
3079 if((ivideo->SiS_Pr.PDCA != -1) &&
3080 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3081 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3082 ivideo->SiS_Pr.PDCA);
3087 #endif
3090 /* -------------------- Memory manager routines ---------------------- */
3092 static u32 __devinit
3093 sisfb_getheapstart(struct sis_video_info *ivideo)
3095 u32 ret = ivideo->sisfb_parm_mem * 1024;
3096 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3097 u32 def;
3099 /* Calculate heap start = end of memory for console
3101 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3102 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3104 * On 76x in UMA+LFB mode, the layout is as follows:
3105 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3106 * where the heap is the entire UMA area, eventually
3107 * into the LFB area if the given mem parameter is
3108 * higher than the size of the UMA memory.
3110 * Basically given by "mem" parameter
3112 * maximum = videosize - cmd_queue - hwcursor
3113 * (results in a heap of size 0)
3114 * default = SiS 300: depends on videosize
3115 * SiS 315/330/340/XGI: 32k below max
3118 if(ivideo->sisvga_engine == SIS_300_VGA) {
3119 if(ivideo->video_size > 0x1000000) {
3120 def = 0xc00000;
3121 } else if(ivideo->video_size > 0x800000) {
3122 def = 0x800000;
3123 } else {
3124 def = 0x400000;
3126 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3127 ret = def = 0;
3128 } else {
3129 def = maxoffs - 0x8000;
3132 /* Use default for secondary card for now (FIXME) */
3133 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3134 ret = def;
3136 return ret;
3139 static u32 __devinit
3140 sisfb_getheapsize(struct sis_video_info *ivideo)
3142 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3143 u32 ret = 0;
3145 if(ivideo->UMAsize && ivideo->LFBsize) {
3146 if( (!ivideo->sisfb_parm_mem) ||
3147 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3148 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3149 ret = ivideo->UMAsize;
3150 max -= ivideo->UMAsize;
3151 } else {
3152 ret = max - (ivideo->sisfb_parm_mem * 1024);
3153 max = ivideo->sisfb_parm_mem * 1024;
3155 ivideo->video_offset = ret;
3156 ivideo->sisfb_mem = max;
3157 } else {
3158 ret = max - ivideo->heapstart;
3159 ivideo->sisfb_mem = ivideo->heapstart;
3162 return ret;
3165 static int __devinit
3166 sisfb_heap_init(struct sis_video_info *ivideo)
3168 struct SIS_OH *poh;
3170 ivideo->video_offset = 0;
3171 if(ivideo->sisfb_parm_mem) {
3172 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3173 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3174 ivideo->sisfb_parm_mem = 0;
3178 ivideo->heapstart = sisfb_getheapstart(ivideo);
3179 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3181 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3182 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3184 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3185 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3187 ivideo->sisfb_heap.vinfo = ivideo;
3189 ivideo->sisfb_heap.poha_chain = NULL;
3190 ivideo->sisfb_heap.poh_freelist = NULL;
3192 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3193 if(poh == NULL)
3194 return 1;
3196 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3197 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3198 poh->size = ivideo->sisfb_heap_size;
3199 poh->offset = ivideo->heapstart;
3201 ivideo->sisfb_heap.oh_free.poh_next = poh;
3202 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3203 ivideo->sisfb_heap.oh_free.size = 0;
3204 ivideo->sisfb_heap.max_freesize = poh->size;
3206 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3207 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3208 ivideo->sisfb_heap.oh_used.size = SENTINEL;
3210 if(ivideo->cardnumber == 0) {
3211 /* For the first card, make this heap the "global" one
3212 * for old DRM (which could handle only one card)
3214 sisfb_heap = &ivideo->sisfb_heap;
3217 return 0;
3220 static struct SIS_OH *
3221 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3223 struct SIS_OHALLOC *poha;
3224 struct SIS_OH *poh;
3225 unsigned long cOhs;
3226 int i;
3228 if(memheap->poh_freelist == NULL) {
3229 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3230 if(!poha)
3231 return NULL;
3233 poha->poha_next = memheap->poha_chain;
3234 memheap->poha_chain = poha;
3236 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3238 poh = &poha->aoh[0];
3239 for(i = cOhs - 1; i != 0; i--) {
3240 poh->poh_next = poh + 1;
3241 poh = poh + 1;
3244 poh->poh_next = NULL;
3245 memheap->poh_freelist = &poha->aoh[0];
3248 poh = memheap->poh_freelist;
3249 memheap->poh_freelist = poh->poh_next;
3251 return poh;
3254 static struct SIS_OH *
3255 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3257 struct SIS_OH *pohThis;
3258 struct SIS_OH *pohRoot;
3259 int bAllocated = 0;
3261 if(size > memheap->max_freesize) {
3262 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3263 (unsigned int) size / 1024);
3264 return NULL;
3267 pohThis = memheap->oh_free.poh_next;
3269 while(pohThis != &memheap->oh_free) {
3270 if(size <= pohThis->size) {
3271 bAllocated = 1;
3272 break;
3274 pohThis = pohThis->poh_next;
3277 if(!bAllocated) {
3278 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3279 (unsigned int) size / 1024);
3280 return NULL;
3283 if(size == pohThis->size) {
3284 pohRoot = pohThis;
3285 sisfb_delete_node(pohThis);
3286 } else {
3287 pohRoot = sisfb_poh_new_node(memheap);
3288 if(pohRoot == NULL)
3289 return NULL;
3291 pohRoot->offset = pohThis->offset;
3292 pohRoot->size = size;
3294 pohThis->offset += size;
3295 pohThis->size -= size;
3298 memheap->max_freesize -= size;
3300 pohThis = &memheap->oh_used;
3301 sisfb_insert_node(pohThis, pohRoot);
3303 return pohRoot;
3306 static void
3307 sisfb_delete_node(struct SIS_OH *poh)
3309 poh->poh_prev->poh_next = poh->poh_next;
3310 poh->poh_next->poh_prev = poh->poh_prev;
3313 static void
3314 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3316 struct SIS_OH *pohTemp = pohList->poh_next;
3318 pohList->poh_next = poh;
3319 pohTemp->poh_prev = poh;
3321 poh->poh_prev = pohList;
3322 poh->poh_next = pohTemp;
3325 static struct SIS_OH *
3326 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3328 struct SIS_OH *pohThis;
3329 struct SIS_OH *poh_freed;
3330 struct SIS_OH *poh_prev;
3331 struct SIS_OH *poh_next;
3332 u32 ulUpper;
3333 u32 ulLower;
3334 int foundNode = 0;
3336 poh_freed = memheap->oh_used.poh_next;
3338 while(poh_freed != &memheap->oh_used) {
3339 if(poh_freed->offset == base) {
3340 foundNode = 1;
3341 break;
3344 poh_freed = poh_freed->poh_next;
3347 if(!foundNode)
3348 return NULL;
3350 memheap->max_freesize += poh_freed->size;
3352 poh_prev = poh_next = NULL;
3353 ulUpper = poh_freed->offset + poh_freed->size;
3354 ulLower = poh_freed->offset;
3356 pohThis = memheap->oh_free.poh_next;
3358 while(pohThis != &memheap->oh_free) {
3359 if(pohThis->offset == ulUpper) {
3360 poh_next = pohThis;
3361 } else if((pohThis->offset + pohThis->size) == ulLower) {
3362 poh_prev = pohThis;
3364 pohThis = pohThis->poh_next;
3367 sisfb_delete_node(poh_freed);
3369 if(poh_prev && poh_next) {
3370 poh_prev->size += (poh_freed->size + poh_next->size);
3371 sisfb_delete_node(poh_next);
3372 sisfb_free_node(memheap, poh_freed);
3373 sisfb_free_node(memheap, poh_next);
3374 return poh_prev;
3377 if(poh_prev) {
3378 poh_prev->size += poh_freed->size;
3379 sisfb_free_node(memheap, poh_freed);
3380 return poh_prev;
3383 if(poh_next) {
3384 poh_next->size += poh_freed->size;
3385 poh_next->offset = poh_freed->offset;
3386 sisfb_free_node(memheap, poh_freed);
3387 return poh_next;
3390 sisfb_insert_node(&memheap->oh_free, poh_freed);
3392 return poh_freed;
3395 static void
3396 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3398 if(poh == NULL)
3399 return;
3401 poh->poh_next = memheap->poh_freelist;
3402 memheap->poh_freelist = poh;
3405 static void
3406 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3408 struct SIS_OH *poh = NULL;
3410 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3411 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3413 if(poh == NULL) {
3414 req->offset = req->size = 0;
3415 DPRINTK("sisfb: Video RAM allocation failed\n");
3416 } else {
3417 req->offset = poh->offset;
3418 req->size = poh->size;
3419 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3420 (poh->offset + ivideo->video_vbase));
3424 void
3425 sis_malloc(struct sis_memreq *req)
3427 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3429 if(&ivideo->sisfb_heap == sisfb_heap)
3430 sis_int_malloc(ivideo, req);
3431 else
3432 req->offset = req->size = 0;
3435 void
3436 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3438 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3440 sis_int_malloc(ivideo, req);
3443 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3445 static void
3446 sis_int_free(struct sis_video_info *ivideo, u32 base)
3448 struct SIS_OH *poh;
3450 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3451 return;
3453 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3455 if(poh == NULL) {
3456 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3457 (unsigned int) base);
3461 void
3462 sis_free(u32 base)
3464 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3466 sis_int_free(ivideo, base);
3469 void
3470 sis_free_new(struct pci_dev *pdev, u32 base)
3472 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3474 sis_int_free(ivideo, base);
3477 /* --------------------- SetMode routines ------------------------- */
3479 static void
3480 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3482 u8 cr30, cr31;
3484 /* Check if MMIO and engines are enabled,
3485 * and sync in case they are. Can't use
3486 * ivideo->accel here, as this might have
3487 * been changed before this is called.
3489 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3490 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3491 /* MMIO and 2D/3D engine enabled? */
3492 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3493 #ifdef CONFIG_FB_SIS_300
3494 if(ivideo->sisvga_engine == SIS_300_VGA) {
3495 /* Don't care about TurboQueue. It's
3496 * enough to know that the engines
3497 * are enabled
3499 sisfb_syncaccel(ivideo);
3501 #endif
3502 #ifdef CONFIG_FB_SIS_315
3503 if(ivideo->sisvga_engine == SIS_315_VGA) {
3504 /* Check that any queue mode is
3505 * enabled, and that the queue
3506 * is not in the state of "reset"
3508 inSISIDXREG(SISSR, 0x26, cr30);
3509 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3510 sisfb_syncaccel(ivideo);
3513 #endif
3517 static void
3518 sisfb_pre_setmode(struct sis_video_info *ivideo)
3520 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3521 int tvregnum = 0;
3523 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3525 outSISIDXREG(SISSR, 0x05, 0x86);
3527 inSISIDXREG(SISCR, 0x31, cr31);
3528 cr31 &= ~0x60;
3529 cr31 |= 0x04;
3531 cr33 = ivideo->rate_idx & 0x0F;
3533 #ifdef CONFIG_FB_SIS_315
3534 if(ivideo->sisvga_engine == SIS_315_VGA) {
3535 if(ivideo->chip >= SIS_661) {
3536 inSISIDXREG(SISCR, 0x38, cr38);
3537 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3538 } else {
3539 tvregnum = 0x38;
3540 inSISIDXREG(SISCR, tvregnum, cr38);
3541 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3544 #endif
3545 #ifdef CONFIG_FB_SIS_300
3546 if(ivideo->sisvga_engine == SIS_300_VGA) {
3547 tvregnum = 0x35;
3548 inSISIDXREG(SISCR, tvregnum, cr38);
3550 #endif
3552 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3553 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
3554 ivideo->curFSTN = ivideo->curDSTN = 0;
3556 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3558 case CRT2_TV:
3559 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3560 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3561 #ifdef CONFIG_FB_SIS_315
3562 if(ivideo->chip >= SIS_661) {
3563 cr38 |= 0x04;
3564 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3565 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3566 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3567 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3568 cr35 &= ~0x01;
3569 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3570 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3571 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3572 cr38 |= 0x08;
3573 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3574 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3575 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3576 cr31 &= ~0x01;
3577 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3579 #endif
3580 } else if((ivideo->vbflags & TV_HIVISION) &&
3581 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3582 if(ivideo->chip >= SIS_661) {
3583 cr38 |= 0x04;
3584 cr35 |= 0x60;
3585 } else {
3586 cr30 |= 0x80;
3588 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3589 cr31 |= 0x01;
3590 cr35 |= 0x01;
3591 ivideo->currentvbflags |= TV_HIVISION;
3592 } else if(ivideo->vbflags & TV_SCART) {
3593 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3594 cr31 |= 0x01;
3595 cr35 |= 0x01;
3596 ivideo->currentvbflags |= TV_SCART;
3597 } else {
3598 if(ivideo->vbflags & TV_SVIDEO) {
3599 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3600 ivideo->currentvbflags |= TV_SVIDEO;
3602 if(ivideo->vbflags & TV_AVIDEO) {
3603 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3604 ivideo->currentvbflags |= TV_AVIDEO;
3607 cr31 |= SIS_DRIVER_MODE;
3609 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3610 if(ivideo->vbflags & TV_PAL) {
3611 cr31 |= 0x01; cr35 |= 0x01;
3612 ivideo->currentvbflags |= TV_PAL;
3613 if(ivideo->vbflags & TV_PALM) {
3614 cr38 |= 0x40; cr35 |= 0x04;
3615 ivideo->currentvbflags |= TV_PALM;
3616 } else if(ivideo->vbflags & TV_PALN) {
3617 cr38 |= 0x80; cr35 |= 0x08;
3618 ivideo->currentvbflags |= TV_PALN;
3620 } else {
3621 cr31 &= ~0x01; cr35 &= ~0x01;
3622 ivideo->currentvbflags |= TV_NTSC;
3623 if(ivideo->vbflags & TV_NTSCJ) {
3624 cr38 |= 0x40; cr35 |= 0x02;
3625 ivideo->currentvbflags |= TV_NTSCJ;
3629 break;
3631 case CRT2_LCD:
3632 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3633 cr31 |= SIS_DRIVER_MODE;
3634 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3635 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3636 ivideo->curFSTN = ivideo->sisfb_fstn;
3637 ivideo->curDSTN = ivideo->sisfb_dstn;
3638 break;
3640 case CRT2_VGA:
3641 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3642 cr31 |= SIS_DRIVER_MODE;
3643 if(ivideo->sisfb_nocrt2rate) {
3644 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3645 } else {
3646 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3648 break;
3650 default: /* disable CRT2 */
3651 cr30 = 0x00;
3652 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3655 outSISIDXREG(SISCR, 0x30, cr30);
3656 outSISIDXREG(SISCR, 0x33, cr33);
3658 if(ivideo->chip >= SIS_661) {
3659 #ifdef CONFIG_FB_SIS_315
3660 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3661 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3662 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3663 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3664 #endif
3665 } else if(ivideo->chip != SIS_300) {
3666 outSISIDXREG(SISCR, tvregnum, cr38);
3668 outSISIDXREG(SISCR, 0x31, cr31);
3670 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3672 sisfb_check_engine_and_sync(ivideo);
3675 /* Fix SR11 for 661 and later */
3676 #ifdef CONFIG_FB_SIS_315
3677 static void
3678 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3680 u8 tmpreg;
3682 if(ivideo->chip >= SIS_661) {
3683 inSISIDXREG(SISSR,0x11,tmpreg);
3684 if(tmpreg & 0x20) {
3685 inSISIDXREG(SISSR,0x3e,tmpreg);
3686 tmpreg = (tmpreg + 1) & 0xff;
3687 outSISIDXREG(SISSR,0x3e,tmpreg);
3688 inSISIDXREG(SISSR,0x11,tmpreg);
3690 if(tmpreg & 0xf0) {
3691 andSISIDXREG(SISSR,0x11,0x0f);
3695 #endif
3697 static void
3698 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3700 if(val > 32) val = 32;
3701 if(val < -32) val = -32;
3702 ivideo->tvxpos = val;
3704 if(ivideo->sisfblocked) return;
3705 if(!ivideo->modechanged) return;
3707 if(ivideo->currentvbflags & CRT2_TV) {
3709 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3711 int x = ivideo->tvx;
3713 switch(ivideo->chronteltype) {
3714 case 1:
3715 x += val;
3716 if(x < 0) x = 0;
3717 outSISIDXREG(SISSR,0x05,0x86);
3718 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3719 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3720 break;
3721 case 2:
3722 /* Not supported by hardware */
3723 break;
3726 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3728 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3729 unsigned short temp;
3731 p2_1f = ivideo->p2_1f;
3732 p2_20 = ivideo->p2_20;
3733 p2_2b = ivideo->p2_2b;
3734 p2_42 = ivideo->p2_42;
3735 p2_43 = ivideo->p2_43;
3737 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3738 temp += (val * 2);
3739 p2_1f = temp & 0xff;
3740 p2_20 = (temp & 0xf00) >> 4;
3741 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3742 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3743 temp += (val * 2);
3744 p2_43 = temp & 0xff;
3745 p2_42 = (temp & 0xf00) >> 4;
3746 outSISIDXREG(SISPART2,0x1f,p2_1f);
3747 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3748 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3749 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3750 outSISIDXREG(SISPART2,0x43,p2_43);
3755 static void
3756 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3758 if(val > 32) val = 32;
3759 if(val < -32) val = -32;
3760 ivideo->tvypos = val;
3762 if(ivideo->sisfblocked) return;
3763 if(!ivideo->modechanged) return;
3765 if(ivideo->currentvbflags & CRT2_TV) {
3767 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3769 int y = ivideo->tvy;
3771 switch(ivideo->chronteltype) {
3772 case 1:
3773 y -= val;
3774 if(y < 0) y = 0;
3775 outSISIDXREG(SISSR,0x05,0x86);
3776 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3777 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3778 break;
3779 case 2:
3780 /* Not supported by hardware */
3781 break;
3784 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3786 char p2_01, p2_02;
3787 val /= 2;
3788 p2_01 = ivideo->p2_01;
3789 p2_02 = ivideo->p2_02;
3791 p2_01 += val;
3792 p2_02 += val;
3793 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3794 while((p2_01 <= 0) || (p2_02 <= 0)) {
3795 p2_01 += 2;
3796 p2_02 += 2;
3799 outSISIDXREG(SISPART2,0x01,p2_01);
3800 outSISIDXREG(SISPART2,0x02,p2_02);
3805 static void
3806 sisfb_post_setmode(struct sis_video_info *ivideo)
3808 bool crt1isoff = false;
3809 bool doit = true;
3810 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3811 u8 reg;
3812 #endif
3813 #ifdef CONFIG_FB_SIS_315
3814 u8 reg1;
3815 #endif
3817 outSISIDXREG(SISSR, 0x05, 0x86);
3819 #ifdef CONFIG_FB_SIS_315
3820 sisfb_fixup_SR11(ivideo);
3821 #endif
3823 /* Now we actually HAVE changed the display mode */
3824 ivideo->modechanged = 1;
3826 /* We can't switch off CRT1 if bridge is in slave mode */
3827 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3828 if(sisfb_bridgeisslave(ivideo)) doit = false;
3829 } else
3830 ivideo->sisfb_crt1off = 0;
3832 #ifdef CONFIG_FB_SIS_300
3833 if(ivideo->sisvga_engine == SIS_300_VGA) {
3834 if((ivideo->sisfb_crt1off) && (doit)) {
3835 crt1isoff = true;
3836 reg = 0x00;
3837 } else {
3838 crt1isoff = false;
3839 reg = 0x80;
3841 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3843 #endif
3844 #ifdef CONFIG_FB_SIS_315
3845 if(ivideo->sisvga_engine == SIS_315_VGA) {
3846 if((ivideo->sisfb_crt1off) && (doit)) {
3847 crt1isoff = true;
3848 reg = 0x40;
3849 reg1 = 0xc0;
3850 } else {
3851 crt1isoff = false;
3852 reg = 0x00;
3853 reg1 = 0x00;
3855 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3856 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3858 #endif
3860 if(crt1isoff) {
3861 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3862 ivideo->currentvbflags |= VB_SINGLE_MODE;
3863 } else {
3864 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3865 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3866 ivideo->currentvbflags |= VB_MIRROR_MODE;
3867 } else {
3868 ivideo->currentvbflags |= VB_SINGLE_MODE;
3872 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3874 if(ivideo->currentvbflags & CRT2_TV) {
3875 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3876 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3877 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3878 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3879 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3880 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3881 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3882 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3883 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3884 if(ivideo->chronteltype == 1) {
3885 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3886 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3887 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3888 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3893 if(ivideo->tvxpos) {
3894 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3896 if(ivideo->tvypos) {
3897 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3900 /* Eventually sync engines */
3901 sisfb_check_engine_and_sync(ivideo);
3903 /* (Re-)Initialize chip engines */
3904 if(ivideo->accel) {
3905 sisfb_engine_init(ivideo);
3906 } else {
3907 ivideo->engineok = 0;
3911 static int
3912 sisfb_reset_mode(struct sis_video_info *ivideo)
3914 if(sisfb_set_mode(ivideo, 0))
3915 return 1;
3917 sisfb_set_pitch(ivideo);
3918 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3919 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3921 return 0;
3924 static void
3925 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3927 int mycrt1off;
3929 switch(sisfb_command->sisfb_cmd) {
3930 case SISFB_CMD_GETVBFLAGS:
3931 if(!ivideo->modechanged) {
3932 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3933 } else {
3934 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3935 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3936 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
3938 break;
3939 case SISFB_CMD_SWITCHCRT1:
3940 /* arg[0]: 0 = off, 1 = on, 99 = query */
3941 if(!ivideo->modechanged) {
3942 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3943 } else if(sisfb_command->sisfb_arg[0] == 99) {
3944 /* Query */
3945 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3946 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3947 } else if(ivideo->sisfblocked) {
3948 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3949 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3950 (sisfb_command->sisfb_arg[0] == 0)) {
3951 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3952 } else {
3953 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3954 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3955 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3956 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3957 ivideo->sisfb_crt1off = mycrt1off;
3958 if(sisfb_reset_mode(ivideo)) {
3959 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
3962 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3964 break;
3965 /* more to come */
3966 default:
3967 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3968 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3969 sisfb_command->sisfb_cmd);
3973 #ifndef MODULE
3974 static int __init sisfb_setup(char *options)
3976 char *this_opt;
3978 sisfb_setdefaultparms();
3980 if(!options || !(*options))
3981 return 0;
3983 while((this_opt = strsep(&options, ",")) != NULL) {
3985 if(!(*this_opt)) continue;
3987 if(!strnicmp(this_opt, "off", 3)) {
3988 sisfb_off = 1;
3989 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3990 /* Need to check crt2 type first for fstn/dstn */
3991 sisfb_search_crt2type(this_opt + 14);
3992 } else if(!strnicmp(this_opt, "tvmode:",7)) {
3993 sisfb_search_tvstd(this_opt + 7);
3994 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3995 sisfb_search_tvstd(this_opt + 11);
3996 } else if(!strnicmp(this_opt, "mode:", 5)) {
3997 sisfb_search_mode(this_opt + 5, false);
3998 } else if(!strnicmp(this_opt, "vesa:", 5)) {
3999 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
4000 } else if(!strnicmp(this_opt, "rate:", 5)) {
4001 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4002 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4003 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4004 } else if(!strnicmp(this_opt, "mem:",4)) {
4005 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4006 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4007 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4008 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4009 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4010 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4011 sisfb_accel = 0;
4012 } else if(!strnicmp(this_opt, "accel", 5)) {
4013 sisfb_accel = -1;
4014 } else if(!strnicmp(this_opt, "noypan", 6)) {
4015 sisfb_ypan = 0;
4016 } else if(!strnicmp(this_opt, "ypan", 4)) {
4017 sisfb_ypan = -1;
4018 } else if(!strnicmp(this_opt, "nomax", 5)) {
4019 sisfb_max = 0;
4020 } else if(!strnicmp(this_opt, "max", 3)) {
4021 sisfb_max = -1;
4022 } else if(!strnicmp(this_opt, "userom:", 7)) {
4023 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4024 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4025 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4026 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4027 sisfb_nocrt2rate = 1;
4028 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4029 unsigned long temp = 2;
4030 temp = simple_strtoul(this_opt + 9, NULL, 0);
4031 if((temp == 0) || (temp == 1)) {
4032 sisfb_scalelcd = temp ^ 1;
4034 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4035 int temp = 0;
4036 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4037 if((temp >= -32) && (temp <= 32)) {
4038 sisfb_tvxposoffset = temp;
4040 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4041 int temp = 0;
4042 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4043 if((temp >= -32) && (temp <= 32)) {
4044 sisfb_tvyposoffset = temp;
4046 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4047 sisfb_search_specialtiming(this_opt + 14);
4048 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4049 int temp = 4;
4050 temp = simple_strtoul(this_opt + 7, NULL, 0);
4051 if((temp >= 0) && (temp <= 3)) {
4052 sisfb_lvdshl = temp;
4054 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4055 sisfb_search_mode(this_opt, true);
4056 #if !defined(__i386__) && !defined(__x86_64__)
4057 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4058 sisfb_resetcard = 1;
4059 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4060 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4061 #endif
4062 } else {
4063 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4068 return 0;
4070 #endif
4072 static int __devinit
4073 sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
4075 void __iomem *rom;
4076 int romptr;
4078 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4079 return 0;
4081 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4082 if(romptr > (0x10000 - 8))
4083 return 0;
4085 rom = rom_base + romptr;
4087 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4088 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4089 return 0;
4091 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4092 return 0;
4094 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4095 return 0;
4097 return 1;
4100 static unsigned char * __devinit
4101 sisfb_find_rom(struct pci_dev *pdev)
4103 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4104 void __iomem *rom_base;
4105 unsigned char *myrombase = NULL;
4106 u32 temp;
4107 size_t romsize;
4109 /* First, try the official pci ROM functions (except
4110 * on integrated chipsets which have no ROM).
4113 if(!ivideo->nbridge) {
4115 if((rom_base = pci_map_rom(pdev, &romsize))) {
4117 if(sisfb_check_rom(rom_base, ivideo)) {
4119 if((myrombase = vmalloc(65536))) {
4121 /* Work around bug in pci/rom.c: Folks forgot to check
4122 * whether the size retrieved from the BIOS image eventually
4123 * is larger than the mapped size
4125 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4126 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4128 memcpy_fromio(myrombase, rom_base,
4129 (romsize > 65536) ? 65536 : romsize);
4132 pci_unmap_rom(pdev, rom_base);
4136 if(myrombase) return myrombase;
4138 /* Otherwise do it the conventional way. */
4140 #if defined(__i386__) || defined(__x86_64__)
4142 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4144 rom_base = ioremap(temp, 65536);
4145 if(!rom_base)
4146 continue;
4148 if(!sisfb_check_rom(rom_base, ivideo)) {
4149 iounmap(rom_base);
4150 continue;
4153 if((myrombase = vmalloc(65536)))
4154 memcpy_fromio(myrombase, rom_base, 65536);
4156 iounmap(rom_base);
4157 break;
4161 #else
4163 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4164 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4165 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4167 rom_base = ioremap(ivideo->video_base, 65536);
4168 if(rom_base) {
4169 if(sisfb_check_rom(rom_base, ivideo)) {
4170 if((myrombase = vmalloc(65536)))
4171 memcpy_fromio(myrombase, rom_base, 65536);
4173 iounmap(rom_base);
4176 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4178 #endif
4180 return myrombase;
4183 static void __devinit
4184 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4185 unsigned int min)
4187 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4189 if(!ivideo->video_vbase) {
4190 printk(KERN_ERR
4191 "sisfb: Unable to map maximum video RAM for size detection\n");
4192 (*mapsize) >>= 1;
4193 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4194 (*mapsize) >>= 1;
4195 if((*mapsize) < (min << 20))
4196 break;
4198 if(ivideo->video_vbase) {
4199 printk(KERN_ERR
4200 "sisfb: Video RAM size detection limited to %dMB\n",
4201 (int)((*mapsize) >> 20));
4206 #ifdef CONFIG_FB_SIS_300
4207 static int __devinit
4208 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4210 void __iomem *FBAddress = ivideo->video_vbase;
4211 unsigned short temp;
4212 unsigned char reg;
4213 int i, j;
4215 andSISIDXREG(SISSR, 0x15, 0xFB);
4216 orSISIDXREG(SISSR, 0x15, 0x04);
4217 outSISIDXREG(SISSR, 0x13, 0x00);
4218 outSISIDXREG(SISSR, 0x14, 0xBF);
4220 for(i = 0; i < 2; i++) {
4221 temp = 0x1234;
4222 for(j = 0; j < 4; j++) {
4223 writew(temp, FBAddress);
4224 if(readw(FBAddress) == temp)
4225 break;
4226 orSISIDXREG(SISSR, 0x3c, 0x01);
4227 inSISIDXREG(SISSR, 0x05, reg);
4228 inSISIDXREG(SISSR, 0x05, reg);
4229 andSISIDXREG(SISSR, 0x3c, 0xfe);
4230 inSISIDXREG(SISSR, 0x05, reg);
4231 inSISIDXREG(SISSR, 0x05, reg);
4232 temp++;
4236 writel(0x01234567L, FBAddress);
4237 writel(0x456789ABL, (FBAddress + 4));
4238 writel(0x89ABCDEFL, (FBAddress + 8));
4239 writel(0xCDEF0123L, (FBAddress + 12));
4241 inSISIDXREG(SISSR, 0x3b, reg);
4242 if(reg & 0x01) {
4243 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4244 return 4; /* Channel A 128bit */
4247 if(readl((FBAddress + 4)) == 0x456789ABL)
4248 return 2; /* Channel B 64bit */
4250 return 1; /* 32bit */
4253 static int __devinit
4254 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4255 int PseudoRankCapacity, int PseudoAdrPinCount,
4256 unsigned int mapsize)
4258 void __iomem *FBAddr = ivideo->video_vbase;
4259 unsigned short sr14;
4260 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4261 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4262 static const unsigned short SiS_DRAMType[17][5] = {
4263 {0x0C,0x0A,0x02,0x40,0x39},
4264 {0x0D,0x0A,0x01,0x40,0x48},
4265 {0x0C,0x09,0x02,0x20,0x35},
4266 {0x0D,0x09,0x01,0x20,0x44},
4267 {0x0C,0x08,0x02,0x10,0x31},
4268 {0x0D,0x08,0x01,0x10,0x40},
4269 {0x0C,0x0A,0x01,0x20,0x34},
4270 {0x0C,0x09,0x01,0x08,0x32},
4271 {0x0B,0x08,0x02,0x08,0x21},
4272 {0x0C,0x08,0x01,0x08,0x30},
4273 {0x0A,0x08,0x02,0x04,0x11},
4274 {0x0B,0x0A,0x01,0x10,0x28},
4275 {0x09,0x08,0x02,0x02,0x01},
4276 {0x0B,0x09,0x01,0x08,0x24},
4277 {0x0B,0x08,0x01,0x04,0x20},
4278 {0x0A,0x08,0x01,0x02,0x10},
4279 {0x09,0x08,0x01,0x01,0x00}
4282 for(k = 0; k <= 16; k++) {
4284 RankCapacity = buswidth * SiS_DRAMType[k][3];
4286 if(RankCapacity != PseudoRankCapacity)
4287 continue;
4289 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4290 continue;
4292 BankNumHigh = RankCapacity * 16 * iteration - 1;
4293 if(iteration == 3) { /* Rank No */
4294 BankNumMid = RankCapacity * 16 - 1;
4295 } else {
4296 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4299 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4300 PhysicalAdrHigh = BankNumHigh;
4301 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4302 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4304 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4305 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4306 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4307 if(buswidth == 4) sr14 |= 0x80;
4308 else if(buswidth == 2) sr14 |= 0x40;
4309 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4310 outSISIDXREG(SISSR, 0x14, sr14);
4312 BankNumHigh <<= 16;
4313 BankNumMid <<= 16;
4315 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4316 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4317 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4318 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4319 continue;
4321 /* Write data */
4322 writew(((unsigned short)PhysicalAdrHigh),
4323 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4324 writew(((unsigned short)BankNumMid),
4325 (FBAddr + BankNumMid + PhysicalAdrHigh));
4326 writew(((unsigned short)PhysicalAdrHalfPage),
4327 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4328 writew(((unsigned short)PhysicalAdrOtherPage),
4329 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4331 /* Read data */
4332 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4333 return 1;
4336 return 0;
4339 static void __devinit
4340 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4342 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4343 int i, j, buswidth;
4344 int PseudoRankCapacity, PseudoAdrPinCount;
4346 buswidth = sisfb_post_300_buswidth(ivideo);
4348 for(i = 6; i >= 0; i--) {
4349 PseudoRankCapacity = 1 << i;
4350 for(j = 4; j >= 1; j--) {
4351 PseudoAdrPinCount = 15 - j;
4352 if((PseudoRankCapacity * j) <= 64) {
4353 if(sisfb_post_300_rwtest(ivideo,
4355 buswidth,
4356 PseudoRankCapacity,
4357 PseudoAdrPinCount,
4358 mapsize))
4359 return;
4365 static void __devinit
4366 sisfb_post_sis300(struct pci_dev *pdev)
4368 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4369 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4370 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4371 u16 index, rindex, memtype = 0;
4372 unsigned int mapsize;
4374 if(!ivideo->SiS_Pr.UseROM)
4375 bios = NULL;
4377 outSISIDXREG(SISSR, 0x05, 0x86);
4379 if(bios) {
4380 if(bios[0x52] & 0x80) {
4381 memtype = bios[0x52];
4382 } else {
4383 inSISIDXREG(SISSR, 0x3a, memtype);
4385 memtype &= 0x07;
4388 v3 = 0x80; v6 = 0x80;
4389 if(ivideo->revision_id <= 0x13) {
4390 v1 = 0x44; v2 = 0x42;
4391 v4 = 0x44; v5 = 0x42;
4392 } else {
4393 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4394 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4395 if(bios) {
4396 index = memtype * 5;
4397 rindex = index + 0x54;
4398 v1 = bios[rindex++];
4399 v2 = bios[rindex++];
4400 v3 = bios[rindex++];
4401 rindex = index + 0x7c;
4402 v4 = bios[rindex++];
4403 v5 = bios[rindex++];
4404 v6 = bios[rindex++];
4407 outSISIDXREG(SISSR, 0x28, v1);
4408 outSISIDXREG(SISSR, 0x29, v2);
4409 outSISIDXREG(SISSR, 0x2a, v3);
4410 outSISIDXREG(SISSR, 0x2e, v4);
4411 outSISIDXREG(SISSR, 0x2f, v5);
4412 outSISIDXREG(SISSR, 0x30, v6);
4414 v1 = 0x10;
4415 if(bios)
4416 v1 = bios[0xa4];
4417 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4419 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4421 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4422 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4423 if(bios) {
4424 memtype += 0xa5;
4425 v1 = bios[memtype];
4426 v2 = bios[memtype + 8];
4427 v3 = bios[memtype + 16];
4428 v4 = bios[memtype + 24];
4429 v5 = bios[memtype + 32];
4430 v6 = bios[memtype + 40];
4431 v7 = bios[memtype + 48];
4432 v8 = bios[memtype + 56];
4434 if(ivideo->revision_id >= 0x80)
4435 v3 &= 0xfd;
4436 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4437 outSISIDXREG(SISSR, 0x16, v2);
4438 outSISIDXREG(SISSR, 0x17, v3);
4439 outSISIDXREG(SISSR, 0x18, v4);
4440 outSISIDXREG(SISSR, 0x19, v5);
4441 outSISIDXREG(SISSR, 0x1a, v6);
4442 outSISIDXREG(SISSR, 0x1b, v7);
4443 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4444 andSISIDXREG(SISSR, 0x15 ,0xfb);
4445 orSISIDXREG(SISSR, 0x15, 0x04);
4446 if(bios) {
4447 if(bios[0x53] & 0x02) {
4448 orSISIDXREG(SISSR, 0x19, 0x20);
4451 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4452 if(ivideo->revision_id >= 0x80)
4453 v1 |= 0x01;
4454 outSISIDXREG(SISSR, 0x1f, v1);
4455 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4456 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4457 if(bios) {
4458 v1 = bios[0xe8];
4459 v2 = bios[0xe9];
4460 v3 = bios[0xea];
4462 outSISIDXREG(SISSR, 0x23, v1);
4463 outSISIDXREG(SISSR, 0x24, v2);
4464 outSISIDXREG(SISSR, 0x25, v3);
4465 outSISIDXREG(SISSR, 0x21, 0x84);
4466 outSISIDXREG(SISSR, 0x22, 0x00);
4467 outSISIDXREG(SISCR, 0x37, 0x00);
4468 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4469 outSISIDXREG(SISPART1, 0x00, 0x00);
4470 v1 = 0x40; v2 = 0x11;
4471 if(bios) {
4472 v1 = bios[0xec];
4473 v2 = bios[0xeb];
4475 outSISIDXREG(SISPART1, 0x02, v1);
4477 if(ivideo->revision_id >= 0x80)
4478 v2 &= ~0x01;
4480 inSISIDXREG(SISPART4, 0x00, reg);
4481 if((reg == 1) || (reg == 2)) {
4482 outSISIDXREG(SISCR, 0x37, 0x02);
4483 outSISIDXREG(SISPART2, 0x00, 0x1c);
4484 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4485 if(ivideo->SiS_Pr.UseROM) {
4486 v4 = bios[0xf5];
4487 v5 = bios[0xf6];
4488 v6 = bios[0xf7];
4490 outSISIDXREG(SISPART4, 0x0d, v4);
4491 outSISIDXREG(SISPART4, 0x0e, v5);
4492 outSISIDXREG(SISPART4, 0x10, v6);
4493 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4494 inSISIDXREG(SISPART4, 0x01, reg);
4495 if(reg >= 0xb0) {
4496 inSISIDXREG(SISPART4, 0x23, reg);
4497 reg &= 0x20;
4498 reg <<= 1;
4499 outSISIDXREG(SISPART4, 0x23, reg);
4501 } else {
4502 v2 &= ~0x10;
4504 outSISIDXREG(SISSR, 0x32, v2);
4506 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4508 inSISIDXREG(SISSR, 0x16, reg);
4509 reg &= 0xc3;
4510 outSISIDXREG(SISCR, 0x35, reg);
4511 outSISIDXREG(SISCR, 0x83, 0x00);
4512 #if !defined(__i386__) && !defined(__x86_64__)
4513 if(sisfb_videoram) {
4514 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4515 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4516 outSISIDXREG(SISSR, 0x14, reg);
4517 } else {
4518 #endif
4519 /* Need to map max FB size for finding out about RAM size */
4520 mapsize = 64 << 20;
4521 sisfb_post_map_vram(ivideo, &mapsize, 4);
4523 if(ivideo->video_vbase) {
4524 sisfb_post_300_ramsize(pdev, mapsize);
4525 iounmap(ivideo->video_vbase);
4526 } else {
4527 printk(KERN_DEBUG
4528 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4529 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4530 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4532 #if !defined(__i386__) && !defined(__x86_64__)
4534 #endif
4535 if(bios) {
4536 v1 = bios[0xe6];
4537 v2 = bios[0xe7];
4538 } else {
4539 inSISIDXREG(SISSR, 0x3a, reg);
4540 if((reg & 0x30) == 0x30) {
4541 v1 = 0x04; /* PCI */
4542 v2 = 0x92;
4543 } else {
4544 v1 = 0x14; /* AGP */
4545 v2 = 0xb2;
4548 outSISIDXREG(SISSR, 0x21, v1);
4549 outSISIDXREG(SISSR, 0x22, v2);
4551 /* Sense CRT1 */
4552 sisfb_sense_crt1(ivideo);
4554 /* Set default mode, don't clear screen */
4555 ivideo->SiS_Pr.SiS_UseOEM = false;
4556 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4557 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
4558 ivideo->curFSTN = ivideo->curDSTN = 0;
4559 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4560 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4562 outSISIDXREG(SISSR, 0x05, 0x86);
4564 /* Display off */
4565 orSISIDXREG(SISSR, 0x01, 0x20);
4567 /* Save mode number in CR34 */
4568 outSISIDXREG(SISCR, 0x34, 0x2e);
4570 /* Let everyone know what the current mode is */
4571 ivideo->modeprechange = 0x2e;
4573 #endif
4575 #ifdef CONFIG_FB_SIS_315
4576 #if 0
4577 static void __devinit
4578 sisfb_post_sis315330(struct pci_dev *pdev)
4580 /* TODO */
4582 #endif
4584 static void __devinit
4585 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4587 unsigned int i;
4588 u8 reg;
4590 for(i = 0; i <= (delay * 10 * 36); i++) {
4591 inSISIDXREG(SISSR, 0x05, reg);
4592 reg++;
4596 static int __devinit
4597 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4598 unsigned short pcivendor)
4600 struct pci_dev *pdev = NULL;
4601 unsigned short temp;
4602 int ret = 0;
4604 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
4605 temp = pdev->vendor;
4606 if(temp == pcivendor) {
4607 ret = 1;
4608 pci_dev_put(pdev);
4609 break;
4613 return ret;
4616 static int __devinit
4617 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4618 unsigned int enda, unsigned int mapsize)
4620 unsigned int pos;
4621 int i;
4623 writel(0, ivideo->video_vbase);
4625 for(i = starta; i <= enda; i++) {
4626 pos = 1 << i;
4627 if(pos < mapsize)
4628 writel(pos, ivideo->video_vbase + pos);
4631 sisfb_post_xgi_delay(ivideo, 150);
4633 if(readl(ivideo->video_vbase) != 0)
4634 return 0;
4636 for(i = starta; i <= enda; i++) {
4637 pos = 1 << i;
4638 if(pos < mapsize) {
4639 if(readl(ivideo->video_vbase + pos) != pos)
4640 return 0;
4641 } else
4642 return 0;
4645 return 1;
4648 static void __devinit
4649 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4651 unsigned int buswidth, ranksize, channelab, mapsize;
4652 int i, j, k, l;
4653 u8 reg, sr14;
4654 static const u8 dramsr13[12 * 5] = {
4655 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4656 0x02, 0x0e, 0x0a, 0x40, 0x59,
4657 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4658 0x02, 0x0e, 0x09, 0x20, 0x55,
4659 0x02, 0x0d, 0x0a, 0x20, 0x49,
4660 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4661 0x02, 0x0e, 0x08, 0x10, 0x51,
4662 0x02, 0x0d, 0x09, 0x10, 0x45,
4663 0x02, 0x0c, 0x0a, 0x10, 0x39,
4664 0x02, 0x0d, 0x08, 0x08, 0x41,
4665 0x02, 0x0c, 0x09, 0x08, 0x35,
4666 0x02, 0x0c, 0x08, 0x04, 0x31
4668 static const u8 dramsr13_4[4 * 5] = {
4669 0x02, 0x0d, 0x09, 0x40, 0x45,
4670 0x02, 0x0c, 0x09, 0x20, 0x35,
4671 0x02, 0x0c, 0x08, 0x10, 0x31,
4672 0x02, 0x0b, 0x08, 0x08, 0x21
4675 /* Enable linear mode, disable 0xa0000 address decoding */
4676 /* We disable a0000 address decoding, because
4677 * - if running on x86, if the card is disabled, it means
4678 * that another card is in the system. We don't want
4679 * to interphere with that primary card's textmode.
4680 * - if running on non-x86, there usually is no VGA window
4681 * at a0000.
4683 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4685 /* Need to map max FB size for finding out about RAM size */
4686 mapsize = 256 << 20;
4687 sisfb_post_map_vram(ivideo, &mapsize, 32);
4689 if(!ivideo->video_vbase) {
4690 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4691 outSISIDXREG(SISSR, 0x13, 0x35);
4692 outSISIDXREG(SISSR, 0x14, 0x41);
4693 /* TODO */
4694 return;
4697 /* Non-interleaving */
4698 outSISIDXREG(SISSR, 0x15, 0x00);
4699 /* No tiling */
4700 outSISIDXREG(SISSR, 0x1c, 0x00);
4702 if(ivideo->chip == XGI_20) {
4704 channelab = 1;
4705 inSISIDXREG(SISCR, 0x97, reg);
4706 if(!(reg & 0x01)) { /* Single 32/16 */
4707 buswidth = 32;
4708 outSISIDXREG(SISSR, 0x13, 0xb1);
4709 outSISIDXREG(SISSR, 0x14, 0x52);
4710 sisfb_post_xgi_delay(ivideo, 1);
4711 sr14 = 0x02;
4712 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4713 goto bail_out;
4715 outSISIDXREG(SISSR, 0x13, 0x31);
4716 outSISIDXREG(SISSR, 0x14, 0x42);
4717 sisfb_post_xgi_delay(ivideo, 1);
4718 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4719 goto bail_out;
4721 buswidth = 16;
4722 outSISIDXREG(SISSR, 0x13, 0xb1);
4723 outSISIDXREG(SISSR, 0x14, 0x41);
4724 sisfb_post_xgi_delay(ivideo, 1);
4725 sr14 = 0x01;
4726 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4727 goto bail_out;
4728 else
4729 outSISIDXREG(SISSR, 0x13, 0x31);
4730 } else { /* Dual 16/8 */
4731 buswidth = 16;
4732 outSISIDXREG(SISSR, 0x13, 0xb1);
4733 outSISIDXREG(SISSR, 0x14, 0x41);
4734 sisfb_post_xgi_delay(ivideo, 1);
4735 sr14 = 0x01;
4736 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4737 goto bail_out;
4739 outSISIDXREG(SISSR, 0x13, 0x31);
4740 outSISIDXREG(SISSR, 0x14, 0x31);
4741 sisfb_post_xgi_delay(ivideo, 1);
4742 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4743 goto bail_out;
4745 buswidth = 8;
4746 outSISIDXREG(SISSR, 0x13, 0xb1);
4747 outSISIDXREG(SISSR, 0x14, 0x30);
4748 sisfb_post_xgi_delay(ivideo, 1);
4749 sr14 = 0x00;
4750 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4751 goto bail_out;
4752 else
4753 outSISIDXREG(SISSR, 0x13, 0x31);
4756 } else { /* XGI_40 */
4758 inSISIDXREG(SISCR, 0x97, reg);
4759 if(!(reg & 0x10)) {
4760 inSISIDXREG(SISSR, 0x39, reg);
4761 reg >>= 1;
4764 if(reg & 0x01) { /* DDRII */
4765 buswidth = 32;
4766 if(ivideo->revision_id == 2) {
4767 channelab = 2;
4768 outSISIDXREG(SISSR, 0x13, 0xa1);
4769 outSISIDXREG(SISSR, 0x14, 0x44);
4770 sr14 = 0x04;
4771 sisfb_post_xgi_delay(ivideo, 1);
4772 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4773 goto bail_out;
4775 outSISIDXREG(SISSR, 0x13, 0x21);
4776 outSISIDXREG(SISSR, 0x14, 0x34);
4777 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4778 goto bail_out;
4780 channelab = 1;
4781 outSISIDXREG(SISSR, 0x13, 0xa1);
4782 outSISIDXREG(SISSR, 0x14, 0x40);
4783 sr14 = 0x00;
4784 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4785 goto bail_out;
4787 outSISIDXREG(SISSR, 0x13, 0x21);
4788 outSISIDXREG(SISSR, 0x14, 0x30);
4789 } else {
4790 channelab = 3;
4791 outSISIDXREG(SISSR, 0x13, 0xa1);
4792 outSISIDXREG(SISSR, 0x14, 0x4c);
4793 sr14 = 0x0c;
4794 sisfb_post_xgi_delay(ivideo, 1);
4795 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4796 goto bail_out;
4798 channelab = 2;
4799 outSISIDXREG(SISSR, 0x14, 0x48);
4800 sisfb_post_xgi_delay(ivideo, 1);
4801 sr14 = 0x08;
4802 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4803 goto bail_out;
4805 outSISIDXREG(SISSR, 0x13, 0x21);
4806 outSISIDXREG(SISSR, 0x14, 0x3c);
4807 sr14 = 0x0c;
4809 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4810 channelab = 3;
4811 } else {
4812 channelab = 2;
4813 outSISIDXREG(SISSR, 0x14, 0x38);
4814 sr14 = 0x08;
4817 sisfb_post_xgi_delay(ivideo, 1);
4819 } else { /* DDR */
4821 buswidth = 64;
4822 if(ivideo->revision_id == 2) {
4823 channelab = 1;
4824 outSISIDXREG(SISSR, 0x13, 0xa1);
4825 outSISIDXREG(SISSR, 0x14, 0x52);
4826 sisfb_post_xgi_delay(ivideo, 1);
4827 sr14 = 0x02;
4828 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4829 goto bail_out;
4831 outSISIDXREG(SISSR, 0x13, 0x21);
4832 outSISIDXREG(SISSR, 0x14, 0x42);
4833 } else {
4834 channelab = 2;
4835 outSISIDXREG(SISSR, 0x13, 0xa1);
4836 outSISIDXREG(SISSR, 0x14, 0x5a);
4837 sisfb_post_xgi_delay(ivideo, 1);
4838 sr14 = 0x0a;
4839 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4840 goto bail_out;
4842 outSISIDXREG(SISSR, 0x13, 0x21);
4843 outSISIDXREG(SISSR, 0x14, 0x4a);
4845 sisfb_post_xgi_delay(ivideo, 1);
4850 bail_out:
4851 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4852 sisfb_post_xgi_delay(ivideo, 1);
4854 j = (ivideo->chip == XGI_20) ? 5 : 9;
4855 k = (ivideo->chip == XGI_20) ? 12 : 4;
4857 for(i = 0; i < k; i++) {
4859 reg = (ivideo->chip == XGI_20) ?
4860 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4861 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4862 sisfb_post_xgi_delay(ivideo, 50);
4864 ranksize = (ivideo->chip == XGI_20) ?
4865 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4867 inSISIDXREG(SISSR, 0x13, reg);
4868 if(reg & 0x80) ranksize <<= 1;
4870 if(ivideo->chip == XGI_20) {
4871 if(buswidth == 16) ranksize <<= 1;
4872 else if(buswidth == 32) ranksize <<= 2;
4873 } else {
4874 if(buswidth == 64) ranksize <<= 1;
4877 reg = 0;
4878 l = channelab;
4879 if(l == 3) l = 4;
4880 if((ranksize * l) <= 256) {
4881 while((ranksize >>= 1)) reg += 0x10;
4884 if(!reg) continue;
4886 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4887 sisfb_post_xgi_delay(ivideo, 1);
4889 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4890 break;
4893 iounmap(ivideo->video_vbase);
4896 static void __devinit
4897 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4899 u8 v1, v2, v3;
4900 int index;
4901 static const u8 cs90[8 * 3] = {
4902 0x16, 0x01, 0x01,
4903 0x3e, 0x03, 0x01,
4904 0x7c, 0x08, 0x01,
4905 0x79, 0x06, 0x01,
4906 0x29, 0x01, 0x81,
4907 0x5c, 0x23, 0x01,
4908 0x5c, 0x23, 0x01,
4909 0x5c, 0x23, 0x01
4911 static const u8 csb8[8 * 3] = {
4912 0x5c, 0x23, 0x01,
4913 0x29, 0x01, 0x01,
4914 0x7c, 0x08, 0x01,
4915 0x79, 0x06, 0x01,
4916 0x29, 0x01, 0x81,
4917 0x5c, 0x23, 0x01,
4918 0x5c, 0x23, 0x01,
4919 0x5c, 0x23, 0x01
4922 regb = 0; /* ! */
4924 index = regb * 3;
4925 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4926 if(ivideo->haveXGIROM) {
4927 v1 = ivideo->bios_abase[0x90 + index];
4928 v2 = ivideo->bios_abase[0x90 + index + 1];
4929 v3 = ivideo->bios_abase[0x90 + index + 2];
4931 outSISIDXREG(SISSR, 0x28, v1);
4932 outSISIDXREG(SISSR, 0x29, v2);
4933 outSISIDXREG(SISSR, 0x2a, v3);
4934 sisfb_post_xgi_delay(ivideo, 0x43);
4935 sisfb_post_xgi_delay(ivideo, 0x43);
4936 sisfb_post_xgi_delay(ivideo, 0x43);
4937 index = regb * 3;
4938 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4939 if(ivideo->haveXGIROM) {
4940 v1 = ivideo->bios_abase[0xb8 + index];
4941 v2 = ivideo->bios_abase[0xb8 + index + 1];
4942 v3 = ivideo->bios_abase[0xb8 + index + 2];
4944 outSISIDXREG(SISSR, 0x2e, v1);
4945 outSISIDXREG(SISSR, 0x2f, v2);
4946 outSISIDXREG(SISSR, 0x30, v3);
4947 sisfb_post_xgi_delay(ivideo, 0x43);
4948 sisfb_post_xgi_delay(ivideo, 0x43);
4949 sisfb_post_xgi_delay(ivideo, 0x43);
4952 static int __devinit
4953 sisfb_post_xgi(struct pci_dev *pdev)
4955 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4956 unsigned char *bios = ivideo->bios_abase;
4957 struct pci_dev *mypdev = NULL;
4958 const u8 *ptr, *ptr2;
4959 u8 v1, v2, v3, v4, v5, reg, ramtype;
4960 u32 rega, regb, regd;
4961 int i, j, k, index;
4962 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4963 static const u8 cs76[2] = { 0xa3, 0xfb };
4964 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4965 static const u8 cs158[8] = {
4966 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4968 static const u8 cs160[8] = {
4969 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4971 static const u8 cs168[8] = {
4972 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4974 static const u8 cs128[3 * 8] = {
4975 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4976 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4977 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4979 static const u8 cs148[2 * 8] = {
4980 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4981 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4983 static const u8 cs31a[8 * 4] = {
4984 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
4985 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
4986 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4987 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4989 static const u8 cs33a[8 * 4] = {
4990 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4991 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4992 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4993 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4995 static const u8 cs45a[8 * 2] = {
4996 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
4997 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4999 static const u8 cs170[7 * 8] = {
5000 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5001 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5002 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5003 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5004 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5005 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5006 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5008 static const u8 cs1a8[3 * 8] = {
5009 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5010 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5011 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5013 static const u8 cs100[2 * 8] = {
5014 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5015 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5018 /* VGA enable */
5019 reg = inSISREG(SISVGAENABLE) | 0x01;
5020 outSISREG(SISVGAENABLE, reg);
5022 /* Misc */
5023 reg = inSISREG(SISMISCR) | 0x01;
5024 outSISREG(SISMISCW, reg);
5026 /* Unlock SR */
5027 outSISIDXREG(SISSR, 0x05, 0x86);
5028 inSISIDXREG(SISSR, 0x05, reg);
5029 if(reg != 0xa1)
5030 return 0;
5032 /* Clear some regs */
5033 for(i = 0; i < 0x22; i++) {
5034 if(0x06 + i == 0x20) continue;
5035 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5037 for(i = 0; i < 0x0b; i++) {
5038 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5040 for(i = 0; i < 0x10; i++) {
5041 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5044 ptr = cs78;
5045 if(ivideo->haveXGIROM) {
5046 ptr = (const u8 *)&bios[0x78];
5048 for(i = 0; i < 3; i++) {
5049 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5052 ptr = cs76;
5053 if(ivideo->haveXGIROM) {
5054 ptr = (const u8 *)&bios[0x76];
5056 for(i = 0; i < 2; i++) {
5057 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5060 v1 = 0x18; v2 = 0x00;
5061 if(ivideo->haveXGIROM) {
5062 v1 = bios[0x74];
5063 v2 = bios[0x75];
5065 outSISIDXREG(SISSR, 0x07, v1);
5066 outSISIDXREG(SISSR, 0x11, 0x0f);
5067 outSISIDXREG(SISSR, 0x1f, v2);
5068 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5069 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5070 outSISIDXREG(SISSR, 0x27, 0x74);
5072 ptr = cs7b;
5073 if(ivideo->haveXGIROM) {
5074 ptr = (const u8 *)&bios[0x7b];
5076 for(i = 0; i < 3; i++) {
5077 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5080 if(ivideo->chip == XGI_40) {
5081 if(ivideo->revision_id == 2) {
5082 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5084 outSISIDXREG(SISCR, 0x7d, 0xfe);
5085 outSISIDXREG(SISCR, 0x7e, 0x0f);
5087 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5088 andSISIDXREG(SISCR, 0x58, 0xd7);
5089 inSISIDXREG(SISCR, 0xcb, reg);
5090 if(reg & 0x20) {
5091 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5095 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5096 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5098 if(ivideo->chip == XGI_20) {
5099 outSISIDXREG(SISSR, 0x36, 0x70);
5100 } else {
5101 outSISIDXREG(SISVID, 0x00, 0x86);
5102 outSISIDXREG(SISVID, 0x32, 0x00);
5103 outSISIDXREG(SISVID, 0x30, 0x00);
5104 outSISIDXREG(SISVID, 0x32, 0x01);
5105 outSISIDXREG(SISVID, 0x30, 0x00);
5106 andSISIDXREG(SISVID, 0x2f, 0xdf);
5107 andSISIDXREG(SISCAP, 0x00, 0x3f);
5109 outSISIDXREG(SISPART1, 0x2f, 0x01);
5110 outSISIDXREG(SISPART1, 0x00, 0x00);
5111 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5112 outSISIDXREG(SISPART1, 0x2e, 0x08);
5113 andSISIDXREG(SISPART1, 0x35, 0x7f);
5114 andSISIDXREG(SISPART1, 0x50, 0xfe);
5116 inSISIDXREG(SISPART4, 0x00, reg);
5117 if(reg == 1 || reg == 2) {
5118 outSISIDXREG(SISPART2, 0x00, 0x1c);
5119 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5120 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5121 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5122 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5124 inSISIDXREG(SISPART4, 0x01, reg);
5125 if((reg & 0xf0) >= 0xb0) {
5126 inSISIDXREG(SISPART4, 0x23, reg);
5127 if(reg & 0x20) reg |= 0x40;
5128 outSISIDXREG(SISPART4, 0x23, reg);
5129 reg = (reg & 0x20) ? 0x02 : 0x00;
5130 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5134 v1 = bios[0x77];
5136 inSISIDXREG(SISSR, 0x3b, reg);
5137 if(reg & 0x02) {
5138 inSISIDXREG(SISSR, 0x3a, reg);
5139 v2 = (reg & 0x30) >> 3;
5140 if(!(v2 & 0x04)) v2 ^= 0x02;
5141 inSISIDXREG(SISSR, 0x39, reg);
5142 if(reg & 0x80) v2 |= 0x80;
5143 v2 |= 0x01;
5145 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5146 pci_dev_put(mypdev);
5147 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5148 v2 &= 0xf9;
5149 v2 |= 0x08;
5150 v1 &= 0xfe;
5151 } else {
5152 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
5153 if(!mypdev)
5154 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
5155 if(!mypdev)
5156 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
5157 if(mypdev) {
5158 pci_read_config_dword(mypdev, 0x94, &regd);
5159 regd &= 0xfffffeff;
5160 pci_write_config_dword(mypdev, 0x94, regd);
5161 v1 &= 0xfe;
5162 pci_dev_put(mypdev);
5163 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5164 v1 &= 0xfe;
5165 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5166 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5167 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5168 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5169 if((v2 & 0x06) == 4)
5170 v2 ^= 0x06;
5171 v2 |= 0x08;
5174 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5176 outSISIDXREG(SISSR, 0x22, v1);
5178 if(ivideo->revision_id == 2) {
5179 inSISIDXREG(SISSR, 0x3b, v1);
5180 inSISIDXREG(SISSR, 0x3a, v2);
5181 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5182 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5183 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5185 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
5186 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5187 * of nforce 2 ROM
5189 if(0)
5190 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5191 pci_dev_put(mypdev);
5195 v1 = 0x30;
5196 inSISIDXREG(SISSR, 0x3b, reg);
5197 inSISIDXREG(SISCR, 0x5f, v2);
5198 if((!(reg & 0x02)) && (v2 & 0x0e))
5199 v1 |= 0x08;
5200 outSISIDXREG(SISSR, 0x27, v1);
5202 if(bios[0x64] & 0x01) {
5203 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5206 v1 = bios[0x4f7];
5207 pci_read_config_dword(pdev, 0x50, &regd);
5208 regd = (regd >> 20) & 0x0f;
5209 if(regd == 1) {
5210 v1 &= 0xfc;
5211 orSISIDXREG(SISCR, 0x5f, 0x08);
5213 outSISIDXREG(SISCR, 0x48, v1);
5215 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5216 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5217 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5218 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5219 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5220 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5221 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5222 outSISIDXREG(SISCR, 0x74, 0xd0);
5223 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5224 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5225 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5226 v1 = bios[0x501];
5227 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
5228 v1 = 0xf0;
5229 pci_dev_put(mypdev);
5231 outSISIDXREG(SISCR, 0x77, v1);
5234 /* RAM type */
5236 regb = 0; /* ! */
5238 v1 = 0xff;
5239 if(ivideo->haveXGIROM) {
5240 v1 = bios[0x140 + regb];
5242 outSISIDXREG(SISCR, 0x6d, v1);
5244 ptr = cs128;
5245 if(ivideo->haveXGIROM) {
5246 ptr = (const u8 *)&bios[0x128];
5248 for(i = 0, j = 0; i < 3; i++, j += 8) {
5249 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5252 ptr = cs31a;
5253 ptr2 = cs33a;
5254 if(ivideo->haveXGIROM) {
5255 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5256 ptr = (const u8 *)&bios[index];
5257 ptr2 = (const u8 *)&bios[index + 0x20];
5259 for(i = 0; i < 2; i++) {
5260 if(i == 0) {
5261 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5262 rega = 0x6b;
5263 } else {
5264 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5265 rega = 0x6e;
5267 reg = 0x00;
5268 for(j = 0; j < 16; j++) {
5269 reg &= 0xf3;
5270 if(regd & 0x01) reg |= 0x04;
5271 if(regd & 0x02) reg |= 0x08;
5272 regd >>= 2;
5273 outSISIDXREG(SISCR, rega, reg);
5274 inSISIDXREG(SISCR, rega, reg);
5275 inSISIDXREG(SISCR, rega, reg);
5276 reg += 0x10;
5280 andSISIDXREG(SISCR, 0x6e, 0xfc);
5282 ptr = NULL;
5283 if(ivideo->haveXGIROM) {
5284 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5285 ptr = (const u8 *)&bios[index];
5287 for(i = 0; i < 4; i++) {
5288 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5289 reg = 0x00;
5290 for(j = 0; j < 2; j++) {
5291 regd = 0;
5292 if(ptr) {
5293 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5294 ptr += 4;
5296 /* reg = 0x00; */
5297 for(k = 0; k < 16; k++) {
5298 reg &= 0xfc;
5299 if(regd & 0x01) reg |= 0x01;
5300 if(regd & 0x02) reg |= 0x02;
5301 regd >>= 2;
5302 outSISIDXREG(SISCR, 0x6f, reg);
5303 inSISIDXREG(SISCR, 0x6f, reg);
5304 inSISIDXREG(SISCR, 0x6f, reg);
5305 reg += 0x08;
5310 ptr = cs148;
5311 if(ivideo->haveXGIROM) {
5312 ptr = (const u8 *)&bios[0x148];
5314 for(i = 0, j = 0; i < 2; i++, j += 8) {
5315 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5318 andSISIDXREG(SISCR, 0x89, 0x8f);
5320 ptr = cs45a;
5321 if(ivideo->haveXGIROM) {
5322 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5323 ptr = (const u8 *)&bios[index];
5325 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5326 reg = 0x80;
5327 for(i = 0; i < 5; i++) {
5328 reg &= 0xfc;
5329 if(regd & 0x01) reg |= 0x01;
5330 if(regd & 0x02) reg |= 0x02;
5331 regd >>= 2;
5332 outSISIDXREG(SISCR, 0x89, reg);
5333 inSISIDXREG(SISCR, 0x89, reg);
5334 inSISIDXREG(SISCR, 0x89, reg);
5335 reg += 0x10;
5338 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5339 if(ivideo->haveXGIROM) {
5340 v1 = bios[0x118 + regb];
5341 v2 = bios[0xf8 + regb];
5342 v3 = bios[0x120 + regb];
5343 v4 = bios[0x1ca];
5345 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5346 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5347 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5348 outSISIDXREG(SISCR, 0x41, v2);
5350 ptr = cs170;
5351 if(ivideo->haveXGIROM) {
5352 ptr = (const u8 *)&bios[0x170];
5354 for(i = 0, j = 0; i < 7; i++, j += 8) {
5355 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5358 outSISIDXREG(SISCR, 0x59, v3);
5360 ptr = cs1a8;
5361 if(ivideo->haveXGIROM) {
5362 ptr = (const u8 *)&bios[0x1a8];
5364 for(i = 0, j = 0; i < 3; i++, j += 8) {
5365 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5368 ptr = cs100;
5369 if(ivideo->haveXGIROM) {
5370 ptr = (const u8 *)&bios[0x100];
5372 for(i = 0, j = 0; i < 2; i++, j += 8) {
5373 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5376 outSISIDXREG(SISCR, 0xcf, v4);
5378 outSISIDXREG(SISCR, 0x83, 0x09);
5379 outSISIDXREG(SISCR, 0x87, 0x00);
5381 if(ivideo->chip == XGI_40) {
5382 if( (ivideo->revision_id == 1) ||
5383 (ivideo->revision_id == 2) ) {
5384 outSISIDXREG(SISCR, 0x8c, 0x87);
5388 outSISIDXREG(SISSR, 0x17, 0x00);
5389 outSISIDXREG(SISSR, 0x1a, 0x87);
5391 if(ivideo->chip == XGI_20) {
5392 outSISIDXREG(SISSR, 0x15, 0x00);
5393 outSISIDXREG(SISSR, 0x1c, 0x00);
5396 ramtype = 0x00; v1 = 0x10;
5397 if(ivideo->haveXGIROM) {
5398 ramtype = bios[0x62];
5399 v1 = bios[0x1d2];
5401 if(!(ramtype & 0x80)) {
5402 if(ivideo->chip == XGI_20) {
5403 outSISIDXREG(SISCR, 0x97, v1);
5404 inSISIDXREG(SISCR, 0x97, reg);
5405 if(reg & 0x10) {
5406 ramtype = (reg & 0x01) << 1;
5408 } else {
5409 inSISIDXREG(SISSR, 0x39, reg);
5410 ramtype = reg & 0x02;
5411 if(!(ramtype)) {
5412 inSISIDXREG(SISSR, 0x3a, reg);
5413 ramtype = (reg >> 1) & 0x01;
5417 ramtype &= 0x07;
5419 regb = 0; /* ! */
5421 switch(ramtype) {
5422 case 0:
5423 sisfb_post_xgi_setclocks(ivideo, regb);
5424 if((ivideo->chip == XGI_20) ||
5425 (ivideo->revision_id == 1) ||
5426 (ivideo->revision_id == 2)) {
5427 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5428 if(ivideo->haveXGIROM) {
5429 v1 = bios[regb + 0x158];
5430 v2 = bios[regb + 0x160];
5431 v3 = bios[regb + 0x168];
5433 outSISIDXREG(SISCR, 0x82, v1);
5434 outSISIDXREG(SISCR, 0x85, v2);
5435 outSISIDXREG(SISCR, 0x86, v3);
5436 } else {
5437 outSISIDXREG(SISCR, 0x82, 0x88);
5438 outSISIDXREG(SISCR, 0x86, 0x00);
5439 inSISIDXREG(SISCR, 0x86, reg);
5440 outSISIDXREG(SISCR, 0x86, 0x88);
5441 inSISIDXREG(SISCR, 0x86, reg);
5442 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5443 outSISIDXREG(SISCR, 0x82, 0x77);
5444 outSISIDXREG(SISCR, 0x85, 0x00);
5445 inSISIDXREG(SISCR, 0x85, reg);
5446 outSISIDXREG(SISCR, 0x85, 0x88);
5447 inSISIDXREG(SISCR, 0x85, reg);
5448 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5449 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5451 if(ivideo->chip == XGI_40) {
5452 outSISIDXREG(SISCR, 0x97, 0x00);
5454 outSISIDXREG(SISCR, 0x98, 0x01);
5455 outSISIDXREG(SISCR, 0x9a, 0x02);
5457 outSISIDXREG(SISSR, 0x18, 0x01);
5458 if((ivideo->chip == XGI_20) ||
5459 (ivideo->revision_id == 2)) {
5460 outSISIDXREG(SISSR, 0x19, 0x40);
5461 } else {
5462 outSISIDXREG(SISSR, 0x19, 0x20);
5464 outSISIDXREG(SISSR, 0x16, 0x00);
5465 outSISIDXREG(SISSR, 0x16, 0x80);
5466 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5467 sisfb_post_xgi_delay(ivideo, 0x43);
5468 sisfb_post_xgi_delay(ivideo, 0x43);
5469 sisfb_post_xgi_delay(ivideo, 0x43);
5470 outSISIDXREG(SISSR, 0x18, 0x00);
5471 if((ivideo->chip == XGI_20) ||
5472 (ivideo->revision_id == 2)) {
5473 outSISIDXREG(SISSR, 0x19, 0x40);
5474 } else {
5475 outSISIDXREG(SISSR, 0x19, 0x20);
5477 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5478 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5480 outSISIDXREG(SISSR, 0x16, 0x00);
5481 outSISIDXREG(SISSR, 0x16, 0x80);
5482 sisfb_post_xgi_delay(ivideo, 4);
5483 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5484 if(ivideo->haveXGIROM) {
5485 v1 = bios[0xf0];
5486 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5487 v2 = bios[index];
5488 v3 = bios[index + 1];
5489 v4 = bios[index + 2];
5490 v5 = bios[index + 3];
5492 outSISIDXREG(SISSR, 0x18, v1);
5493 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5494 outSISIDXREG(SISSR, 0x16, v2);
5495 outSISIDXREG(SISSR, 0x16, v3);
5496 sisfb_post_xgi_delay(ivideo, 0x43);
5497 outSISIDXREG(SISSR, 0x1b, 0x03);
5498 sisfb_post_xgi_delay(ivideo, 0x22);
5499 outSISIDXREG(SISSR, 0x18, v1);
5500 outSISIDXREG(SISSR, 0x19, 0x00);
5501 outSISIDXREG(SISSR, 0x16, v4);
5502 outSISIDXREG(SISSR, 0x16, v5);
5503 outSISIDXREG(SISSR, 0x1b, 0x00);
5504 break;
5505 case 1:
5506 outSISIDXREG(SISCR, 0x82, 0x77);
5507 outSISIDXREG(SISCR, 0x86, 0x00);
5508 inSISIDXREG(SISCR, 0x86, reg);
5509 outSISIDXREG(SISCR, 0x86, 0x88);
5510 inSISIDXREG(SISCR, 0x86, reg);
5511 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5512 if(ivideo->haveXGIROM) {
5513 v1 = bios[regb + 0x168];
5514 v2 = bios[regb + 0x160];
5515 v3 = bios[regb + 0x158];
5517 outSISIDXREG(SISCR, 0x86, v1);
5518 outSISIDXREG(SISCR, 0x82, 0x77);
5519 outSISIDXREG(SISCR, 0x85, 0x00);
5520 inSISIDXREG(SISCR, 0x85, reg);
5521 outSISIDXREG(SISCR, 0x85, 0x88);
5522 inSISIDXREG(SISCR, 0x85, reg);
5523 outSISIDXREG(SISCR, 0x85, v2);
5524 outSISIDXREG(SISCR, 0x82, v3);
5525 outSISIDXREG(SISCR, 0x98, 0x01);
5526 outSISIDXREG(SISCR, 0x9a, 0x02);
5528 outSISIDXREG(SISSR, 0x28, 0x64);
5529 outSISIDXREG(SISSR, 0x29, 0x63);
5530 sisfb_post_xgi_delay(ivideo, 15);
5531 outSISIDXREG(SISSR, 0x18, 0x00);
5532 outSISIDXREG(SISSR, 0x19, 0x20);
5533 outSISIDXREG(SISSR, 0x16, 0x00);
5534 outSISIDXREG(SISSR, 0x16, 0x80);
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(SISCR, 0x97,0x11);
5541 sisfb_post_xgi_setclocks(ivideo, regb);
5542 sisfb_post_xgi_delay(ivideo, 0x46);
5543 outSISIDXREG(SISSR, 0x18, 0xc5);
5544 outSISIDXREG(SISSR, 0x19, 0x23);
5545 outSISIDXREG(SISSR, 0x16, 0x00);
5546 outSISIDXREG(SISSR, 0x16, 0x80);
5547 sisfb_post_xgi_delay(ivideo, 1);
5548 outSISIDXREG(SISSR, 0x1b, 0x04);
5549 sisfb_post_xgi_delay(ivideo, 1);
5550 outSISIDXREG(SISSR, 0x1b, 0x00);
5551 sisfb_post_xgi_delay(ivideo, 1);
5552 v1 = 0x31;
5553 if(ivideo->haveXGIROM) {
5554 v1 = bios[0xf0];
5556 outSISIDXREG(SISSR, 0x18, v1);
5557 outSISIDXREG(SISSR, 0x19, 0x06);
5558 outSISIDXREG(SISSR, 0x16, 0x04);
5559 outSISIDXREG(SISSR, 0x16, 0x84);
5560 sisfb_post_xgi_delay(ivideo, 1);
5561 break;
5562 default:
5563 sisfb_post_xgi_setclocks(ivideo, regb);
5564 if((ivideo->chip == XGI_40) &&
5565 ((ivideo->revision_id == 1) ||
5566 (ivideo->revision_id == 2))) {
5567 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5568 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5569 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5570 } else {
5571 outSISIDXREG(SISCR, 0x82, 0x88);
5572 outSISIDXREG(SISCR, 0x86, 0x00);
5573 inSISIDXREG(SISCR, 0x86, reg);
5574 outSISIDXREG(SISCR, 0x86, 0x88);
5575 outSISIDXREG(SISCR, 0x82, 0x77);
5576 outSISIDXREG(SISCR, 0x85, 0x00);
5577 inSISIDXREG(SISCR, 0x85, reg);
5578 outSISIDXREG(SISCR, 0x85, 0x88);
5579 inSISIDXREG(SISCR, 0x85, reg);
5580 v1 = cs160[regb]; v2 = cs158[regb];
5581 if(ivideo->haveXGIROM) {
5582 v1 = bios[regb + 0x160];
5583 v2 = bios[regb + 0x158];
5585 outSISIDXREG(SISCR, 0x85, v1);
5586 outSISIDXREG(SISCR, 0x82, v2);
5588 if(ivideo->chip == XGI_40) {
5589 outSISIDXREG(SISCR, 0x97, 0x11);
5591 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5592 outSISIDXREG(SISCR, 0x98, 0x01);
5593 } else {
5594 outSISIDXREG(SISCR, 0x98, 0x03);
5596 outSISIDXREG(SISCR, 0x9a, 0x02);
5598 if(ivideo->chip == XGI_40) {
5599 outSISIDXREG(SISSR, 0x18, 0x01);
5600 } else {
5601 outSISIDXREG(SISSR, 0x18, 0x00);
5603 outSISIDXREG(SISSR, 0x19, 0x40);
5604 outSISIDXREG(SISSR, 0x16, 0x00);
5605 outSISIDXREG(SISSR, 0x16, 0x80);
5606 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5607 sisfb_post_xgi_delay(ivideo, 0x43);
5608 sisfb_post_xgi_delay(ivideo, 0x43);
5609 sisfb_post_xgi_delay(ivideo, 0x43);
5610 outSISIDXREG(SISSR, 0x18, 0x00);
5611 outSISIDXREG(SISSR, 0x19, 0x40);
5612 outSISIDXREG(SISSR, 0x16, 0x00);
5613 outSISIDXREG(SISSR, 0x16, 0x80);
5615 sisfb_post_xgi_delay(ivideo, 4);
5616 v1 = 0x31;
5617 if(ivideo->haveXGIROM) {
5618 v1 = bios[0xf0];
5620 outSISIDXREG(SISSR, 0x18, v1);
5621 outSISIDXREG(SISSR, 0x19, 0x01);
5622 if(ivideo->chip == XGI_40) {
5623 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5624 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5625 } else {
5626 outSISIDXREG(SISSR, 0x16, 0x05);
5627 outSISIDXREG(SISSR, 0x16, 0x85);
5629 sisfb_post_xgi_delay(ivideo, 0x43);
5630 if(ivideo->chip == XGI_40) {
5631 outSISIDXREG(SISSR, 0x1b, 0x01);
5632 } else {
5633 outSISIDXREG(SISSR, 0x1b, 0x03);
5635 sisfb_post_xgi_delay(ivideo, 0x22);
5636 outSISIDXREG(SISSR, 0x18, v1);
5637 outSISIDXREG(SISSR, 0x19, 0x00);
5638 if(ivideo->chip == XGI_40) {
5639 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5640 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5641 } else {
5642 outSISIDXREG(SISSR, 0x16, 0x05);
5643 outSISIDXREG(SISSR, 0x16, 0x85);
5645 outSISIDXREG(SISSR, 0x1b, 0x00);
5648 regb = 0; /* ! */
5649 v1 = 0x03;
5650 if(ivideo->haveXGIROM) {
5651 v1 = bios[0x110 + regb];
5653 outSISIDXREG(SISSR, 0x1b, v1);
5655 /* RAM size */
5656 v1 = 0x00; v2 = 0x00;
5657 if(ivideo->haveXGIROM) {
5658 v1 = bios[0x62];
5659 v2 = bios[0x63];
5661 regb = 0; /* ! */
5662 regd = 1 << regb;
5663 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5665 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5666 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5668 } else {
5670 /* Set default mode, don't clear screen */
5671 ivideo->SiS_Pr.SiS_UseOEM = false;
5672 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5673 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5674 ivideo->curFSTN = ivideo->curDSTN = 0;
5675 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5676 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5678 outSISIDXREG(SISSR, 0x05, 0x86);
5680 /* Disable read-cache */
5681 andSISIDXREG(SISSR, 0x21, 0xdf);
5682 sisfb_post_xgi_ramsize(ivideo);
5683 /* Enable read-cache */
5684 orSISIDXREG(SISSR, 0x21, 0x20);
5688 #if 0
5689 printk(KERN_DEBUG "-----------------\n");
5690 for(i = 0; i < 0xff; i++) {
5691 inSISIDXREG(SISCR, i, reg);
5692 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5694 for(i = 0; i < 0x40; i++) {
5695 inSISIDXREG(SISSR, i, reg);
5696 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5698 printk(KERN_DEBUG "-----------------\n");
5699 #endif
5701 /* Sense CRT1 */
5702 if(ivideo->chip == XGI_20) {
5703 orSISIDXREG(SISCR, 0x32, 0x20);
5704 } else {
5705 inSISIDXREG(SISPART4, 0x00, reg);
5706 if((reg == 1) || (reg == 2)) {
5707 sisfb_sense_crt1(ivideo);
5708 } else {
5709 orSISIDXREG(SISCR, 0x32, 0x20);
5713 /* Set default mode, don't clear screen */
5714 ivideo->SiS_Pr.SiS_UseOEM = false;
5715 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5716 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5717 ivideo->curFSTN = ivideo->curDSTN = 0;
5718 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5720 outSISIDXREG(SISSR, 0x05, 0x86);
5722 /* Display off */
5723 orSISIDXREG(SISSR, 0x01, 0x20);
5725 /* Save mode number in CR34 */
5726 outSISIDXREG(SISCR, 0x34, 0x2e);
5728 /* Let everyone know what the current mode is */
5729 ivideo->modeprechange = 0x2e;
5731 if(ivideo->chip == XGI_40) {
5732 inSISIDXREG(SISCR, 0xca, reg);
5733 inSISIDXREG(SISCR, 0xcc, v1);
5734 if((reg & 0x10) && (!(v1 & 0x04))) {
5735 printk(KERN_ERR
5736 "sisfb: Please connect power to the card.\n");
5737 return 0;
5741 return 1;
5743 #endif
5745 static int __devinit
5746 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5748 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5749 struct sis_video_info *ivideo = NULL;
5750 struct fb_info *sis_fb_info = NULL;
5751 u16 reg16;
5752 u8 reg;
5753 int i, ret;
5755 if(sisfb_off)
5756 return -ENXIO;
5758 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5759 if(!sis_fb_info)
5760 return -ENOMEM;
5762 ivideo = (struct sis_video_info *)sis_fb_info->par;
5763 ivideo->memyselfandi = sis_fb_info;
5765 ivideo->sisfb_id = SISFB_ID;
5767 if(card_list == NULL) {
5768 ivideo->cardnumber = 0;
5769 } else {
5770 struct sis_video_info *countvideo = card_list;
5771 ivideo->cardnumber = 1;
5772 while((countvideo = countvideo->next) != NULL)
5773 ivideo->cardnumber++;
5776 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5778 ivideo->warncount = 0;
5779 ivideo->chip_id = pdev->device;
5780 ivideo->chip_vendor = pdev->vendor;
5781 ivideo->revision_id = pdev->revision;
5782 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5783 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
5784 ivideo->sisvga_enabled = reg16 & 0x01;
5785 ivideo->pcibus = pdev->bus->number;
5786 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5787 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5788 ivideo->subsysvendor = pdev->subsystem_vendor;
5789 ivideo->subsysdevice = pdev->subsystem_device;
5791 #ifndef MODULE
5792 if(sisfb_mode_idx == -1) {
5793 sisfb_get_vga_mode_from_kernel();
5795 #endif
5797 ivideo->chip = chipinfo->chip;
5798 ivideo->sisvga_engine = chipinfo->vgaengine;
5799 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5800 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5801 ivideo->mni = chipinfo->mni;
5803 ivideo->detectedpdc = 0xff;
5804 ivideo->detectedpdca = 0xff;
5805 ivideo->detectedlcda = 0xff;
5807 ivideo->sisfb_thismonitor.datavalid = false;
5809 ivideo->current_base = 0;
5811 ivideo->engineok = 0;
5813 ivideo->sisfb_was_boot_device = 0;
5815 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5816 if(ivideo->sisvga_enabled)
5817 ivideo->sisfb_was_boot_device = 1;
5818 else {
5819 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5820 "but marked as boot video device ???\n");
5821 printk(KERN_DEBUG "sisfb: I will not accept this "
5822 "as the primary VGA device\n");
5826 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5827 ivideo->sisfb_accel = sisfb_accel;
5828 ivideo->sisfb_ypan = sisfb_ypan;
5829 ivideo->sisfb_max = sisfb_max;
5830 ivideo->sisfb_userom = sisfb_userom;
5831 ivideo->sisfb_useoem = sisfb_useoem;
5832 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5833 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5834 ivideo->sisfb_crt1off = sisfb_crt1off;
5835 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5836 ivideo->sisfb_crt2type = sisfb_crt2type;
5837 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5838 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5839 ivideo->sisfb_dstn = sisfb_dstn;
5840 ivideo->sisfb_fstn = sisfb_fstn;
5841 ivideo->sisfb_tvplug = sisfb_tvplug;
5842 ivideo->sisfb_tvstd = sisfb_tvstd;
5843 ivideo->tvxpos = sisfb_tvxposoffset;
5844 ivideo->tvypos = sisfb_tvyposoffset;
5845 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5846 ivideo->refresh_rate = 0;
5847 if(ivideo->sisfb_parm_rate != -1) {
5848 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5851 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5852 ivideo->SiS_Pr.CenterScreen = -1;
5853 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5854 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5856 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5857 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5858 ivideo->SiS_Pr.SiS_ChSW = false;
5859 ivideo->SiS_Pr.SiS_UseLCDA = false;
5860 ivideo->SiS_Pr.HaveEMI = false;
5861 ivideo->SiS_Pr.HaveEMILCD = false;
5862 ivideo->SiS_Pr.OverruleEMI = false;
5863 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
5864 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5865 ivideo->SiS_Pr.PDC = -1;
5866 ivideo->SiS_Pr.PDCA = -1;
5867 ivideo->SiS_Pr.DDCPortMixup = false;
5868 #ifdef CONFIG_FB_SIS_315
5869 if(ivideo->chip >= SIS_330) {
5870 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5871 if(ivideo->chip >= SIS_661) {
5872 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
5875 #endif
5877 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5879 pci_set_drvdata(pdev, ivideo);
5881 /* Patch special cases */
5882 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5883 switch(ivideo->nbridge->device) {
5884 #ifdef CONFIG_FB_SIS_300
5885 case PCI_DEVICE_ID_SI_730:
5886 ivideo->chip = SIS_730;
5887 strcpy(ivideo->myid, "SiS 730");
5888 break;
5889 #endif
5890 #ifdef CONFIG_FB_SIS_315
5891 case PCI_DEVICE_ID_SI_651:
5892 /* ivideo->chip is ok */
5893 strcpy(ivideo->myid, "SiS 651");
5894 break;
5895 case PCI_DEVICE_ID_SI_740:
5896 ivideo->chip = SIS_740;
5897 strcpy(ivideo->myid, "SiS 740");
5898 break;
5899 case PCI_DEVICE_ID_SI_661:
5900 ivideo->chip = SIS_661;
5901 strcpy(ivideo->myid, "SiS 661");
5902 break;
5903 case PCI_DEVICE_ID_SI_741:
5904 ivideo->chip = SIS_741;
5905 strcpy(ivideo->myid, "SiS 741");
5906 break;
5907 case PCI_DEVICE_ID_SI_760:
5908 ivideo->chip = SIS_760;
5909 strcpy(ivideo->myid, "SiS 760");
5910 break;
5911 case PCI_DEVICE_ID_SI_761:
5912 ivideo->chip = SIS_761;
5913 strcpy(ivideo->myid, "SiS 761");
5914 break;
5915 #endif
5916 default:
5917 break;
5921 ivideo->SiS_Pr.ChipType = ivideo->chip;
5923 ivideo->SiS_Pr.ivideo = (void *)ivideo;
5925 #ifdef CONFIG_FB_SIS_315
5926 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5927 (ivideo->SiS_Pr.ChipType == SIS_315)) {
5928 ivideo->SiS_Pr.ChipType = SIS_315H;
5930 #endif
5932 if(!ivideo->sisvga_enabled) {
5933 if(pci_enable_device(pdev)) {
5934 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
5935 pci_set_drvdata(pdev, NULL);
5936 framebuffer_release(sis_fb_info);
5937 return -EIO;
5941 ivideo->video_base = pci_resource_start(pdev, 0);
5942 ivideo->mmio_base = pci_resource_start(pdev, 1);
5943 ivideo->mmio_size = pci_resource_len(pdev, 1);
5944 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
5945 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
5947 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
5949 #ifdef CONFIG_FB_SIS_300
5950 /* Find PCI systems for Chrontel/GPIO communication setup */
5951 if(ivideo->chip == SIS_630) {
5952 i = 0;
5953 do {
5954 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5955 mychswtable[i].subsysCard == ivideo->subsysdevice) {
5956 ivideo->SiS_Pr.SiS_ChSW = true;
5957 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5958 "requiring Chrontel/GPIO setup\n",
5959 mychswtable[i].vendorName,
5960 mychswtable[i].cardName);
5961 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
5962 break;
5964 i++;
5965 } while(mychswtable[i].subsysVendor != 0);
5967 #endif
5969 #ifdef CONFIG_FB_SIS_315
5970 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
5971 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
5973 #endif
5975 outSISIDXREG(SISSR, 0x05, 0x86);
5977 if( (!ivideo->sisvga_enabled)
5978 #if !defined(__i386__) && !defined(__x86_64__)
5979 || (sisfb_resetcard)
5980 #endif
5982 for(i = 0x30; i <= 0x3f; i++) {
5983 outSISIDXREG(SISCR, i, 0x00);
5987 /* Find out about current video mode */
5988 ivideo->modeprechange = 0x03;
5989 inSISIDXREG(SISCR, 0x34, reg);
5990 if(reg & 0x7f) {
5991 ivideo->modeprechange = reg & 0x7f;
5992 } else if(ivideo->sisvga_enabled) {
5993 #if defined(__i386__) || defined(__x86_64__)
5994 unsigned char __iomem *tt = ioremap(0x400, 0x100);
5995 if(tt) {
5996 ivideo->modeprechange = readb(tt + 0x49);
5997 iounmap(tt);
5999 #endif
6002 /* Search and copy ROM image */
6003 ivideo->bios_abase = NULL;
6004 ivideo->SiS_Pr.VirtualRomBase = NULL;
6005 ivideo->SiS_Pr.UseROM = false;
6006 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
6007 if(ivideo->sisfb_userom) {
6008 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6009 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6010 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
6011 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6012 ivideo->SiS_Pr.UseROM ? "" : "not ");
6013 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6014 ivideo->SiS_Pr.UseROM = false;
6015 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
6016 if( (ivideo->revision_id == 2) &&
6017 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6018 ivideo->SiS_Pr.DDCPortMixup = true;
6021 } else {
6022 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6025 /* Find systems for special custom timing */
6026 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6027 sisfb_detect_custom_timing(ivideo);
6030 /* POST card in case this has not been done by the BIOS */
6031 if( (!ivideo->sisvga_enabled)
6032 #if !defined(__i386__) && !defined(__x86_64__)
6033 || (sisfb_resetcard)
6034 #endif
6036 #ifdef CONFIG_FB_SIS_300
6037 if(ivideo->sisvga_engine == SIS_300_VGA) {
6038 if(ivideo->chip == SIS_300) {
6039 sisfb_post_sis300(pdev);
6040 ivideo->sisfb_can_post = 1;
6043 #endif
6045 #ifdef CONFIG_FB_SIS_315
6046 if(ivideo->sisvga_engine == SIS_315_VGA) {
6047 int result = 1;
6048 /* if((ivideo->chip == SIS_315H) ||
6049 (ivideo->chip == SIS_315) ||
6050 (ivideo->chip == SIS_315PRO) ||
6051 (ivideo->chip == SIS_330)) {
6052 sisfb_post_sis315330(pdev);
6053 } else */ if(ivideo->chip == XGI_20) {
6054 result = sisfb_post_xgi(pdev);
6055 ivideo->sisfb_can_post = 1;
6056 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6057 result = sisfb_post_xgi(pdev);
6058 ivideo->sisfb_can_post = 1;
6059 } else {
6060 printk(KERN_INFO "sisfb: Card is not "
6061 "POSTed and sisfb can't do this either.\n");
6063 if(!result) {
6064 printk(KERN_ERR "sisfb: Failed to POST card\n");
6065 ret = -ENODEV;
6066 goto error_3;
6069 #endif
6072 ivideo->sisfb_card_posted = 1;
6074 /* Find out about RAM size */
6075 if(sisfb_get_dram_size(ivideo)) {
6076 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6077 ret = -ENODEV;
6078 goto error_3;
6082 /* Enable PCI addressing and MMIO */
6083 if((ivideo->sisfb_mode_idx < 0) ||
6084 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6085 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6086 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6087 /* Enable 2D accelerator engine */
6088 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6091 if(sisfb_pdc != 0xff) {
6092 if(ivideo->sisvga_engine == SIS_300_VGA)
6093 sisfb_pdc &= 0x3c;
6094 else
6095 sisfb_pdc &= 0x1f;
6096 ivideo->SiS_Pr.PDC = sisfb_pdc;
6098 #ifdef CONFIG_FB_SIS_315
6099 if(ivideo->sisvga_engine == SIS_315_VGA) {
6100 if(sisfb_pdca != 0xff)
6101 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6103 #endif
6105 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6106 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6107 (int)(ivideo->video_size >> 20));
6108 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6109 ret = -ENODEV;
6110 goto error_3;
6113 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6114 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6115 ret = -ENODEV;
6116 goto error_2;
6119 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6120 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6121 if(!ivideo->video_vbase) {
6122 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6123 ret = -ENODEV;
6124 goto error_1;
6127 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6128 if(!ivideo->mmio_vbase) {
6129 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6130 ret = -ENODEV;
6131 error_0: iounmap(ivideo->video_vbase);
6132 error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6133 error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6134 error_3: vfree(ivideo->bios_abase);
6135 if(ivideo->lpcdev)
6136 pci_dev_put(ivideo->lpcdev);
6137 if(ivideo->nbridge)
6138 pci_dev_put(ivideo->nbridge);
6139 pci_set_drvdata(pdev, NULL);
6140 if(!ivideo->sisvga_enabled)
6141 pci_disable_device(pdev);
6142 framebuffer_release(sis_fb_info);
6143 return ret;
6146 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6147 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6149 if(ivideo->video_offset) {
6150 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6151 ivideo->video_offset / 1024);
6154 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6155 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6158 /* Determine the size of the command queue */
6159 if(ivideo->sisvga_engine == SIS_300_VGA) {
6160 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6161 } else {
6162 if(ivideo->chip == XGI_20) {
6163 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6164 } else {
6165 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6169 /* Engines are no longer initialized here; this is
6170 * now done after the first mode-switch (if the
6171 * submitted var has its acceleration flags set).
6174 /* Calculate the base of the (unused) hw cursor */
6175 ivideo->hwcursor_vbase = ivideo->video_vbase
6176 + ivideo->video_size
6177 - ivideo->cmdQueueSize
6178 - ivideo->hwcursor_size;
6179 ivideo->caps |= HW_CURSOR_CAP;
6181 /* Initialize offscreen memory manager */
6182 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6183 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6186 /* Used for clearing the screen only, therefore respect our mem limit */
6187 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6188 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6190 ivideo->mtrr = -1;
6192 ivideo->vbflags = 0;
6193 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6194 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6195 ivideo->defmodeidx = DEFAULT_MODE;
6197 ivideo->newrom = 0;
6198 if(ivideo->chip < XGI_20) {
6199 if(ivideo->bios_abase) {
6200 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6204 if((ivideo->sisfb_mode_idx < 0) ||
6205 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6207 sisfb_sense_crt1(ivideo);
6209 sisfb_get_VB_type(ivideo);
6211 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6212 sisfb_detect_VB_connect(ivideo);
6215 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6217 /* Decide on which CRT2 device to use */
6218 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6219 if(ivideo->sisfb_crt2type != -1) {
6220 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6221 (ivideo->vbflags & CRT2_LCD)) {
6222 ivideo->currentvbflags |= CRT2_LCD;
6223 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6224 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6226 } else {
6227 /* Chrontel 700x TV detection often unreliable, therefore
6228 * use a different default order on such machines
6230 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6231 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6232 if(ivideo->vbflags & CRT2_LCD)
6233 ivideo->currentvbflags |= CRT2_LCD;
6234 else if(ivideo->vbflags & CRT2_TV)
6235 ivideo->currentvbflags |= CRT2_TV;
6236 else if(ivideo->vbflags & CRT2_VGA)
6237 ivideo->currentvbflags |= CRT2_VGA;
6238 } else {
6239 if(ivideo->vbflags & CRT2_TV)
6240 ivideo->currentvbflags |= CRT2_TV;
6241 else if(ivideo->vbflags & CRT2_LCD)
6242 ivideo->currentvbflags |= CRT2_LCD;
6243 else if(ivideo->vbflags & CRT2_VGA)
6244 ivideo->currentvbflags |= CRT2_VGA;
6249 if(ivideo->vbflags & CRT2_LCD) {
6250 sisfb_detect_lcd_type(ivideo);
6253 sisfb_save_pdc_emi(ivideo);
6255 if(!ivideo->sisfb_crt1off) {
6256 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6257 } else {
6258 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6259 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6260 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6264 if(ivideo->sisfb_mode_idx >= 0) {
6265 int bu = ivideo->sisfb_mode_idx;
6266 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6267 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6268 if(bu != ivideo->sisfb_mode_idx) {
6269 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6270 sisbios_mode[bu].xres,
6271 sisbios_mode[bu].yres,
6272 sisbios_mode[bu].bpp);
6276 if(ivideo->sisfb_mode_idx < 0) {
6277 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6278 case CRT2_LCD:
6279 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6280 break;
6281 case CRT2_TV:
6282 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6283 break;
6284 default:
6285 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6286 break;
6290 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6292 if(ivideo->refresh_rate != 0) {
6293 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6294 ivideo->sisfb_mode_idx);
6297 if(ivideo->rate_idx == 0) {
6298 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6299 ivideo->refresh_rate = 60;
6302 if(ivideo->sisfb_thismonitor.datavalid) {
6303 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6304 ivideo->sisfb_mode_idx,
6305 ivideo->rate_idx,
6306 ivideo->refresh_rate)) {
6307 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6308 "exceeds monitor specs!\n");
6312 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6313 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6314 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6316 sisfb_set_vparms(ivideo);
6318 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6319 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6320 ivideo->refresh_rate);
6322 /* Set up the default var according to chosen default display mode */
6323 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6324 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6325 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6327 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6329 ivideo->default_var.pixclock = (u32) (1000000000 /
6330 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6332 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6333 ivideo->rate_idx, &ivideo->default_var)) {
6334 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6335 ivideo->default_var.pixclock <<= 1;
6339 if(ivideo->sisfb_ypan) {
6340 /* Maximize regardless of sisfb_max at startup */
6341 ivideo->default_var.yres_virtual =
6342 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6343 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6344 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6348 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6350 ivideo->accel = 0;
6351 if(ivideo->sisfb_accel) {
6352 ivideo->accel = -1;
6353 #ifdef STUPID_ACCELF_TEXT_SHIT
6354 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6355 #endif
6357 sisfb_initaccel(ivideo);
6359 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6360 sis_fb_info->flags = FBINFO_DEFAULT |
6361 FBINFO_HWACCEL_YPAN |
6362 FBINFO_HWACCEL_XPAN |
6363 FBINFO_HWACCEL_COPYAREA |
6364 FBINFO_HWACCEL_FILLRECT |
6365 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6366 #else
6367 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6368 #endif
6369 sis_fb_info->var = ivideo->default_var;
6370 sis_fb_info->fix = ivideo->sisfb_fix;
6371 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6372 sis_fb_info->fbops = &sisfb_ops;
6373 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6375 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6377 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6379 #ifdef CONFIG_MTRR
6380 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6381 MTRR_TYPE_WRCOMB, 1);
6382 if(ivideo->mtrr < 0) {
6383 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6385 #endif
6387 if(register_framebuffer(sis_fb_info) < 0) {
6388 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6389 ret = -EINVAL;
6390 iounmap(ivideo->mmio_vbase);
6391 goto error_0;
6394 ivideo->registered = 1;
6396 /* Enlist us */
6397 ivideo->next = card_list;
6398 card_list = ivideo;
6400 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6401 ivideo->sisfb_accel ? "enabled" : "disabled",
6402 ivideo->sisfb_ypan ?
6403 (ivideo->sisfb_max ? "enabled (auto-max)" :
6404 "enabled (no auto-max)") :
6405 "disabled");
6408 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6409 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6411 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6413 } /* if mode = "none" */
6415 return 0;
6418 /*****************************************************/
6419 /* PCI DEVICE HANDLING */
6420 /*****************************************************/
6422 static void __devexit sisfb_remove(struct pci_dev *pdev)
6424 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6425 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6426 int registered = ivideo->registered;
6427 int modechanged = ivideo->modechanged;
6429 /* Unmap */
6430 iounmap(ivideo->mmio_vbase);
6431 iounmap(ivideo->video_vbase);
6433 /* Release mem regions */
6434 release_mem_region(ivideo->video_base, ivideo->video_size);
6435 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6437 vfree(ivideo->bios_abase);
6439 if(ivideo->lpcdev)
6440 pci_dev_put(ivideo->lpcdev);
6442 if(ivideo->nbridge)
6443 pci_dev_put(ivideo->nbridge);
6445 #ifdef CONFIG_MTRR
6446 /* Release MTRR region */
6447 if(ivideo->mtrr >= 0)
6448 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6449 #endif
6451 pci_set_drvdata(pdev, NULL);
6453 /* If device was disabled when starting, disable
6454 * it when quitting.
6456 if(!ivideo->sisvga_enabled)
6457 pci_disable_device(pdev);
6459 /* Unregister the framebuffer */
6460 if(ivideo->registered) {
6461 unregister_framebuffer(sis_fb_info);
6462 framebuffer_release(sis_fb_info);
6465 /* OK, our ivideo is gone for good from here. */
6467 /* TODO: Restore the initial mode
6468 * This sounds easy but is as good as impossible
6469 * on many machines with SiS chip and video bridge
6470 * since text modes are always set up differently
6471 * from machine to machine. Depends on the type
6472 * of integration between chipset and bridge.
6474 if(registered && modechanged)
6475 printk(KERN_INFO
6476 "sisfb: Restoring of text mode not supported yet\n");
6479 static struct pci_driver sisfb_driver = {
6480 .name = "sisfb",
6481 .id_table = sisfb_pci_table,
6482 .probe = sisfb_probe,
6483 .remove = __devexit_p(sisfb_remove)
6486 static int __init sisfb_init(void)
6488 #ifndef MODULE
6489 char *options = NULL;
6491 if(fb_get_options("sisfb", &options))
6492 return -ENODEV;
6494 sisfb_setup(options);
6495 #endif
6496 return pci_register_driver(&sisfb_driver);
6499 #ifndef MODULE
6500 module_init(sisfb_init);
6501 #endif
6503 /*****************************************************/
6504 /* MODULE */
6505 /*****************************************************/
6507 #ifdef MODULE
6509 static char *mode = NULL;
6510 static int vesa = -1;
6511 static unsigned int rate = 0;
6512 static unsigned int crt1off = 1;
6513 static unsigned int mem = 0;
6514 static char *forcecrt2type = NULL;
6515 static int forcecrt1 = -1;
6516 static int pdc = -1;
6517 static int pdc1 = -1;
6518 static int noaccel = -1;
6519 static int noypan = -1;
6520 static int nomax = -1;
6521 static int userom = -1;
6522 static int useoem = -1;
6523 static char *tvstandard = NULL;
6524 static int nocrt2rate = 0;
6525 static int scalelcd = -1;
6526 static char *specialtiming = NULL;
6527 static int lvdshl = -1;
6528 static int tvxposoffset = 0, tvyposoffset = 0;
6529 #if !defined(__i386__) && !defined(__x86_64__)
6530 static int resetcard = 0;
6531 static int videoram = 0;
6532 #endif
6534 static int __init sisfb_init_module(void)
6536 sisfb_setdefaultparms();
6538 if(rate)
6539 sisfb_parm_rate = rate;
6541 if((scalelcd == 0) || (scalelcd == 1))
6542 sisfb_scalelcd = scalelcd ^ 1;
6544 /* Need to check crt2 type first for fstn/dstn */
6546 if(forcecrt2type)
6547 sisfb_search_crt2type(forcecrt2type);
6549 if(tvstandard)
6550 sisfb_search_tvstd(tvstandard);
6552 if(mode)
6553 sisfb_search_mode(mode, false);
6554 else if(vesa != -1)
6555 sisfb_search_vesamode(vesa, false);
6557 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6559 sisfb_forcecrt1 = forcecrt1;
6560 if(forcecrt1 == 1)
6561 sisfb_crt1off = 0;
6562 else if(forcecrt1 == 0)
6563 sisfb_crt1off = 1;
6565 if(noaccel == 1)
6566 sisfb_accel = 0;
6567 else if(noaccel == 0)
6568 sisfb_accel = 1;
6570 if(noypan == 1)
6571 sisfb_ypan = 0;
6572 else if(noypan == 0)
6573 sisfb_ypan = 1;
6575 if(nomax == 1)
6576 sisfb_max = 0;
6577 else if(nomax == 0)
6578 sisfb_max = 1;
6580 if(mem)
6581 sisfb_parm_mem = mem;
6583 if(userom != -1)
6584 sisfb_userom = userom;
6586 if(useoem != -1)
6587 sisfb_useoem = useoem;
6589 if(pdc != -1)
6590 sisfb_pdc = (pdc & 0x7f);
6592 if(pdc1 != -1)
6593 sisfb_pdca = (pdc1 & 0x1f);
6595 sisfb_nocrt2rate = nocrt2rate;
6597 if(specialtiming)
6598 sisfb_search_specialtiming(specialtiming);
6600 if((lvdshl >= 0) && (lvdshl <= 3))
6601 sisfb_lvdshl = lvdshl;
6603 sisfb_tvxposoffset = tvxposoffset;
6604 sisfb_tvyposoffset = tvyposoffset;
6606 #if !defined(__i386__) && !defined(__x86_64__)
6607 sisfb_resetcard = (resetcard) ? 1 : 0;
6608 if(videoram)
6609 sisfb_videoram = videoram;
6610 #endif
6612 return sisfb_init();
6615 static void __exit sisfb_remove_module(void)
6617 pci_unregister_driver(&sisfb_driver);
6618 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6621 module_init(sisfb_init_module);
6622 module_exit(sisfb_remove_module);
6624 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6625 MODULE_LICENSE("GPL");
6626 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6628 module_param(mem, int, 0);
6629 module_param(noaccel, int, 0);
6630 module_param(noypan, int, 0);
6631 module_param(nomax, int, 0);
6632 module_param(userom, int, 0);
6633 module_param(useoem, int, 0);
6634 module_param(mode, charp, 0);
6635 module_param(vesa, int, 0);
6636 module_param(rate, int, 0);
6637 module_param(forcecrt1, int, 0);
6638 module_param(forcecrt2type, charp, 0);
6639 module_param(scalelcd, int, 0);
6640 module_param(pdc, int, 0);
6641 module_param(pdc1, int, 0);
6642 module_param(specialtiming, charp, 0);
6643 module_param(lvdshl, int, 0);
6644 module_param(tvstandard, charp, 0);
6645 module_param(tvxposoffset, int, 0);
6646 module_param(tvyposoffset, int, 0);
6647 module_param(nocrt2rate, int, 0);
6648 #if !defined(__i386__) && !defined(__x86_64__)
6649 module_param(resetcard, int, 0);
6650 module_param(videoram, int, 0);
6651 #endif
6653 MODULE_PARM_DESC(mem,
6654 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6655 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6656 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6657 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6658 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6659 "The value is to be specified without 'KB'.\n");
6661 MODULE_PARM_DESC(noaccel,
6662 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6663 "(default: 0)\n");
6665 MODULE_PARM_DESC(noypan,
6666 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6667 "will be performed by redrawing the screen. (default: 0)\n");
6669 MODULE_PARM_DESC(nomax,
6670 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
6671 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6672 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6673 "enable the user to positively specify a virtual Y size of the screen using\n"
6674 "fbset. (default: 0)\n");
6676 MODULE_PARM_DESC(mode,
6677 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6678 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
6679 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6680 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6682 MODULE_PARM_DESC(vesa,
6683 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6684 "0x117 (default: 0x0103)\n");
6686 MODULE_PARM_DESC(rate,
6687 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6688 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6689 "will be ignored (default: 60)\n");
6691 MODULE_PARM_DESC(forcecrt1,
6692 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6693 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6694 "0=CRT1 OFF) (default: [autodetected])\n");
6696 MODULE_PARM_DESC(forcecrt2type,
6697 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6698 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6699 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6700 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6701 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6702 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6703 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6704 "depends on the very hardware in use. (default: [autodetected])\n");
6706 MODULE_PARM_DESC(scalelcd,
6707 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6708 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6709 "show black bars around the image, TMDS panels will probably do the scaling\n"
6710 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6712 MODULE_PARM_DESC(pdc,
6713 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
6714 "should detect this correctly in most cases; however, sometimes this is not\n"
6715 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
6716 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6717 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6718 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
6720 #ifdef CONFIG_FB_SIS_315
6721 MODULE_PARM_DESC(pdc1,
6722 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
6723 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6724 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6725 "implemented yet.\n");
6726 #endif
6728 MODULE_PARM_DESC(specialtiming,
6729 "\nPlease refer to documentation for more information on this option.\n");
6731 MODULE_PARM_DESC(lvdshl,
6732 "\nPlease refer to documentation for more information on this option.\n");
6734 MODULE_PARM_DESC(tvstandard,
6735 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6736 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6738 MODULE_PARM_DESC(tvxposoffset,
6739 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6740 "Default: 0\n");
6742 MODULE_PARM_DESC(tvyposoffset,
6743 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6744 "Default: 0\n");
6746 MODULE_PARM_DESC(nocrt2rate,
6747 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6748 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6750 #if !defined(__i386__) && !defined(__x86_64__)
6751 #ifdef CONFIG_FB_SIS_300
6752 MODULE_PARM_DESC(resetcard,
6753 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
6754 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6755 "currently). Default: 0\n");
6757 MODULE_PARM_DESC(videoram,
6758 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6759 "some non-x86 architectures where the memory auto detection fails. Only\n"
6760 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
6761 #endif
6762 #endif
6764 #endif /* /MODULE */
6766 /* _GPL only for new symbols. */
6767 EXPORT_SYMBOL(sis_malloc);
6768 EXPORT_SYMBOL(sis_free);
6769 EXPORT_SYMBOL_GPL(sis_malloc_new);
6770 EXPORT_SYMBOL_GPL(sis_free_new);