V4L/DVB: media/IR/imon: testing the wrong variable
[wandboard.git] / drivers / video / sis / sis_main.c
bloba531a0f7cdf2d7ba27e0f44b8028efa0307d7ab2
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:
1704 sisvbblank.count = 0;
1705 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1707 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1708 return -EFAULT;
1710 break;
1712 case SISFB_GET_INFO_SIZE:
1713 return put_user(sizeof(struct sisfb_info), argp);
1715 case SISFB_GET_INFO_OLD:
1716 if(ivideo->warncount++ < 10)
1717 printk(KERN_INFO
1718 "sisfb: Deprecated ioctl call received - update your application!\n");
1719 case SISFB_GET_INFO: /* For communication with X driver */
1720 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1721 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1722 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1723 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1724 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1725 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1726 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1727 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1728 if(ivideo->modechanged) {
1729 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1730 } else {
1731 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1733 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1734 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1735 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1736 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1737 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1738 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1739 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1740 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1741 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1742 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1743 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1744 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1745 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1746 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1747 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1748 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1749 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1750 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1751 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1752 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1753 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1754 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1755 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1756 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1757 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1758 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1759 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1760 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1762 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1763 sizeof(ivideo->sisfb_infoblock)))
1764 return -EFAULT;
1766 break;
1768 case SISFB_GET_VBRSTATUS_OLD:
1769 if(ivideo->warncount++ < 10)
1770 printk(KERN_INFO
1771 "sisfb: Deprecated ioctl call received - update your application!\n");
1772 case SISFB_GET_VBRSTATUS:
1773 if(sisfb_CheckVBRetrace(ivideo))
1774 return put_user((u32)1, argp);
1775 else
1776 return put_user((u32)0, argp);
1778 case SISFB_GET_AUTOMAXIMIZE_OLD:
1779 if(ivideo->warncount++ < 10)
1780 printk(KERN_INFO
1781 "sisfb: Deprecated ioctl call received - update your application!\n");
1782 case SISFB_GET_AUTOMAXIMIZE:
1783 if(ivideo->sisfb_max)
1784 return put_user((u32)1, argp);
1785 else
1786 return put_user((u32)0, argp);
1788 case SISFB_SET_AUTOMAXIMIZE_OLD:
1789 if(ivideo->warncount++ < 10)
1790 printk(KERN_INFO
1791 "sisfb: Deprecated ioctl call received - update your application!\n");
1792 case SISFB_SET_AUTOMAXIMIZE:
1793 if(get_user(gpu32, argp))
1794 return -EFAULT;
1796 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1797 break;
1799 case SISFB_SET_TVPOSOFFSET:
1800 if(get_user(gpu32, argp))
1801 return -EFAULT;
1803 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1804 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1805 break;
1807 case SISFB_GET_TVPOSOFFSET:
1808 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1809 argp);
1811 case SISFB_COMMAND:
1812 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1813 sizeof(struct sisfb_cmd)))
1814 return -EFAULT;
1816 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1818 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1819 sizeof(struct sisfb_cmd)))
1820 return -EFAULT;
1822 break;
1824 case SISFB_SET_LOCK:
1825 if(get_user(gpu32, argp))
1826 return -EFAULT;
1828 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1829 break;
1831 default:
1832 #ifdef SIS_NEW_CONFIG_COMPAT
1833 return -ENOIOCTLCMD;
1834 #else
1835 return -EINVAL;
1836 #endif
1838 return 0;
1841 static int
1842 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1844 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1846 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1848 strcpy(fix->id, ivideo->myid);
1850 mutex_lock(&info->mm_lock);
1851 fix->smem_start = ivideo->video_base + ivideo->video_offset;
1852 fix->smem_len = ivideo->sisfb_mem;
1853 mutex_unlock(&info->mm_lock);
1854 fix->type = FB_TYPE_PACKED_PIXELS;
1855 fix->type_aux = 0;
1856 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1857 fix->xpanstep = 1;
1858 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1859 fix->ywrapstep = 0;
1860 fix->line_length = ivideo->video_linelength;
1861 fix->mmio_start = ivideo->mmio_base;
1862 fix->mmio_len = ivideo->mmio_size;
1863 if(ivideo->sisvga_engine == SIS_300_VGA) {
1864 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1865 } else if((ivideo->chip == SIS_330) ||
1866 (ivideo->chip == SIS_760) ||
1867 (ivideo->chip == SIS_761)) {
1868 fix->accel = FB_ACCEL_SIS_XABRE;
1869 } else if(ivideo->chip == XGI_20) {
1870 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1871 } else if(ivideo->chip >= XGI_40) {
1872 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1873 } else {
1874 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1877 return 0;
1880 /* ---------------- fb_ops structures ----------------- */
1882 static struct fb_ops sisfb_ops = {
1883 .owner = THIS_MODULE,
1884 .fb_open = sisfb_open,
1885 .fb_release = sisfb_release,
1886 .fb_check_var = sisfb_check_var,
1887 .fb_set_par = sisfb_set_par,
1888 .fb_setcolreg = sisfb_setcolreg,
1889 .fb_pan_display = sisfb_pan_display,
1890 .fb_blank = sisfb_blank,
1891 .fb_fillrect = fbcon_sis_fillrect,
1892 .fb_copyarea = fbcon_sis_copyarea,
1893 .fb_imageblit = cfb_imageblit,
1894 .fb_sync = fbcon_sis_sync,
1895 #ifdef SIS_NEW_CONFIG_COMPAT
1896 .fb_compat_ioctl= sisfb_ioctl,
1897 #endif
1898 .fb_ioctl = sisfb_ioctl
1901 /* ---------------- Chip generation dependent routines ---------------- */
1903 static struct pci_dev * __devinit
1904 sisfb_get_northbridge(int basechipid)
1906 struct pci_dev *pdev = NULL;
1907 int nbridgenum, nbridgeidx, i;
1908 static const unsigned short nbridgeids[] = {
1909 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1910 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1911 PCI_DEVICE_ID_SI_730,
1912 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1913 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1914 PCI_DEVICE_ID_SI_651,
1915 PCI_DEVICE_ID_SI_740,
1916 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
1917 PCI_DEVICE_ID_SI_741,
1918 PCI_DEVICE_ID_SI_660,
1919 PCI_DEVICE_ID_SI_760,
1920 PCI_DEVICE_ID_SI_761
1923 switch(basechipid) {
1924 #ifdef CONFIG_FB_SIS_300
1925 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1926 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1927 #endif
1928 #ifdef CONFIG_FB_SIS_315
1929 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1930 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
1931 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
1932 #endif
1933 default: return NULL;
1935 for(i = 0; i < nbridgenum; i++) {
1936 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
1937 nbridgeids[nbridgeidx+i], NULL)))
1938 break;
1940 return pdev;
1943 static int __devinit
1944 sisfb_get_dram_size(struct sis_video_info *ivideo)
1946 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1947 u8 reg;
1948 #endif
1950 ivideo->video_size = 0;
1951 ivideo->UMAsize = ivideo->LFBsize = 0;
1953 switch(ivideo->chip) {
1954 #ifdef CONFIG_FB_SIS_300
1955 case SIS_300:
1956 inSISIDXREG(SISSR, 0x14, reg);
1957 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1958 break;
1959 case SIS_540:
1960 case SIS_630:
1961 case SIS_730:
1962 if(!ivideo->nbridge)
1963 return -1;
1964 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
1965 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1966 break;
1967 #endif
1968 #ifdef CONFIG_FB_SIS_315
1969 case SIS_315H:
1970 case SIS_315PRO:
1971 case SIS_315:
1972 inSISIDXREG(SISSR, 0x14, reg);
1973 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1974 switch((reg >> 2) & 0x03) {
1975 case 0x01:
1976 case 0x03:
1977 ivideo->video_size <<= 1;
1978 break;
1979 case 0x02:
1980 ivideo->video_size += (ivideo->video_size/2);
1982 break;
1983 case SIS_330:
1984 inSISIDXREG(SISSR, 0x14, reg);
1985 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1986 if(reg & 0x0c) ivideo->video_size <<= 1;
1987 break;
1988 case SIS_550:
1989 case SIS_650:
1990 case SIS_740:
1991 inSISIDXREG(SISSR, 0x14, reg);
1992 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
1993 break;
1994 case SIS_661:
1995 case SIS_741:
1996 inSISIDXREG(SISCR, 0x79, reg);
1997 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1998 break;
1999 case SIS_660:
2000 case SIS_760:
2001 case SIS_761:
2002 inSISIDXREG(SISCR, 0x79, reg);
2003 reg = (reg & 0xf0) >> 4;
2004 if(reg) {
2005 ivideo->video_size = (1 << reg) << 20;
2006 ivideo->UMAsize = ivideo->video_size;
2008 inSISIDXREG(SISCR, 0x78, reg);
2009 reg &= 0x30;
2010 if(reg) {
2011 if(reg == 0x10) {
2012 ivideo->LFBsize = (32 << 20);
2013 } else {
2014 ivideo->LFBsize = (64 << 20);
2016 ivideo->video_size += ivideo->LFBsize;
2018 break;
2019 case SIS_340:
2020 case XGI_20:
2021 case XGI_40:
2022 inSISIDXREG(SISSR, 0x14, reg);
2023 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2024 if(ivideo->chip != XGI_20) {
2025 reg = (reg & 0x0c) >> 2;
2026 if(ivideo->revision_id == 2) {
2027 if(reg & 0x01) reg = 0x02;
2028 else reg = 0x00;
2030 if(reg == 0x02) ivideo->video_size <<= 1;
2031 else if(reg == 0x03) ivideo->video_size <<= 2;
2033 break;
2034 #endif
2035 default:
2036 return -1;
2038 return 0;
2041 /* -------------- video bridge device detection --------------- */
2043 static void __devinit
2044 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2046 u8 cr32, temp;
2048 /* No CRT2 on XGI Z7 */
2049 if(ivideo->chip == XGI_20) {
2050 ivideo->sisfb_crt1off = 0;
2051 return;
2054 #ifdef CONFIG_FB_SIS_300
2055 if(ivideo->sisvga_engine == SIS_300_VGA) {
2056 inSISIDXREG(SISSR, 0x17, temp);
2057 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2058 /* PAL/NTSC is stored on SR16 on such machines */
2059 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2060 inSISIDXREG(SISSR, 0x16, temp);
2061 if(temp & 0x20)
2062 ivideo->vbflags |= TV_PAL;
2063 else
2064 ivideo->vbflags |= TV_NTSC;
2068 #endif
2070 inSISIDXREG(SISCR, 0x32, cr32);
2072 if(cr32 & SIS_CRT1) {
2073 ivideo->sisfb_crt1off = 0;
2074 } else {
2075 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2078 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2080 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2081 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2082 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2084 /* Check given parms for hardware compatibility.
2085 * (Cannot do this in the search_xx routines since we don't
2086 * know what hardware we are running on then)
2089 if(ivideo->chip != SIS_550) {
2090 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2093 if(ivideo->sisfb_tvplug != -1) {
2094 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2095 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2096 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2097 ivideo->sisfb_tvplug = -1;
2098 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2102 if(ivideo->sisfb_tvplug != -1) {
2103 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2104 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2105 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2106 ivideo->sisfb_tvplug = -1;
2107 printk(KERN_ERR "sisfb: HiVision not supported\n");
2111 if(ivideo->sisfb_tvstd != -1) {
2112 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2113 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2114 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2115 if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
2116 ivideo->sisfb_tvstd = -1;
2117 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2122 /* Detect/set TV plug & type */
2123 if(ivideo->sisfb_tvplug != -1) {
2124 ivideo->vbflags |= ivideo->sisfb_tvplug;
2125 } else {
2126 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2127 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2128 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2129 else {
2130 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2131 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2135 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2136 if(ivideo->sisfb_tvstd != -1) {
2137 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2138 ivideo->vbflags |= ivideo->sisfb_tvstd;
2140 if(ivideo->vbflags & TV_SCART) {
2141 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2142 ivideo->vbflags |= TV_PAL;
2144 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2145 if(ivideo->sisvga_engine == SIS_300_VGA) {
2146 inSISIDXREG(SISSR, 0x38, temp);
2147 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2148 else ivideo->vbflags |= TV_NTSC;
2149 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2150 inSISIDXREG(SISSR, 0x38, temp);
2151 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2152 else ivideo->vbflags |= TV_NTSC;
2153 } else {
2154 inSISIDXREG(SISCR, 0x79, temp);
2155 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2156 else ivideo->vbflags |= TV_NTSC;
2161 /* Copy forceCRT1 option to CRT1off if option is given */
2162 if(ivideo->sisfb_forcecrt1 != -1) {
2163 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2167 /* ------------------ Sensing routines ------------------ */
2169 static bool __devinit
2170 sisfb_test_DDC1(struct sis_video_info *ivideo)
2172 unsigned short old;
2173 int count = 48;
2175 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2176 do {
2177 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2178 } while(count--);
2179 return (count != -1);
2182 static void __devinit
2183 sisfb_sense_crt1(struct sis_video_info *ivideo)
2185 bool mustwait = false;
2186 u8 sr1F, cr17;
2187 #ifdef CONFIG_FB_SIS_315
2188 u8 cr63=0;
2189 #endif
2190 u16 temp = 0xffff;
2191 int i;
2193 inSISIDXREG(SISSR,0x1F,sr1F);
2194 orSISIDXREG(SISSR,0x1F,0x04);
2195 andSISIDXREG(SISSR,0x1F,0x3F);
2196 if(sr1F & 0xc0) mustwait = true;
2198 #ifdef CONFIG_FB_SIS_315
2199 if(ivideo->sisvga_engine == SIS_315_VGA) {
2200 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2201 cr63 &= 0x40;
2202 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2204 #endif
2206 inSISIDXREG(SISCR,0x17,cr17);
2207 cr17 &= 0x80;
2208 if(!cr17) {
2209 orSISIDXREG(SISCR,0x17,0x80);
2210 mustwait = true;
2211 outSISIDXREG(SISSR, 0x00, 0x01);
2212 outSISIDXREG(SISSR, 0x00, 0x03);
2215 if(mustwait) {
2216 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2219 #ifdef CONFIG_FB_SIS_315
2220 if(ivideo->chip >= SIS_330) {
2221 andSISIDXREG(SISCR,0x32,~0x20);
2222 if(ivideo->chip >= SIS_340) {
2223 outSISIDXREG(SISCR, 0x57, 0x4a);
2224 } else {
2225 outSISIDXREG(SISCR, 0x57, 0x5f);
2227 orSISIDXREG(SISCR, 0x53, 0x02);
2228 while((inSISREG(SISINPSTAT)) & 0x01) break;
2229 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2230 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2231 andSISIDXREG(SISCR, 0x53, 0xfd);
2232 andSISIDXREG(SISCR, 0x57, 0x00);
2234 #endif
2236 if(temp == 0xffff) {
2237 i = 3;
2238 do {
2239 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2240 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2241 } while(((temp == 0) || (temp == 0xffff)) && i--);
2243 if((temp == 0) || (temp == 0xffff)) {
2244 if(sisfb_test_DDC1(ivideo)) temp = 1;
2248 if((temp) && (temp != 0xffff)) {
2249 orSISIDXREG(SISCR,0x32,0x20);
2252 #ifdef CONFIG_FB_SIS_315
2253 if(ivideo->sisvga_engine == SIS_315_VGA) {
2254 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2256 #endif
2258 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2260 outSISIDXREG(SISSR,0x1F,sr1F);
2263 /* Determine and detect attached devices on SiS30x */
2264 static void __devinit
2265 SiS_SenseLCD(struct sis_video_info *ivideo)
2267 unsigned char buffer[256];
2268 unsigned short temp, realcrtno, i;
2269 u8 reg, cr37 = 0, paneltype = 0;
2270 u16 xres, yres;
2272 ivideo->SiS_Pr.PanelSelfDetected = false;
2274 /* LCD detection only for TMDS bridges */
2275 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2276 return;
2277 if(ivideo->vbflags2 & VB2_30xBDH)
2278 return;
2280 /* If LCD already set up by BIOS, skip it */
2281 inSISIDXREG(SISCR, 0x32, reg);
2282 if(reg & 0x08)
2283 return;
2285 realcrtno = 1;
2286 if(ivideo->SiS_Pr.DDCPortMixup)
2287 realcrtno = 0;
2289 /* Check DDC capabilities */
2290 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2291 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2293 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2294 return;
2296 /* Read DDC data */
2297 i = 3; /* Number of retrys */
2298 do {
2299 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2300 ivideo->sisvga_engine, realcrtno, 1,
2301 &buffer[0], ivideo->vbflags2);
2302 } while((temp) && i--);
2304 if(temp)
2305 return;
2307 /* No digital device */
2308 if(!(buffer[0x14] & 0x80))
2309 return;
2311 /* First detailed timing preferred timing? */
2312 if(!(buffer[0x18] & 0x02))
2313 return;
2315 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2316 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2318 switch(xres) {
2319 case 1024:
2320 if(yres == 768)
2321 paneltype = 0x02;
2322 break;
2323 case 1280:
2324 if(yres == 1024)
2325 paneltype = 0x03;
2326 break;
2327 case 1600:
2328 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2329 paneltype = 0x0b;
2330 break;
2333 if(!paneltype)
2334 return;
2336 if(buffer[0x23])
2337 cr37 |= 0x10;
2339 if((buffer[0x47] & 0x18) == 0x18)
2340 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2341 else
2342 cr37 |= 0xc0;
2344 outSISIDXREG(SISCR, 0x36, paneltype);
2345 cr37 &= 0xf1;
2346 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2347 orSISIDXREG(SISCR, 0x32, 0x08);
2349 ivideo->SiS_Pr.PanelSelfDetected = true;
2352 static int __devinit
2353 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2355 int temp, mytest, result, i, j;
2357 for(j = 0; j < 10; j++) {
2358 result = 0;
2359 for(i = 0; i < 3; i++) {
2360 mytest = test;
2361 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2362 temp = (type >> 8) | (mytest & 0x00ff);
2363 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2364 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2365 mytest >>= 8;
2366 mytest &= 0x7f;
2367 inSISIDXREG(SISPART4,0x03,temp);
2368 temp ^= 0x0e;
2369 temp &= mytest;
2370 if(temp == mytest) result++;
2371 #if 1
2372 outSISIDXREG(SISPART4,0x11,0x00);
2373 andSISIDXREG(SISPART4,0x10,0xe0);
2374 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2375 #endif
2377 if((result == 0) || (result >= 2)) break;
2379 return result;
2382 static void __devinit
2383 SiS_Sense30x(struct sis_video_info *ivideo)
2385 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2386 u16 svhs=0, svhs_c=0;
2387 u16 cvbs=0, cvbs_c=0;
2388 u16 vga2=0, vga2_c=0;
2389 int myflag, result;
2390 char stdstr[] = "sisfb: Detected";
2391 char tvstr[] = "TV connected to";
2393 if(ivideo->vbflags2 & VB2_301) {
2394 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2395 inSISIDXREG(SISPART4,0x01,myflag);
2396 if(myflag & 0x04) {
2397 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2399 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2400 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2401 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2402 svhs = 0x0200; cvbs = 0x0100;
2403 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2404 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2405 } else
2406 return;
2408 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2409 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2410 svhs_c = 0x0408; cvbs_c = 0x0808;
2413 biosflag = 2;
2414 if(ivideo->haveXGIROM) {
2415 biosflag = ivideo->bios_abase[0x58] & 0x03;
2416 } else if(ivideo->newrom) {
2417 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2418 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2419 if(ivideo->bios_abase) {
2420 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2424 if(ivideo->chip == SIS_300) {
2425 inSISIDXREG(SISSR,0x3b,myflag);
2426 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2429 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2430 vga2 = vga2_c = 0;
2433 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2434 orSISIDXREG(SISSR,0x1e,0x20);
2436 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2437 if(ivideo->vbflags2 & VB2_30xC) {
2438 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2439 } else {
2440 orSISIDXREG(SISPART4,0x0d,0x04);
2442 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2444 inSISIDXREG(SISPART2,0x00,backupP2_00);
2445 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2447 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2448 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2449 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2452 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2453 SISDoSense(ivideo, 0, 0);
2456 andSISIDXREG(SISCR, 0x32, ~0x14);
2458 if(vga2_c || vga2) {
2459 if(SISDoSense(ivideo, vga2, vga2_c)) {
2460 if(biosflag & 0x01) {
2461 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2462 orSISIDXREG(SISCR, 0x32, 0x04);
2463 } else {
2464 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2465 orSISIDXREG(SISCR, 0x32, 0x10);
2470 andSISIDXREG(SISCR, 0x32, 0x3f);
2472 if(ivideo->vbflags2 & VB2_30xCLV) {
2473 orSISIDXREG(SISPART4,0x0d,0x04);
2476 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2477 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2478 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2479 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2480 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2481 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2482 orSISIDXREG(SISCR,0x32,0x80);
2485 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2488 andSISIDXREG(SISCR, 0x32, ~0x03);
2490 if(!(ivideo->vbflags & TV_YPBPR)) {
2491 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2492 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2493 orSISIDXREG(SISCR, 0x32, 0x02);
2495 if((biosflag & 0x02) || (!result)) {
2496 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2497 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2498 orSISIDXREG(SISCR, 0x32, 0x01);
2503 SISDoSense(ivideo, 0, 0);
2505 outSISIDXREG(SISPART2,0x00,backupP2_00);
2506 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2507 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2509 if(ivideo->vbflags2 & VB2_30xCLV) {
2510 inSISIDXREG(SISPART2,0x00,biosflag);
2511 if(biosflag & 0x20) {
2512 for(myflag = 2; myflag > 0; myflag--) {
2513 biosflag ^= 0x20;
2514 outSISIDXREG(SISPART2,0x00,biosflag);
2519 outSISIDXREG(SISPART2,0x00,backupP2_00);
2522 /* Determine and detect attached TV's on Chrontel */
2523 static void __devinit
2524 SiS_SenseCh(struct sis_video_info *ivideo)
2526 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2527 u8 temp1, temp2;
2528 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2529 #endif
2530 #ifdef CONFIG_FB_SIS_300
2531 unsigned char test[3];
2532 int i;
2533 #endif
2535 if(ivideo->chip < SIS_315H) {
2537 #ifdef CONFIG_FB_SIS_300
2538 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2539 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2540 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2541 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2542 /* See Chrontel TB31 for explanation */
2543 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2544 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2545 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2546 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2548 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2549 if(temp2 != temp1) temp1 = temp2;
2551 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2552 /* Read power status */
2553 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2554 if((temp1 & 0x03) != 0x03) {
2555 /* Power all outputs */
2556 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2557 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2559 /* Sense connected TV devices */
2560 for(i = 0; i < 3; i++) {
2561 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2562 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2563 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2564 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2565 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2566 if(!(temp1 & 0x08)) test[i] = 0x02;
2567 else if(!(temp1 & 0x02)) test[i] = 0x01;
2568 else test[i] = 0;
2569 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2572 if(test[0] == test[1]) temp1 = test[0];
2573 else if(test[0] == test[2]) temp1 = test[0];
2574 else if(test[1] == test[2]) temp1 = test[1];
2575 else {
2576 printk(KERN_INFO
2577 "sisfb: TV detection unreliable - test results varied\n");
2578 temp1 = test[2];
2580 if(temp1 == 0x02) {
2581 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2582 ivideo->vbflags |= TV_SVIDEO;
2583 orSISIDXREG(SISCR, 0x32, 0x02);
2584 andSISIDXREG(SISCR, 0x32, ~0x05);
2585 } else if (temp1 == 0x01) {
2586 printk(KERN_INFO "%s CVBS output\n", stdstr);
2587 ivideo->vbflags |= TV_AVIDEO;
2588 orSISIDXREG(SISCR, 0x32, 0x01);
2589 andSISIDXREG(SISCR, 0x32, ~0x06);
2590 } else {
2591 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2592 andSISIDXREG(SISCR, 0x32, ~0x07);
2594 } else if(temp1 == 0) {
2595 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2596 andSISIDXREG(SISCR, 0x32, ~0x07);
2598 /* Set general purpose IO for Chrontel communication */
2599 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2600 #endif
2602 } else {
2604 #ifdef CONFIG_FB_SIS_315
2605 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2606 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2607 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2608 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2609 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2610 temp2 |= 0x01;
2611 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2612 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2613 temp2 ^= 0x01;
2614 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2615 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2616 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2617 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2618 temp1 = 0;
2619 if(temp2 & 0x02) temp1 |= 0x01;
2620 if(temp2 & 0x10) temp1 |= 0x01;
2621 if(temp2 & 0x04) temp1 |= 0x02;
2622 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2623 switch(temp1) {
2624 case 0x01:
2625 printk(KERN_INFO "%s CVBS output\n", stdstr);
2626 ivideo->vbflags |= TV_AVIDEO;
2627 orSISIDXREG(SISCR, 0x32, 0x01);
2628 andSISIDXREG(SISCR, 0x32, ~0x06);
2629 break;
2630 case 0x02:
2631 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2632 ivideo->vbflags |= TV_SVIDEO;
2633 orSISIDXREG(SISCR, 0x32, 0x02);
2634 andSISIDXREG(SISCR, 0x32, ~0x05);
2635 break;
2636 case 0x04:
2637 printk(KERN_INFO "%s SCART output\n", stdstr);
2638 orSISIDXREG(SISCR, 0x32, 0x04);
2639 andSISIDXREG(SISCR, 0x32, ~0x03);
2640 break;
2641 default:
2642 andSISIDXREG(SISCR, 0x32, ~0x07);
2644 #endif
2648 static void __devinit
2649 sisfb_get_VB_type(struct sis_video_info *ivideo)
2651 char stdstr[] = "sisfb: Detected";
2652 char bridgestr[] = "video bridge";
2653 u8 vb_chipid;
2654 u8 reg;
2656 /* No CRT2 on XGI Z7 */
2657 if(ivideo->chip == XGI_20)
2658 return;
2660 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2661 switch(vb_chipid) {
2662 case 0x01:
2663 inSISIDXREG(SISPART4, 0x01, reg);
2664 if(reg < 0xb0) {
2665 ivideo->vbflags |= VB_301; /* Deprecated */
2666 ivideo->vbflags2 |= VB2_301;
2667 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2668 } else if(reg < 0xc0) {
2669 ivideo->vbflags |= VB_301B; /* Deprecated */
2670 ivideo->vbflags2 |= VB2_301B;
2671 inSISIDXREG(SISPART4,0x23,reg);
2672 if(!(reg & 0x02)) {
2673 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2674 ivideo->vbflags2 |= VB2_30xBDH;
2675 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2676 } else {
2677 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2679 } else if(reg < 0xd0) {
2680 ivideo->vbflags |= VB_301C; /* Deprecated */
2681 ivideo->vbflags2 |= VB2_301C;
2682 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2683 } else if(reg < 0xe0) {
2684 ivideo->vbflags |= VB_301LV; /* Deprecated */
2685 ivideo->vbflags2 |= VB2_301LV;
2686 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2687 } else if(reg <= 0xe1) {
2688 inSISIDXREG(SISPART4,0x39,reg);
2689 if(reg == 0xff) {
2690 ivideo->vbflags |= VB_302LV; /* Deprecated */
2691 ivideo->vbflags2 |= VB2_302LV;
2692 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2693 } else {
2694 ivideo->vbflags |= VB_301C; /* Deprecated */
2695 ivideo->vbflags2 |= VB2_301C;
2696 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2697 #if 0
2698 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2699 ivideo->vbflags2 |= VB2_302ELV;
2700 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2701 #endif
2704 break;
2705 case 0x02:
2706 ivideo->vbflags |= VB_302B; /* Deprecated */
2707 ivideo->vbflags2 |= VB2_302B;
2708 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2709 break;
2712 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2713 inSISIDXREG(SISCR, 0x37, reg);
2714 reg &= SIS_EXTERNAL_CHIP_MASK;
2715 reg >>= 1;
2716 if(ivideo->sisvga_engine == SIS_300_VGA) {
2717 #ifdef CONFIG_FB_SIS_300
2718 switch(reg) {
2719 case SIS_EXTERNAL_CHIP_LVDS:
2720 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2721 ivideo->vbflags2 |= VB2_LVDS;
2722 break;
2723 case SIS_EXTERNAL_CHIP_TRUMPION:
2724 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2725 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2726 break;
2727 case SIS_EXTERNAL_CHIP_CHRONTEL:
2728 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2729 ivideo->vbflags2 |= VB2_CHRONTEL;
2730 break;
2731 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2732 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2733 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2734 break;
2736 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2737 #endif
2738 } else if(ivideo->chip < SIS_661) {
2739 #ifdef CONFIG_FB_SIS_315
2740 switch (reg) {
2741 case SIS310_EXTERNAL_CHIP_LVDS:
2742 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2743 ivideo->vbflags2 |= VB2_LVDS;
2744 break;
2745 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2746 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2747 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2748 break;
2750 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2751 #endif
2752 } else if(ivideo->chip >= SIS_661) {
2753 #ifdef CONFIG_FB_SIS_315
2754 inSISIDXREG(SISCR, 0x38, reg);
2755 reg >>= 5;
2756 switch(reg) {
2757 case 0x02:
2758 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2759 ivideo->vbflags2 |= VB2_LVDS;
2760 break;
2761 case 0x03:
2762 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2763 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2764 break;
2765 case 0x04:
2766 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2767 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2768 break;
2770 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2771 #endif
2773 if(ivideo->vbflags2 & VB2_LVDS) {
2774 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2776 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2777 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2779 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2780 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2782 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2783 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2787 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2788 SiS_SenseLCD(ivideo);
2789 SiS_Sense30x(ivideo);
2790 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2791 SiS_SenseCh(ivideo);
2795 /* ---------- Engine initialization routines ------------ */
2797 static void
2798 sisfb_engine_init(struct sis_video_info *ivideo)
2801 /* Initialize command queue (we use MMIO only) */
2803 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2805 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2806 MMIO_CMD_QUEUE_CAP |
2807 VM_CMD_QUEUE_CAP |
2808 AGP_CMD_QUEUE_CAP);
2810 #ifdef CONFIG_FB_SIS_300
2811 if(ivideo->sisvga_engine == SIS_300_VGA) {
2812 u32 tqueue_pos;
2813 u8 tq_state;
2815 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2817 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2818 tq_state |= 0xf0;
2819 tq_state &= 0xfc;
2820 tq_state |= (u8)(tqueue_pos >> 8);
2821 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2823 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2825 ivideo->caps |= TURBO_QUEUE_CAP;
2827 #endif
2829 #ifdef CONFIG_FB_SIS_315
2830 if(ivideo->sisvga_engine == SIS_315_VGA) {
2831 u32 tempq = 0, templ;
2832 u8 temp;
2834 if(ivideo->chip == XGI_20) {
2835 switch(ivideo->cmdQueueSize) {
2836 case (64 * 1024):
2837 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2838 break;
2839 case (128 * 1024):
2840 default:
2841 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2843 } else {
2844 switch(ivideo->cmdQueueSize) {
2845 case (4 * 1024 * 1024):
2846 temp = SIS_CMD_QUEUE_SIZE_4M;
2847 break;
2848 case (2 * 1024 * 1024):
2849 temp = SIS_CMD_QUEUE_SIZE_2M;
2850 break;
2851 case (1 * 1024 * 1024):
2852 temp = SIS_CMD_QUEUE_SIZE_1M;
2853 break;
2854 default:
2855 case (512 * 1024):
2856 temp = SIS_CMD_QUEUE_SIZE_512k;
2860 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2861 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2863 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2864 /* Must disable dual pipe on XGI_40. Can't do
2865 * this in MMIO mode, because it requires
2866 * setting/clearing a bit in the MMIO fire trigger
2867 * register.
2869 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2871 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2873 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2875 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2876 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2878 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2879 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2881 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2882 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2883 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2884 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2886 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2888 sisfb_syncaccel(ivideo);
2890 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2895 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2896 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2898 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2899 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2901 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2902 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2904 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2906 #endif
2908 ivideo->engineok = 1;
2911 static void __devinit
2912 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2914 u8 reg;
2915 int i;
2917 inSISIDXREG(SISCR, 0x36, reg);
2918 reg &= 0x0f;
2919 if(ivideo->sisvga_engine == SIS_300_VGA) {
2920 ivideo->CRT2LCDType = sis300paneltype[reg];
2921 } else if(ivideo->chip >= SIS_661) {
2922 ivideo->CRT2LCDType = sis661paneltype[reg];
2923 } else {
2924 ivideo->CRT2LCDType = sis310paneltype[reg];
2925 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2926 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2927 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2928 ivideo->CRT2LCDType = LCD_320x240;
2933 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2934 /* For broken BIOSes: Assume 1024x768, RGB18 */
2935 ivideo->CRT2LCDType = LCD_1024x768;
2936 setSISIDXREG(SISCR,0x36,0xf0,0x02);
2937 setSISIDXREG(SISCR,0x37,0xee,0x01);
2938 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2941 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2942 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2943 ivideo->lcdxres = sis_lcd_data[i].xres;
2944 ivideo->lcdyres = sis_lcd_data[i].yres;
2945 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2946 break;
2950 #ifdef CONFIG_FB_SIS_300
2951 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2952 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2953 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2954 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2955 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2956 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2957 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2958 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2959 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2961 #endif
2963 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2964 ivideo->lcdxres, ivideo->lcdyres);
2967 static void __devinit
2968 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2970 #ifdef CONFIG_FB_SIS_300
2971 /* Save the current PanelDelayCompensation if the LCD is currently used */
2972 if(ivideo->sisvga_engine == SIS_300_VGA) {
2973 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2974 int tmp;
2975 inSISIDXREG(SISCR,0x30,tmp);
2976 if(tmp & 0x20) {
2977 /* Currently on LCD? If yes, read current pdc */
2978 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2979 ivideo->detectedpdc &= 0x3c;
2980 if(ivideo->SiS_Pr.PDC == -1) {
2981 /* Let option override detection */
2982 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2984 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2985 ivideo->detectedpdc);
2987 if((ivideo->SiS_Pr.PDC != -1) &&
2988 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2989 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2990 ivideo->SiS_Pr.PDC);
2994 #endif
2996 #ifdef CONFIG_FB_SIS_315
2997 if(ivideo->sisvga_engine == SIS_315_VGA) {
2999 /* Try to find about LCDA */
3000 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3001 int tmp;
3002 inSISIDXREG(SISPART1,0x13,tmp);
3003 if(tmp & 0x04) {
3004 ivideo->SiS_Pr.SiS_UseLCDA = true;
3005 ivideo->detectedlcda = 0x03;
3009 /* Save PDC */
3010 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3011 int tmp;
3012 inSISIDXREG(SISCR,0x30,tmp);
3013 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3014 /* Currently on LCD? If yes, read current pdc */
3015 u8 pdc;
3016 inSISIDXREG(SISPART1,0x2D,pdc);
3017 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3018 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3019 inSISIDXREG(SISPART1,0x35,pdc);
3020 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3021 inSISIDXREG(SISPART1,0x20,pdc);
3022 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3023 if(ivideo->newrom) {
3024 /* New ROM invalidates other PDC resp. */
3025 if(ivideo->detectedlcda != 0xff) {
3026 ivideo->detectedpdc = 0xff;
3027 } else {
3028 ivideo->detectedpdca = 0xff;
3031 if(ivideo->SiS_Pr.PDC == -1) {
3032 if(ivideo->detectedpdc != 0xff) {
3033 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3036 if(ivideo->SiS_Pr.PDCA == -1) {
3037 if(ivideo->detectedpdca != 0xff) {
3038 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3041 if(ivideo->detectedpdc != 0xff) {
3042 printk(KERN_INFO
3043 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3044 ivideo->detectedpdc);
3046 if(ivideo->detectedpdca != 0xff) {
3047 printk(KERN_INFO
3048 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3049 ivideo->detectedpdca);
3053 /* Save EMI */
3054 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3055 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3056 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3057 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3058 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3059 ivideo->SiS_Pr.HaveEMI = true;
3060 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3061 ivideo->SiS_Pr.HaveEMILCD = true;
3066 /* Let user override detected PDCs (all bridges) */
3067 if(ivideo->vbflags2 & VB2_30xBLV) {
3068 if((ivideo->SiS_Pr.PDC != -1) &&
3069 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3070 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3071 ivideo->SiS_Pr.PDC);
3073 if((ivideo->SiS_Pr.PDCA != -1) &&
3074 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3075 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3076 ivideo->SiS_Pr.PDCA);
3081 #endif
3084 /* -------------------- Memory manager routines ---------------------- */
3086 static u32 __devinit
3087 sisfb_getheapstart(struct sis_video_info *ivideo)
3089 u32 ret = ivideo->sisfb_parm_mem * 1024;
3090 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3091 u32 def;
3093 /* Calculate heap start = end of memory for console
3095 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3096 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3098 * On 76x in UMA+LFB mode, the layout is as follows:
3099 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3100 * where the heap is the entire UMA area, eventually
3101 * into the LFB area if the given mem parameter is
3102 * higher than the size of the UMA memory.
3104 * Basically given by "mem" parameter
3106 * maximum = videosize - cmd_queue - hwcursor
3107 * (results in a heap of size 0)
3108 * default = SiS 300: depends on videosize
3109 * SiS 315/330/340/XGI: 32k below max
3112 if(ivideo->sisvga_engine == SIS_300_VGA) {
3113 if(ivideo->video_size > 0x1000000) {
3114 def = 0xc00000;
3115 } else if(ivideo->video_size > 0x800000) {
3116 def = 0x800000;
3117 } else {
3118 def = 0x400000;
3120 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3121 ret = def = 0;
3122 } else {
3123 def = maxoffs - 0x8000;
3126 /* Use default for secondary card for now (FIXME) */
3127 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3128 ret = def;
3130 return ret;
3133 static u32 __devinit
3134 sisfb_getheapsize(struct sis_video_info *ivideo)
3136 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3137 u32 ret = 0;
3139 if(ivideo->UMAsize && ivideo->LFBsize) {
3140 if( (!ivideo->sisfb_parm_mem) ||
3141 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3142 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3143 ret = ivideo->UMAsize;
3144 max -= ivideo->UMAsize;
3145 } else {
3146 ret = max - (ivideo->sisfb_parm_mem * 1024);
3147 max = ivideo->sisfb_parm_mem * 1024;
3149 ivideo->video_offset = ret;
3150 ivideo->sisfb_mem = max;
3151 } else {
3152 ret = max - ivideo->heapstart;
3153 ivideo->sisfb_mem = ivideo->heapstart;
3156 return ret;
3159 static int __devinit
3160 sisfb_heap_init(struct sis_video_info *ivideo)
3162 struct SIS_OH *poh;
3164 ivideo->video_offset = 0;
3165 if(ivideo->sisfb_parm_mem) {
3166 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3167 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3168 ivideo->sisfb_parm_mem = 0;
3172 ivideo->heapstart = sisfb_getheapstart(ivideo);
3173 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3175 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3176 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3178 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3179 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3181 ivideo->sisfb_heap.vinfo = ivideo;
3183 ivideo->sisfb_heap.poha_chain = NULL;
3184 ivideo->sisfb_heap.poh_freelist = NULL;
3186 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3187 if(poh == NULL)
3188 return 1;
3190 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3191 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3192 poh->size = ivideo->sisfb_heap_size;
3193 poh->offset = ivideo->heapstart;
3195 ivideo->sisfb_heap.oh_free.poh_next = poh;
3196 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3197 ivideo->sisfb_heap.oh_free.size = 0;
3198 ivideo->sisfb_heap.max_freesize = poh->size;
3200 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3201 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3202 ivideo->sisfb_heap.oh_used.size = SENTINEL;
3204 if(ivideo->cardnumber == 0) {
3205 /* For the first card, make this heap the "global" one
3206 * for old DRM (which could handle only one card)
3208 sisfb_heap = &ivideo->sisfb_heap;
3211 return 0;
3214 static struct SIS_OH *
3215 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3217 struct SIS_OHALLOC *poha;
3218 struct SIS_OH *poh;
3219 unsigned long cOhs;
3220 int i;
3222 if(memheap->poh_freelist == NULL) {
3223 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3224 if(!poha)
3225 return NULL;
3227 poha->poha_next = memheap->poha_chain;
3228 memheap->poha_chain = poha;
3230 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3232 poh = &poha->aoh[0];
3233 for(i = cOhs - 1; i != 0; i--) {
3234 poh->poh_next = poh + 1;
3235 poh = poh + 1;
3238 poh->poh_next = NULL;
3239 memheap->poh_freelist = &poha->aoh[0];
3242 poh = memheap->poh_freelist;
3243 memheap->poh_freelist = poh->poh_next;
3245 return poh;
3248 static struct SIS_OH *
3249 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3251 struct SIS_OH *pohThis;
3252 struct SIS_OH *pohRoot;
3253 int bAllocated = 0;
3255 if(size > memheap->max_freesize) {
3256 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3257 (unsigned int) size / 1024);
3258 return NULL;
3261 pohThis = memheap->oh_free.poh_next;
3263 while(pohThis != &memheap->oh_free) {
3264 if(size <= pohThis->size) {
3265 bAllocated = 1;
3266 break;
3268 pohThis = pohThis->poh_next;
3271 if(!bAllocated) {
3272 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3273 (unsigned int) size / 1024);
3274 return NULL;
3277 if(size == pohThis->size) {
3278 pohRoot = pohThis;
3279 sisfb_delete_node(pohThis);
3280 } else {
3281 pohRoot = sisfb_poh_new_node(memheap);
3282 if(pohRoot == NULL)
3283 return NULL;
3285 pohRoot->offset = pohThis->offset;
3286 pohRoot->size = size;
3288 pohThis->offset += size;
3289 pohThis->size -= size;
3292 memheap->max_freesize -= size;
3294 pohThis = &memheap->oh_used;
3295 sisfb_insert_node(pohThis, pohRoot);
3297 return pohRoot;
3300 static void
3301 sisfb_delete_node(struct SIS_OH *poh)
3303 poh->poh_prev->poh_next = poh->poh_next;
3304 poh->poh_next->poh_prev = poh->poh_prev;
3307 static void
3308 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3310 struct SIS_OH *pohTemp = pohList->poh_next;
3312 pohList->poh_next = poh;
3313 pohTemp->poh_prev = poh;
3315 poh->poh_prev = pohList;
3316 poh->poh_next = pohTemp;
3319 static struct SIS_OH *
3320 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3322 struct SIS_OH *pohThis;
3323 struct SIS_OH *poh_freed;
3324 struct SIS_OH *poh_prev;
3325 struct SIS_OH *poh_next;
3326 u32 ulUpper;
3327 u32 ulLower;
3328 int foundNode = 0;
3330 poh_freed = memheap->oh_used.poh_next;
3332 while(poh_freed != &memheap->oh_used) {
3333 if(poh_freed->offset == base) {
3334 foundNode = 1;
3335 break;
3338 poh_freed = poh_freed->poh_next;
3341 if(!foundNode)
3342 return NULL;
3344 memheap->max_freesize += poh_freed->size;
3346 poh_prev = poh_next = NULL;
3347 ulUpper = poh_freed->offset + poh_freed->size;
3348 ulLower = poh_freed->offset;
3350 pohThis = memheap->oh_free.poh_next;
3352 while(pohThis != &memheap->oh_free) {
3353 if(pohThis->offset == ulUpper) {
3354 poh_next = pohThis;
3355 } else if((pohThis->offset + pohThis->size) == ulLower) {
3356 poh_prev = pohThis;
3358 pohThis = pohThis->poh_next;
3361 sisfb_delete_node(poh_freed);
3363 if(poh_prev && poh_next) {
3364 poh_prev->size += (poh_freed->size + poh_next->size);
3365 sisfb_delete_node(poh_next);
3366 sisfb_free_node(memheap, poh_freed);
3367 sisfb_free_node(memheap, poh_next);
3368 return poh_prev;
3371 if(poh_prev) {
3372 poh_prev->size += poh_freed->size;
3373 sisfb_free_node(memheap, poh_freed);
3374 return poh_prev;
3377 if(poh_next) {
3378 poh_next->size += poh_freed->size;
3379 poh_next->offset = poh_freed->offset;
3380 sisfb_free_node(memheap, poh_freed);
3381 return poh_next;
3384 sisfb_insert_node(&memheap->oh_free, poh_freed);
3386 return poh_freed;
3389 static void
3390 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3392 if(poh == NULL)
3393 return;
3395 poh->poh_next = memheap->poh_freelist;
3396 memheap->poh_freelist = poh;
3399 static void
3400 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3402 struct SIS_OH *poh = NULL;
3404 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3405 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3407 if(poh == NULL) {
3408 req->offset = req->size = 0;
3409 DPRINTK("sisfb: Video RAM allocation failed\n");
3410 } else {
3411 req->offset = poh->offset;
3412 req->size = poh->size;
3413 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3414 (poh->offset + ivideo->video_vbase));
3418 void
3419 sis_malloc(struct sis_memreq *req)
3421 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3423 if(&ivideo->sisfb_heap == sisfb_heap)
3424 sis_int_malloc(ivideo, req);
3425 else
3426 req->offset = req->size = 0;
3429 void
3430 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3432 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3434 sis_int_malloc(ivideo, req);
3437 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3439 static void
3440 sis_int_free(struct sis_video_info *ivideo, u32 base)
3442 struct SIS_OH *poh;
3444 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3445 return;
3447 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3449 if(poh == NULL) {
3450 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3451 (unsigned int) base);
3455 void
3456 sis_free(u32 base)
3458 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3460 sis_int_free(ivideo, base);
3463 void
3464 sis_free_new(struct pci_dev *pdev, u32 base)
3466 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3468 sis_int_free(ivideo, base);
3471 /* --------------------- SetMode routines ------------------------- */
3473 static void
3474 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3476 u8 cr30, cr31;
3478 /* Check if MMIO and engines are enabled,
3479 * and sync in case they are. Can't use
3480 * ivideo->accel here, as this might have
3481 * been changed before this is called.
3483 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3484 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3485 /* MMIO and 2D/3D engine enabled? */
3486 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3487 #ifdef CONFIG_FB_SIS_300
3488 if(ivideo->sisvga_engine == SIS_300_VGA) {
3489 /* Don't care about TurboQueue. It's
3490 * enough to know that the engines
3491 * are enabled
3493 sisfb_syncaccel(ivideo);
3495 #endif
3496 #ifdef CONFIG_FB_SIS_315
3497 if(ivideo->sisvga_engine == SIS_315_VGA) {
3498 /* Check that any queue mode is
3499 * enabled, and that the queue
3500 * is not in the state of "reset"
3502 inSISIDXREG(SISSR, 0x26, cr30);
3503 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3504 sisfb_syncaccel(ivideo);
3507 #endif
3511 static void
3512 sisfb_pre_setmode(struct sis_video_info *ivideo)
3514 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3515 int tvregnum = 0;
3517 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3519 outSISIDXREG(SISSR, 0x05, 0x86);
3521 inSISIDXREG(SISCR, 0x31, cr31);
3522 cr31 &= ~0x60;
3523 cr31 |= 0x04;
3525 cr33 = ivideo->rate_idx & 0x0F;
3527 #ifdef CONFIG_FB_SIS_315
3528 if(ivideo->sisvga_engine == SIS_315_VGA) {
3529 if(ivideo->chip >= SIS_661) {
3530 inSISIDXREG(SISCR, 0x38, cr38);
3531 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3532 } else {
3533 tvregnum = 0x38;
3534 inSISIDXREG(SISCR, tvregnum, cr38);
3535 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3538 #endif
3539 #ifdef CONFIG_FB_SIS_300
3540 if(ivideo->sisvga_engine == SIS_300_VGA) {
3541 tvregnum = 0x35;
3542 inSISIDXREG(SISCR, tvregnum, cr38);
3544 #endif
3546 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3547 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
3548 ivideo->curFSTN = ivideo->curDSTN = 0;
3550 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3552 case CRT2_TV:
3553 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3554 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3555 #ifdef CONFIG_FB_SIS_315
3556 if(ivideo->chip >= SIS_661) {
3557 cr38 |= 0x04;
3558 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3559 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3560 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3561 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3562 cr35 &= ~0x01;
3563 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3564 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3565 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3566 cr38 |= 0x08;
3567 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3568 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3569 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3570 cr31 &= ~0x01;
3571 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3573 #endif
3574 } else if((ivideo->vbflags & TV_HIVISION) &&
3575 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3576 if(ivideo->chip >= SIS_661) {
3577 cr38 |= 0x04;
3578 cr35 |= 0x60;
3579 } else {
3580 cr30 |= 0x80;
3582 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3583 cr31 |= 0x01;
3584 cr35 |= 0x01;
3585 ivideo->currentvbflags |= TV_HIVISION;
3586 } else if(ivideo->vbflags & TV_SCART) {
3587 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3588 cr31 |= 0x01;
3589 cr35 |= 0x01;
3590 ivideo->currentvbflags |= TV_SCART;
3591 } else {
3592 if(ivideo->vbflags & TV_SVIDEO) {
3593 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3594 ivideo->currentvbflags |= TV_SVIDEO;
3596 if(ivideo->vbflags & TV_AVIDEO) {
3597 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3598 ivideo->currentvbflags |= TV_AVIDEO;
3601 cr31 |= SIS_DRIVER_MODE;
3603 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3604 if(ivideo->vbflags & TV_PAL) {
3605 cr31 |= 0x01; cr35 |= 0x01;
3606 ivideo->currentvbflags |= TV_PAL;
3607 if(ivideo->vbflags & TV_PALM) {
3608 cr38 |= 0x40; cr35 |= 0x04;
3609 ivideo->currentvbflags |= TV_PALM;
3610 } else if(ivideo->vbflags & TV_PALN) {
3611 cr38 |= 0x80; cr35 |= 0x08;
3612 ivideo->currentvbflags |= TV_PALN;
3614 } else {
3615 cr31 &= ~0x01; cr35 &= ~0x01;
3616 ivideo->currentvbflags |= TV_NTSC;
3617 if(ivideo->vbflags & TV_NTSCJ) {
3618 cr38 |= 0x40; cr35 |= 0x02;
3619 ivideo->currentvbflags |= TV_NTSCJ;
3623 break;
3625 case CRT2_LCD:
3626 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3627 cr31 |= SIS_DRIVER_MODE;
3628 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3629 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3630 ivideo->curFSTN = ivideo->sisfb_fstn;
3631 ivideo->curDSTN = ivideo->sisfb_dstn;
3632 break;
3634 case CRT2_VGA:
3635 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3636 cr31 |= SIS_DRIVER_MODE;
3637 if(ivideo->sisfb_nocrt2rate) {
3638 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3639 } else {
3640 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3642 break;
3644 default: /* disable CRT2 */
3645 cr30 = 0x00;
3646 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3649 outSISIDXREG(SISCR, 0x30, cr30);
3650 outSISIDXREG(SISCR, 0x33, cr33);
3652 if(ivideo->chip >= SIS_661) {
3653 #ifdef CONFIG_FB_SIS_315
3654 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3655 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3656 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3657 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3658 #endif
3659 } else if(ivideo->chip != SIS_300) {
3660 outSISIDXREG(SISCR, tvregnum, cr38);
3662 outSISIDXREG(SISCR, 0x31, cr31);
3664 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3666 sisfb_check_engine_and_sync(ivideo);
3669 /* Fix SR11 for 661 and later */
3670 #ifdef CONFIG_FB_SIS_315
3671 static void
3672 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3674 u8 tmpreg;
3676 if(ivideo->chip >= SIS_661) {
3677 inSISIDXREG(SISSR,0x11,tmpreg);
3678 if(tmpreg & 0x20) {
3679 inSISIDXREG(SISSR,0x3e,tmpreg);
3680 tmpreg = (tmpreg + 1) & 0xff;
3681 outSISIDXREG(SISSR,0x3e,tmpreg);
3682 inSISIDXREG(SISSR,0x11,tmpreg);
3684 if(tmpreg & 0xf0) {
3685 andSISIDXREG(SISSR,0x11,0x0f);
3689 #endif
3691 static void
3692 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3694 if(val > 32) val = 32;
3695 if(val < -32) val = -32;
3696 ivideo->tvxpos = val;
3698 if(ivideo->sisfblocked) return;
3699 if(!ivideo->modechanged) return;
3701 if(ivideo->currentvbflags & CRT2_TV) {
3703 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3705 int x = ivideo->tvx;
3707 switch(ivideo->chronteltype) {
3708 case 1:
3709 x += val;
3710 if(x < 0) x = 0;
3711 outSISIDXREG(SISSR,0x05,0x86);
3712 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3713 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3714 break;
3715 case 2:
3716 /* Not supported by hardware */
3717 break;
3720 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3722 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3723 unsigned short temp;
3725 p2_1f = ivideo->p2_1f;
3726 p2_20 = ivideo->p2_20;
3727 p2_2b = ivideo->p2_2b;
3728 p2_42 = ivideo->p2_42;
3729 p2_43 = ivideo->p2_43;
3731 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3732 temp += (val * 2);
3733 p2_1f = temp & 0xff;
3734 p2_20 = (temp & 0xf00) >> 4;
3735 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3736 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3737 temp += (val * 2);
3738 p2_43 = temp & 0xff;
3739 p2_42 = (temp & 0xf00) >> 4;
3740 outSISIDXREG(SISPART2,0x1f,p2_1f);
3741 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3742 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3743 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3744 outSISIDXREG(SISPART2,0x43,p2_43);
3749 static void
3750 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3752 if(val > 32) val = 32;
3753 if(val < -32) val = -32;
3754 ivideo->tvypos = val;
3756 if(ivideo->sisfblocked) return;
3757 if(!ivideo->modechanged) return;
3759 if(ivideo->currentvbflags & CRT2_TV) {
3761 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3763 int y = ivideo->tvy;
3765 switch(ivideo->chronteltype) {
3766 case 1:
3767 y -= val;
3768 if(y < 0) y = 0;
3769 outSISIDXREG(SISSR,0x05,0x86);
3770 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3771 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3772 break;
3773 case 2:
3774 /* Not supported by hardware */
3775 break;
3778 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3780 char p2_01, p2_02;
3781 val /= 2;
3782 p2_01 = ivideo->p2_01;
3783 p2_02 = ivideo->p2_02;
3785 p2_01 += val;
3786 p2_02 += val;
3787 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3788 while((p2_01 <= 0) || (p2_02 <= 0)) {
3789 p2_01 += 2;
3790 p2_02 += 2;
3793 outSISIDXREG(SISPART2,0x01,p2_01);
3794 outSISIDXREG(SISPART2,0x02,p2_02);
3799 static void
3800 sisfb_post_setmode(struct sis_video_info *ivideo)
3802 bool crt1isoff = false;
3803 bool doit = true;
3804 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3805 u8 reg;
3806 #endif
3807 #ifdef CONFIG_FB_SIS_315
3808 u8 reg1;
3809 #endif
3811 outSISIDXREG(SISSR, 0x05, 0x86);
3813 #ifdef CONFIG_FB_SIS_315
3814 sisfb_fixup_SR11(ivideo);
3815 #endif
3817 /* Now we actually HAVE changed the display mode */
3818 ivideo->modechanged = 1;
3820 /* We can't switch off CRT1 if bridge is in slave mode */
3821 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3822 if(sisfb_bridgeisslave(ivideo)) doit = false;
3823 } else
3824 ivideo->sisfb_crt1off = 0;
3826 #ifdef CONFIG_FB_SIS_300
3827 if(ivideo->sisvga_engine == SIS_300_VGA) {
3828 if((ivideo->sisfb_crt1off) && (doit)) {
3829 crt1isoff = true;
3830 reg = 0x00;
3831 } else {
3832 crt1isoff = false;
3833 reg = 0x80;
3835 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3837 #endif
3838 #ifdef CONFIG_FB_SIS_315
3839 if(ivideo->sisvga_engine == SIS_315_VGA) {
3840 if((ivideo->sisfb_crt1off) && (doit)) {
3841 crt1isoff = true;
3842 reg = 0x40;
3843 reg1 = 0xc0;
3844 } else {
3845 crt1isoff = false;
3846 reg = 0x00;
3847 reg1 = 0x00;
3849 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3850 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3852 #endif
3854 if(crt1isoff) {
3855 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3856 ivideo->currentvbflags |= VB_SINGLE_MODE;
3857 } else {
3858 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3859 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3860 ivideo->currentvbflags |= VB_MIRROR_MODE;
3861 } else {
3862 ivideo->currentvbflags |= VB_SINGLE_MODE;
3866 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3868 if(ivideo->currentvbflags & CRT2_TV) {
3869 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3870 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3871 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3872 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3873 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3874 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3875 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3876 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3877 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3878 if(ivideo->chronteltype == 1) {
3879 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3880 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3881 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3882 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3887 if(ivideo->tvxpos) {
3888 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3890 if(ivideo->tvypos) {
3891 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3894 /* Eventually sync engines */
3895 sisfb_check_engine_and_sync(ivideo);
3897 /* (Re-)Initialize chip engines */
3898 if(ivideo->accel) {
3899 sisfb_engine_init(ivideo);
3900 } else {
3901 ivideo->engineok = 0;
3905 static int
3906 sisfb_reset_mode(struct sis_video_info *ivideo)
3908 if(sisfb_set_mode(ivideo, 0))
3909 return 1;
3911 sisfb_set_pitch(ivideo);
3912 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3913 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3915 return 0;
3918 static void
3919 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3921 int mycrt1off;
3923 switch(sisfb_command->sisfb_cmd) {
3924 case SISFB_CMD_GETVBFLAGS:
3925 if(!ivideo->modechanged) {
3926 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3927 } else {
3928 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3929 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3930 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
3932 break;
3933 case SISFB_CMD_SWITCHCRT1:
3934 /* arg[0]: 0 = off, 1 = on, 99 = query */
3935 if(!ivideo->modechanged) {
3936 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3937 } else if(sisfb_command->sisfb_arg[0] == 99) {
3938 /* Query */
3939 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3940 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3941 } else if(ivideo->sisfblocked) {
3942 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3943 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3944 (sisfb_command->sisfb_arg[0] == 0)) {
3945 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3946 } else {
3947 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3948 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3949 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3950 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3951 ivideo->sisfb_crt1off = mycrt1off;
3952 if(sisfb_reset_mode(ivideo)) {
3953 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
3956 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3958 break;
3959 /* more to come */
3960 default:
3961 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3962 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3963 sisfb_command->sisfb_cmd);
3967 #ifndef MODULE
3968 static int __init sisfb_setup(char *options)
3970 char *this_opt;
3972 sisfb_setdefaultparms();
3974 if(!options || !(*options))
3975 return 0;
3977 while((this_opt = strsep(&options, ",")) != NULL) {
3979 if(!(*this_opt)) continue;
3981 if(!strnicmp(this_opt, "off", 3)) {
3982 sisfb_off = 1;
3983 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3984 /* Need to check crt2 type first for fstn/dstn */
3985 sisfb_search_crt2type(this_opt + 14);
3986 } else if(!strnicmp(this_opt, "tvmode:",7)) {
3987 sisfb_search_tvstd(this_opt + 7);
3988 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3989 sisfb_search_tvstd(this_opt + 11);
3990 } else if(!strnicmp(this_opt, "mode:", 5)) {
3991 sisfb_search_mode(this_opt + 5, false);
3992 } else if(!strnicmp(this_opt, "vesa:", 5)) {
3993 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
3994 } else if(!strnicmp(this_opt, "rate:", 5)) {
3995 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
3996 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3997 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
3998 } else if(!strnicmp(this_opt, "mem:",4)) {
3999 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4000 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4001 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4002 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4003 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4004 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4005 sisfb_accel = 0;
4006 } else if(!strnicmp(this_opt, "accel", 5)) {
4007 sisfb_accel = -1;
4008 } else if(!strnicmp(this_opt, "noypan", 6)) {
4009 sisfb_ypan = 0;
4010 } else if(!strnicmp(this_opt, "ypan", 4)) {
4011 sisfb_ypan = -1;
4012 } else if(!strnicmp(this_opt, "nomax", 5)) {
4013 sisfb_max = 0;
4014 } else if(!strnicmp(this_opt, "max", 3)) {
4015 sisfb_max = -1;
4016 } else if(!strnicmp(this_opt, "userom:", 7)) {
4017 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4018 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4019 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4020 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4021 sisfb_nocrt2rate = 1;
4022 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4023 unsigned long temp = 2;
4024 temp = simple_strtoul(this_opt + 9, NULL, 0);
4025 if((temp == 0) || (temp == 1)) {
4026 sisfb_scalelcd = temp ^ 1;
4028 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4029 int temp = 0;
4030 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4031 if((temp >= -32) && (temp <= 32)) {
4032 sisfb_tvxposoffset = temp;
4034 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4035 int temp = 0;
4036 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4037 if((temp >= -32) && (temp <= 32)) {
4038 sisfb_tvyposoffset = temp;
4040 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4041 sisfb_search_specialtiming(this_opt + 14);
4042 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4043 int temp = 4;
4044 temp = simple_strtoul(this_opt + 7, NULL, 0);
4045 if((temp >= 0) && (temp <= 3)) {
4046 sisfb_lvdshl = temp;
4048 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4049 sisfb_search_mode(this_opt, true);
4050 #if !defined(__i386__) && !defined(__x86_64__)
4051 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4052 sisfb_resetcard = 1;
4053 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4054 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4055 #endif
4056 } else {
4057 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4062 return 0;
4064 #endif
4066 static int __devinit
4067 sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
4069 void __iomem *rom;
4070 int romptr;
4072 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4073 return 0;
4075 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4076 if(romptr > (0x10000 - 8))
4077 return 0;
4079 rom = rom_base + romptr;
4081 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4082 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4083 return 0;
4085 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4086 return 0;
4088 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4089 return 0;
4091 return 1;
4094 static unsigned char * __devinit
4095 sisfb_find_rom(struct pci_dev *pdev)
4097 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4098 void __iomem *rom_base;
4099 unsigned char *myrombase = NULL;
4100 u32 temp;
4101 size_t romsize;
4103 /* First, try the official pci ROM functions (except
4104 * on integrated chipsets which have no ROM).
4107 if(!ivideo->nbridge) {
4109 if((rom_base = pci_map_rom(pdev, &romsize))) {
4111 if(sisfb_check_rom(rom_base, ivideo)) {
4113 if((myrombase = vmalloc(65536))) {
4115 /* Work around bug in pci/rom.c: Folks forgot to check
4116 * whether the size retrieved from the BIOS image eventually
4117 * is larger than the mapped size
4119 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4120 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4122 memcpy_fromio(myrombase, rom_base,
4123 (romsize > 65536) ? 65536 : romsize);
4126 pci_unmap_rom(pdev, rom_base);
4130 if(myrombase) return myrombase;
4132 /* Otherwise do it the conventional way. */
4134 #if defined(__i386__) || defined(__x86_64__)
4136 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4138 rom_base = ioremap(temp, 65536);
4139 if(!rom_base)
4140 continue;
4142 if(!sisfb_check_rom(rom_base, ivideo)) {
4143 iounmap(rom_base);
4144 continue;
4147 if((myrombase = vmalloc(65536)))
4148 memcpy_fromio(myrombase, rom_base, 65536);
4150 iounmap(rom_base);
4151 break;
4155 #else
4157 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4158 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4159 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4161 rom_base = ioremap(ivideo->video_base, 65536);
4162 if(rom_base) {
4163 if(sisfb_check_rom(rom_base, ivideo)) {
4164 if((myrombase = vmalloc(65536)))
4165 memcpy_fromio(myrombase, rom_base, 65536);
4167 iounmap(rom_base);
4170 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4172 #endif
4174 return myrombase;
4177 static void __devinit
4178 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4179 unsigned int min)
4181 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4183 if(!ivideo->video_vbase) {
4184 printk(KERN_ERR
4185 "sisfb: Unable to map maximum video RAM for size detection\n");
4186 (*mapsize) >>= 1;
4187 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4188 (*mapsize) >>= 1;
4189 if((*mapsize) < (min << 20))
4190 break;
4192 if(ivideo->video_vbase) {
4193 printk(KERN_ERR
4194 "sisfb: Video RAM size detection limited to %dMB\n",
4195 (int)((*mapsize) >> 20));
4200 #ifdef CONFIG_FB_SIS_300
4201 static int __devinit
4202 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4204 void __iomem *FBAddress = ivideo->video_vbase;
4205 unsigned short temp;
4206 unsigned char reg;
4207 int i, j;
4209 andSISIDXREG(SISSR, 0x15, 0xFB);
4210 orSISIDXREG(SISSR, 0x15, 0x04);
4211 outSISIDXREG(SISSR, 0x13, 0x00);
4212 outSISIDXREG(SISSR, 0x14, 0xBF);
4214 for(i = 0; i < 2; i++) {
4215 temp = 0x1234;
4216 for(j = 0; j < 4; j++) {
4217 writew(temp, FBAddress);
4218 if(readw(FBAddress) == temp)
4219 break;
4220 orSISIDXREG(SISSR, 0x3c, 0x01);
4221 inSISIDXREG(SISSR, 0x05, reg);
4222 inSISIDXREG(SISSR, 0x05, reg);
4223 andSISIDXREG(SISSR, 0x3c, 0xfe);
4224 inSISIDXREG(SISSR, 0x05, reg);
4225 inSISIDXREG(SISSR, 0x05, reg);
4226 temp++;
4230 writel(0x01234567L, FBAddress);
4231 writel(0x456789ABL, (FBAddress + 4));
4232 writel(0x89ABCDEFL, (FBAddress + 8));
4233 writel(0xCDEF0123L, (FBAddress + 12));
4235 inSISIDXREG(SISSR, 0x3b, reg);
4236 if(reg & 0x01) {
4237 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4238 return 4; /* Channel A 128bit */
4241 if(readl((FBAddress + 4)) == 0x456789ABL)
4242 return 2; /* Channel B 64bit */
4244 return 1; /* 32bit */
4247 static int __devinit
4248 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4249 int PseudoRankCapacity, int PseudoAdrPinCount,
4250 unsigned int mapsize)
4252 void __iomem *FBAddr = ivideo->video_vbase;
4253 unsigned short sr14;
4254 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4255 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4256 static const unsigned short SiS_DRAMType[17][5] = {
4257 {0x0C,0x0A,0x02,0x40,0x39},
4258 {0x0D,0x0A,0x01,0x40,0x48},
4259 {0x0C,0x09,0x02,0x20,0x35},
4260 {0x0D,0x09,0x01,0x20,0x44},
4261 {0x0C,0x08,0x02,0x10,0x31},
4262 {0x0D,0x08,0x01,0x10,0x40},
4263 {0x0C,0x0A,0x01,0x20,0x34},
4264 {0x0C,0x09,0x01,0x08,0x32},
4265 {0x0B,0x08,0x02,0x08,0x21},
4266 {0x0C,0x08,0x01,0x08,0x30},
4267 {0x0A,0x08,0x02,0x04,0x11},
4268 {0x0B,0x0A,0x01,0x10,0x28},
4269 {0x09,0x08,0x02,0x02,0x01},
4270 {0x0B,0x09,0x01,0x08,0x24},
4271 {0x0B,0x08,0x01,0x04,0x20},
4272 {0x0A,0x08,0x01,0x02,0x10},
4273 {0x09,0x08,0x01,0x01,0x00}
4276 for(k = 0; k <= 16; k++) {
4278 RankCapacity = buswidth * SiS_DRAMType[k][3];
4280 if(RankCapacity != PseudoRankCapacity)
4281 continue;
4283 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4284 continue;
4286 BankNumHigh = RankCapacity * 16 * iteration - 1;
4287 if(iteration == 3) { /* Rank No */
4288 BankNumMid = RankCapacity * 16 - 1;
4289 } else {
4290 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4293 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4294 PhysicalAdrHigh = BankNumHigh;
4295 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4296 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4298 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4299 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4300 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4301 if(buswidth == 4) sr14 |= 0x80;
4302 else if(buswidth == 2) sr14 |= 0x40;
4303 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4304 outSISIDXREG(SISSR, 0x14, sr14);
4306 BankNumHigh <<= 16;
4307 BankNumMid <<= 16;
4309 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4310 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4311 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4312 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4313 continue;
4315 /* Write data */
4316 writew(((unsigned short)PhysicalAdrHigh),
4317 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4318 writew(((unsigned short)BankNumMid),
4319 (FBAddr + BankNumMid + PhysicalAdrHigh));
4320 writew(((unsigned short)PhysicalAdrHalfPage),
4321 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4322 writew(((unsigned short)PhysicalAdrOtherPage),
4323 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4325 /* Read data */
4326 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4327 return 1;
4330 return 0;
4333 static void __devinit
4334 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4336 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4337 int i, j, buswidth;
4338 int PseudoRankCapacity, PseudoAdrPinCount;
4340 buswidth = sisfb_post_300_buswidth(ivideo);
4342 for(i = 6; i >= 0; i--) {
4343 PseudoRankCapacity = 1 << i;
4344 for(j = 4; j >= 1; j--) {
4345 PseudoAdrPinCount = 15 - j;
4346 if((PseudoRankCapacity * j) <= 64) {
4347 if(sisfb_post_300_rwtest(ivideo,
4349 buswidth,
4350 PseudoRankCapacity,
4351 PseudoAdrPinCount,
4352 mapsize))
4353 return;
4359 static void __devinit
4360 sisfb_post_sis300(struct pci_dev *pdev)
4362 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4363 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4364 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4365 u16 index, rindex, memtype = 0;
4366 unsigned int mapsize;
4368 if(!ivideo->SiS_Pr.UseROM)
4369 bios = NULL;
4371 outSISIDXREG(SISSR, 0x05, 0x86);
4373 if(bios) {
4374 if(bios[0x52] & 0x80) {
4375 memtype = bios[0x52];
4376 } else {
4377 inSISIDXREG(SISSR, 0x3a, memtype);
4379 memtype &= 0x07;
4382 v3 = 0x80; v6 = 0x80;
4383 if(ivideo->revision_id <= 0x13) {
4384 v1 = 0x44; v2 = 0x42;
4385 v4 = 0x44; v5 = 0x42;
4386 } else {
4387 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4388 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4389 if(bios) {
4390 index = memtype * 5;
4391 rindex = index + 0x54;
4392 v1 = bios[rindex++];
4393 v2 = bios[rindex++];
4394 v3 = bios[rindex++];
4395 rindex = index + 0x7c;
4396 v4 = bios[rindex++];
4397 v5 = bios[rindex++];
4398 v6 = bios[rindex++];
4401 outSISIDXREG(SISSR, 0x28, v1);
4402 outSISIDXREG(SISSR, 0x29, v2);
4403 outSISIDXREG(SISSR, 0x2a, v3);
4404 outSISIDXREG(SISSR, 0x2e, v4);
4405 outSISIDXREG(SISSR, 0x2f, v5);
4406 outSISIDXREG(SISSR, 0x30, v6);
4408 v1 = 0x10;
4409 if(bios)
4410 v1 = bios[0xa4];
4411 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4413 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4415 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4416 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4417 if(bios) {
4418 memtype += 0xa5;
4419 v1 = bios[memtype];
4420 v2 = bios[memtype + 8];
4421 v3 = bios[memtype + 16];
4422 v4 = bios[memtype + 24];
4423 v5 = bios[memtype + 32];
4424 v6 = bios[memtype + 40];
4425 v7 = bios[memtype + 48];
4426 v8 = bios[memtype + 56];
4428 if(ivideo->revision_id >= 0x80)
4429 v3 &= 0xfd;
4430 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4431 outSISIDXREG(SISSR, 0x16, v2);
4432 outSISIDXREG(SISSR, 0x17, v3);
4433 outSISIDXREG(SISSR, 0x18, v4);
4434 outSISIDXREG(SISSR, 0x19, v5);
4435 outSISIDXREG(SISSR, 0x1a, v6);
4436 outSISIDXREG(SISSR, 0x1b, v7);
4437 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4438 andSISIDXREG(SISSR, 0x15 ,0xfb);
4439 orSISIDXREG(SISSR, 0x15, 0x04);
4440 if(bios) {
4441 if(bios[0x53] & 0x02) {
4442 orSISIDXREG(SISSR, 0x19, 0x20);
4445 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4446 if(ivideo->revision_id >= 0x80)
4447 v1 |= 0x01;
4448 outSISIDXREG(SISSR, 0x1f, v1);
4449 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4450 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4451 if(bios) {
4452 v1 = bios[0xe8];
4453 v2 = bios[0xe9];
4454 v3 = bios[0xea];
4456 outSISIDXREG(SISSR, 0x23, v1);
4457 outSISIDXREG(SISSR, 0x24, v2);
4458 outSISIDXREG(SISSR, 0x25, v3);
4459 outSISIDXREG(SISSR, 0x21, 0x84);
4460 outSISIDXREG(SISSR, 0x22, 0x00);
4461 outSISIDXREG(SISCR, 0x37, 0x00);
4462 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4463 outSISIDXREG(SISPART1, 0x00, 0x00);
4464 v1 = 0x40; v2 = 0x11;
4465 if(bios) {
4466 v1 = bios[0xec];
4467 v2 = bios[0xeb];
4469 outSISIDXREG(SISPART1, 0x02, v1);
4471 if(ivideo->revision_id >= 0x80)
4472 v2 &= ~0x01;
4474 inSISIDXREG(SISPART4, 0x00, reg);
4475 if((reg == 1) || (reg == 2)) {
4476 outSISIDXREG(SISCR, 0x37, 0x02);
4477 outSISIDXREG(SISPART2, 0x00, 0x1c);
4478 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4479 if(ivideo->SiS_Pr.UseROM) {
4480 v4 = bios[0xf5];
4481 v5 = bios[0xf6];
4482 v6 = bios[0xf7];
4484 outSISIDXREG(SISPART4, 0x0d, v4);
4485 outSISIDXREG(SISPART4, 0x0e, v5);
4486 outSISIDXREG(SISPART4, 0x10, v6);
4487 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4488 inSISIDXREG(SISPART4, 0x01, reg);
4489 if(reg >= 0xb0) {
4490 inSISIDXREG(SISPART4, 0x23, reg);
4491 reg &= 0x20;
4492 reg <<= 1;
4493 outSISIDXREG(SISPART4, 0x23, reg);
4495 } else {
4496 v2 &= ~0x10;
4498 outSISIDXREG(SISSR, 0x32, v2);
4500 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4502 inSISIDXREG(SISSR, 0x16, reg);
4503 reg &= 0xc3;
4504 outSISIDXREG(SISCR, 0x35, reg);
4505 outSISIDXREG(SISCR, 0x83, 0x00);
4506 #if !defined(__i386__) && !defined(__x86_64__)
4507 if(sisfb_videoram) {
4508 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4509 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4510 outSISIDXREG(SISSR, 0x14, reg);
4511 } else {
4512 #endif
4513 /* Need to map max FB size for finding out about RAM size */
4514 mapsize = 64 << 20;
4515 sisfb_post_map_vram(ivideo, &mapsize, 4);
4517 if(ivideo->video_vbase) {
4518 sisfb_post_300_ramsize(pdev, mapsize);
4519 iounmap(ivideo->video_vbase);
4520 } else {
4521 printk(KERN_DEBUG
4522 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4523 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4524 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4526 #if !defined(__i386__) && !defined(__x86_64__)
4528 #endif
4529 if(bios) {
4530 v1 = bios[0xe6];
4531 v2 = bios[0xe7];
4532 } else {
4533 inSISIDXREG(SISSR, 0x3a, reg);
4534 if((reg & 0x30) == 0x30) {
4535 v1 = 0x04; /* PCI */
4536 v2 = 0x92;
4537 } else {
4538 v1 = 0x14; /* AGP */
4539 v2 = 0xb2;
4542 outSISIDXREG(SISSR, 0x21, v1);
4543 outSISIDXREG(SISSR, 0x22, v2);
4545 /* Sense CRT1 */
4546 sisfb_sense_crt1(ivideo);
4548 /* Set default mode, don't clear screen */
4549 ivideo->SiS_Pr.SiS_UseOEM = false;
4550 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4551 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
4552 ivideo->curFSTN = ivideo->curDSTN = 0;
4553 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4554 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4556 outSISIDXREG(SISSR, 0x05, 0x86);
4558 /* Display off */
4559 orSISIDXREG(SISSR, 0x01, 0x20);
4561 /* Save mode number in CR34 */
4562 outSISIDXREG(SISCR, 0x34, 0x2e);
4564 /* Let everyone know what the current mode is */
4565 ivideo->modeprechange = 0x2e;
4567 #endif
4569 #ifdef CONFIG_FB_SIS_315
4570 #if 0
4571 static void __devinit
4572 sisfb_post_sis315330(struct pci_dev *pdev)
4574 /* TODO */
4576 #endif
4578 static void __devinit
4579 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4581 unsigned int i;
4582 u8 reg;
4584 for(i = 0; i <= (delay * 10 * 36); i++) {
4585 inSISIDXREG(SISSR, 0x05, reg);
4586 reg++;
4590 static int __devinit
4591 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4592 unsigned short pcivendor)
4594 struct pci_dev *pdev = NULL;
4595 unsigned short temp;
4596 int ret = 0;
4598 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
4599 temp = pdev->vendor;
4600 if(temp == pcivendor) {
4601 ret = 1;
4602 pci_dev_put(pdev);
4603 break;
4607 return ret;
4610 static int __devinit
4611 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4612 unsigned int enda, unsigned int mapsize)
4614 unsigned int pos;
4615 int i;
4617 writel(0, ivideo->video_vbase);
4619 for(i = starta; i <= enda; i++) {
4620 pos = 1 << i;
4621 if(pos < mapsize)
4622 writel(pos, ivideo->video_vbase + pos);
4625 sisfb_post_xgi_delay(ivideo, 150);
4627 if(readl(ivideo->video_vbase) != 0)
4628 return 0;
4630 for(i = starta; i <= enda; i++) {
4631 pos = 1 << i;
4632 if(pos < mapsize) {
4633 if(readl(ivideo->video_vbase + pos) != pos)
4634 return 0;
4635 } else
4636 return 0;
4639 return 1;
4642 static void __devinit
4643 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4645 unsigned int buswidth, ranksize, channelab, mapsize;
4646 int i, j, k, l;
4647 u8 reg, sr14;
4648 static const u8 dramsr13[12 * 5] = {
4649 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4650 0x02, 0x0e, 0x0a, 0x40, 0x59,
4651 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4652 0x02, 0x0e, 0x09, 0x20, 0x55,
4653 0x02, 0x0d, 0x0a, 0x20, 0x49,
4654 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4655 0x02, 0x0e, 0x08, 0x10, 0x51,
4656 0x02, 0x0d, 0x09, 0x10, 0x45,
4657 0x02, 0x0c, 0x0a, 0x10, 0x39,
4658 0x02, 0x0d, 0x08, 0x08, 0x41,
4659 0x02, 0x0c, 0x09, 0x08, 0x35,
4660 0x02, 0x0c, 0x08, 0x04, 0x31
4662 static const u8 dramsr13_4[4 * 5] = {
4663 0x02, 0x0d, 0x09, 0x40, 0x45,
4664 0x02, 0x0c, 0x09, 0x20, 0x35,
4665 0x02, 0x0c, 0x08, 0x10, 0x31,
4666 0x02, 0x0b, 0x08, 0x08, 0x21
4669 /* Enable linear mode, disable 0xa0000 address decoding */
4670 /* We disable a0000 address decoding, because
4671 * - if running on x86, if the card is disabled, it means
4672 * that another card is in the system. We don't want
4673 * to interphere with that primary card's textmode.
4674 * - if running on non-x86, there usually is no VGA window
4675 * at a0000.
4677 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4679 /* Need to map max FB size for finding out about RAM size */
4680 mapsize = 256 << 20;
4681 sisfb_post_map_vram(ivideo, &mapsize, 32);
4683 if(!ivideo->video_vbase) {
4684 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4685 outSISIDXREG(SISSR, 0x13, 0x35);
4686 outSISIDXREG(SISSR, 0x14, 0x41);
4687 /* TODO */
4688 return;
4691 /* Non-interleaving */
4692 outSISIDXREG(SISSR, 0x15, 0x00);
4693 /* No tiling */
4694 outSISIDXREG(SISSR, 0x1c, 0x00);
4696 if(ivideo->chip == XGI_20) {
4698 channelab = 1;
4699 inSISIDXREG(SISCR, 0x97, reg);
4700 if(!(reg & 0x01)) { /* Single 32/16 */
4701 buswidth = 32;
4702 outSISIDXREG(SISSR, 0x13, 0xb1);
4703 outSISIDXREG(SISSR, 0x14, 0x52);
4704 sisfb_post_xgi_delay(ivideo, 1);
4705 sr14 = 0x02;
4706 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4707 goto bail_out;
4709 outSISIDXREG(SISSR, 0x13, 0x31);
4710 outSISIDXREG(SISSR, 0x14, 0x42);
4711 sisfb_post_xgi_delay(ivideo, 1);
4712 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4713 goto bail_out;
4715 buswidth = 16;
4716 outSISIDXREG(SISSR, 0x13, 0xb1);
4717 outSISIDXREG(SISSR, 0x14, 0x41);
4718 sisfb_post_xgi_delay(ivideo, 1);
4719 sr14 = 0x01;
4720 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4721 goto bail_out;
4722 else
4723 outSISIDXREG(SISSR, 0x13, 0x31);
4724 } else { /* Dual 16/8 */
4725 buswidth = 16;
4726 outSISIDXREG(SISSR, 0x13, 0xb1);
4727 outSISIDXREG(SISSR, 0x14, 0x41);
4728 sisfb_post_xgi_delay(ivideo, 1);
4729 sr14 = 0x01;
4730 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4731 goto bail_out;
4733 outSISIDXREG(SISSR, 0x13, 0x31);
4734 outSISIDXREG(SISSR, 0x14, 0x31);
4735 sisfb_post_xgi_delay(ivideo, 1);
4736 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4737 goto bail_out;
4739 buswidth = 8;
4740 outSISIDXREG(SISSR, 0x13, 0xb1);
4741 outSISIDXREG(SISSR, 0x14, 0x30);
4742 sisfb_post_xgi_delay(ivideo, 1);
4743 sr14 = 0x00;
4744 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4745 goto bail_out;
4746 else
4747 outSISIDXREG(SISSR, 0x13, 0x31);
4750 } else { /* XGI_40 */
4752 inSISIDXREG(SISCR, 0x97, reg);
4753 if(!(reg & 0x10)) {
4754 inSISIDXREG(SISSR, 0x39, reg);
4755 reg >>= 1;
4758 if(reg & 0x01) { /* DDRII */
4759 buswidth = 32;
4760 if(ivideo->revision_id == 2) {
4761 channelab = 2;
4762 outSISIDXREG(SISSR, 0x13, 0xa1);
4763 outSISIDXREG(SISSR, 0x14, 0x44);
4764 sr14 = 0x04;
4765 sisfb_post_xgi_delay(ivideo, 1);
4766 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4767 goto bail_out;
4769 outSISIDXREG(SISSR, 0x13, 0x21);
4770 outSISIDXREG(SISSR, 0x14, 0x34);
4771 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4772 goto bail_out;
4774 channelab = 1;
4775 outSISIDXREG(SISSR, 0x13, 0xa1);
4776 outSISIDXREG(SISSR, 0x14, 0x40);
4777 sr14 = 0x00;
4778 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4779 goto bail_out;
4781 outSISIDXREG(SISSR, 0x13, 0x21);
4782 outSISIDXREG(SISSR, 0x14, 0x30);
4783 } else {
4784 channelab = 3;
4785 outSISIDXREG(SISSR, 0x13, 0xa1);
4786 outSISIDXREG(SISSR, 0x14, 0x4c);
4787 sr14 = 0x0c;
4788 sisfb_post_xgi_delay(ivideo, 1);
4789 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4790 goto bail_out;
4792 channelab = 2;
4793 outSISIDXREG(SISSR, 0x14, 0x48);
4794 sisfb_post_xgi_delay(ivideo, 1);
4795 sr14 = 0x08;
4796 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4797 goto bail_out;
4799 outSISIDXREG(SISSR, 0x13, 0x21);
4800 outSISIDXREG(SISSR, 0x14, 0x3c);
4801 sr14 = 0x0c;
4803 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4804 channelab = 3;
4805 } else {
4806 channelab = 2;
4807 outSISIDXREG(SISSR, 0x14, 0x38);
4808 sr14 = 0x08;
4811 sisfb_post_xgi_delay(ivideo, 1);
4813 } else { /* DDR */
4815 buswidth = 64;
4816 if(ivideo->revision_id == 2) {
4817 channelab = 1;
4818 outSISIDXREG(SISSR, 0x13, 0xa1);
4819 outSISIDXREG(SISSR, 0x14, 0x52);
4820 sisfb_post_xgi_delay(ivideo, 1);
4821 sr14 = 0x02;
4822 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4823 goto bail_out;
4825 outSISIDXREG(SISSR, 0x13, 0x21);
4826 outSISIDXREG(SISSR, 0x14, 0x42);
4827 } else {
4828 channelab = 2;
4829 outSISIDXREG(SISSR, 0x13, 0xa1);
4830 outSISIDXREG(SISSR, 0x14, 0x5a);
4831 sisfb_post_xgi_delay(ivideo, 1);
4832 sr14 = 0x0a;
4833 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4834 goto bail_out;
4836 outSISIDXREG(SISSR, 0x13, 0x21);
4837 outSISIDXREG(SISSR, 0x14, 0x4a);
4839 sisfb_post_xgi_delay(ivideo, 1);
4844 bail_out:
4845 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4846 sisfb_post_xgi_delay(ivideo, 1);
4848 j = (ivideo->chip == XGI_20) ? 5 : 9;
4849 k = (ivideo->chip == XGI_20) ? 12 : 4;
4851 for(i = 0; i < k; i++) {
4853 reg = (ivideo->chip == XGI_20) ?
4854 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4855 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4856 sisfb_post_xgi_delay(ivideo, 50);
4858 ranksize = (ivideo->chip == XGI_20) ?
4859 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4861 inSISIDXREG(SISSR, 0x13, reg);
4862 if(reg & 0x80) ranksize <<= 1;
4864 if(ivideo->chip == XGI_20) {
4865 if(buswidth == 16) ranksize <<= 1;
4866 else if(buswidth == 32) ranksize <<= 2;
4867 } else {
4868 if(buswidth == 64) ranksize <<= 1;
4871 reg = 0;
4872 l = channelab;
4873 if(l == 3) l = 4;
4874 if((ranksize * l) <= 256) {
4875 while((ranksize >>= 1)) reg += 0x10;
4878 if(!reg) continue;
4880 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4881 sisfb_post_xgi_delay(ivideo, 1);
4883 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4884 break;
4887 iounmap(ivideo->video_vbase);
4890 static void __devinit
4891 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4893 u8 v1, v2, v3;
4894 int index;
4895 static const u8 cs90[8 * 3] = {
4896 0x16, 0x01, 0x01,
4897 0x3e, 0x03, 0x01,
4898 0x7c, 0x08, 0x01,
4899 0x79, 0x06, 0x01,
4900 0x29, 0x01, 0x81,
4901 0x5c, 0x23, 0x01,
4902 0x5c, 0x23, 0x01,
4903 0x5c, 0x23, 0x01
4905 static const u8 csb8[8 * 3] = {
4906 0x5c, 0x23, 0x01,
4907 0x29, 0x01, 0x01,
4908 0x7c, 0x08, 0x01,
4909 0x79, 0x06, 0x01,
4910 0x29, 0x01, 0x81,
4911 0x5c, 0x23, 0x01,
4912 0x5c, 0x23, 0x01,
4913 0x5c, 0x23, 0x01
4916 regb = 0; /* ! */
4918 index = regb * 3;
4919 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4920 if(ivideo->haveXGIROM) {
4921 v1 = ivideo->bios_abase[0x90 + index];
4922 v2 = ivideo->bios_abase[0x90 + index + 1];
4923 v3 = ivideo->bios_abase[0x90 + index + 2];
4925 outSISIDXREG(SISSR, 0x28, v1);
4926 outSISIDXREG(SISSR, 0x29, v2);
4927 outSISIDXREG(SISSR, 0x2a, v3);
4928 sisfb_post_xgi_delay(ivideo, 0x43);
4929 sisfb_post_xgi_delay(ivideo, 0x43);
4930 sisfb_post_xgi_delay(ivideo, 0x43);
4931 index = regb * 3;
4932 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4933 if(ivideo->haveXGIROM) {
4934 v1 = ivideo->bios_abase[0xb8 + index];
4935 v2 = ivideo->bios_abase[0xb8 + index + 1];
4936 v3 = ivideo->bios_abase[0xb8 + index + 2];
4938 outSISIDXREG(SISSR, 0x2e, v1);
4939 outSISIDXREG(SISSR, 0x2f, v2);
4940 outSISIDXREG(SISSR, 0x30, v3);
4941 sisfb_post_xgi_delay(ivideo, 0x43);
4942 sisfb_post_xgi_delay(ivideo, 0x43);
4943 sisfb_post_xgi_delay(ivideo, 0x43);
4946 static int __devinit
4947 sisfb_post_xgi(struct pci_dev *pdev)
4949 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4950 unsigned char *bios = ivideo->bios_abase;
4951 struct pci_dev *mypdev = NULL;
4952 const u8 *ptr, *ptr2;
4953 u8 v1, v2, v3, v4, v5, reg, ramtype;
4954 u32 rega, regb, regd;
4955 int i, j, k, index;
4956 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4957 static const u8 cs76[2] = { 0xa3, 0xfb };
4958 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4959 static const u8 cs158[8] = {
4960 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4962 static const u8 cs160[8] = {
4963 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4965 static const u8 cs168[8] = {
4966 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4968 static const u8 cs128[3 * 8] = {
4969 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4970 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4971 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4973 static const u8 cs148[2 * 8] = {
4974 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4975 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4977 static const u8 cs31a[8 * 4] = {
4978 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
4979 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
4980 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4981 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4983 static const u8 cs33a[8 * 4] = {
4984 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4985 0x00, 0x00, 0x00, 0x00, 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 cs45a[8 * 2] = {
4990 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
4991 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4993 static const u8 cs170[7 * 8] = {
4994 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4995 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4996 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
4997 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4998 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
4999 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5000 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5002 static const u8 cs1a8[3 * 8] = {
5003 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5004 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5005 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5007 static const u8 cs100[2 * 8] = {
5008 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5009 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5012 /* VGA enable */
5013 reg = inSISREG(SISVGAENABLE) | 0x01;
5014 outSISREG(SISVGAENABLE, reg);
5016 /* Misc */
5017 reg = inSISREG(SISMISCR) | 0x01;
5018 outSISREG(SISMISCW, reg);
5020 /* Unlock SR */
5021 outSISIDXREG(SISSR, 0x05, 0x86);
5022 inSISIDXREG(SISSR, 0x05, reg);
5023 if(reg != 0xa1)
5024 return 0;
5026 /* Clear some regs */
5027 for(i = 0; i < 0x22; i++) {
5028 if(0x06 + i == 0x20) continue;
5029 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5031 for(i = 0; i < 0x0b; i++) {
5032 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5034 for(i = 0; i < 0x10; i++) {
5035 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5038 ptr = cs78;
5039 if(ivideo->haveXGIROM) {
5040 ptr = (const u8 *)&bios[0x78];
5042 for(i = 0; i < 3; i++) {
5043 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5046 ptr = cs76;
5047 if(ivideo->haveXGIROM) {
5048 ptr = (const u8 *)&bios[0x76];
5050 for(i = 0; i < 2; i++) {
5051 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5054 v1 = 0x18; v2 = 0x00;
5055 if(ivideo->haveXGIROM) {
5056 v1 = bios[0x74];
5057 v2 = bios[0x75];
5059 outSISIDXREG(SISSR, 0x07, v1);
5060 outSISIDXREG(SISSR, 0x11, 0x0f);
5061 outSISIDXREG(SISSR, 0x1f, v2);
5062 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5063 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5064 outSISIDXREG(SISSR, 0x27, 0x74);
5066 ptr = cs7b;
5067 if(ivideo->haveXGIROM) {
5068 ptr = (const u8 *)&bios[0x7b];
5070 for(i = 0; i < 3; i++) {
5071 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5074 if(ivideo->chip == XGI_40) {
5075 if(ivideo->revision_id == 2) {
5076 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5078 outSISIDXREG(SISCR, 0x7d, 0xfe);
5079 outSISIDXREG(SISCR, 0x7e, 0x0f);
5081 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5082 andSISIDXREG(SISCR, 0x58, 0xd7);
5083 inSISIDXREG(SISCR, 0xcb, reg);
5084 if(reg & 0x20) {
5085 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5089 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5090 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5092 if(ivideo->chip == XGI_20) {
5093 outSISIDXREG(SISSR, 0x36, 0x70);
5094 } else {
5095 outSISIDXREG(SISVID, 0x00, 0x86);
5096 outSISIDXREG(SISVID, 0x32, 0x00);
5097 outSISIDXREG(SISVID, 0x30, 0x00);
5098 outSISIDXREG(SISVID, 0x32, 0x01);
5099 outSISIDXREG(SISVID, 0x30, 0x00);
5100 andSISIDXREG(SISVID, 0x2f, 0xdf);
5101 andSISIDXREG(SISCAP, 0x00, 0x3f);
5103 outSISIDXREG(SISPART1, 0x2f, 0x01);
5104 outSISIDXREG(SISPART1, 0x00, 0x00);
5105 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5106 outSISIDXREG(SISPART1, 0x2e, 0x08);
5107 andSISIDXREG(SISPART1, 0x35, 0x7f);
5108 andSISIDXREG(SISPART1, 0x50, 0xfe);
5110 inSISIDXREG(SISPART4, 0x00, reg);
5111 if(reg == 1 || reg == 2) {
5112 outSISIDXREG(SISPART2, 0x00, 0x1c);
5113 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5114 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5115 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5116 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5118 inSISIDXREG(SISPART4, 0x01, reg);
5119 if((reg & 0xf0) >= 0xb0) {
5120 inSISIDXREG(SISPART4, 0x23, reg);
5121 if(reg & 0x20) reg |= 0x40;
5122 outSISIDXREG(SISPART4, 0x23, reg);
5123 reg = (reg & 0x20) ? 0x02 : 0x00;
5124 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5128 v1 = bios[0x77];
5130 inSISIDXREG(SISSR, 0x3b, reg);
5131 if(reg & 0x02) {
5132 inSISIDXREG(SISSR, 0x3a, reg);
5133 v2 = (reg & 0x30) >> 3;
5134 if(!(v2 & 0x04)) v2 ^= 0x02;
5135 inSISIDXREG(SISSR, 0x39, reg);
5136 if(reg & 0x80) v2 |= 0x80;
5137 v2 |= 0x01;
5139 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5140 pci_dev_put(mypdev);
5141 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5142 v2 &= 0xf9;
5143 v2 |= 0x08;
5144 v1 &= 0xfe;
5145 } else {
5146 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
5147 if(!mypdev)
5148 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
5149 if(!mypdev)
5150 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
5151 if(mypdev) {
5152 pci_read_config_dword(mypdev, 0x94, &regd);
5153 regd &= 0xfffffeff;
5154 pci_write_config_dword(mypdev, 0x94, regd);
5155 v1 &= 0xfe;
5156 pci_dev_put(mypdev);
5157 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5158 v1 &= 0xfe;
5159 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5160 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5161 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5162 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5163 if((v2 & 0x06) == 4)
5164 v2 ^= 0x06;
5165 v2 |= 0x08;
5168 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5170 outSISIDXREG(SISSR, 0x22, v1);
5172 if(ivideo->revision_id == 2) {
5173 inSISIDXREG(SISSR, 0x3b, v1);
5174 inSISIDXREG(SISSR, 0x3a, v2);
5175 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5176 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5177 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5179 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
5180 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5181 * of nforce 2 ROM
5183 if(0)
5184 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5185 pci_dev_put(mypdev);
5189 v1 = 0x30;
5190 inSISIDXREG(SISSR, 0x3b, reg);
5191 inSISIDXREG(SISCR, 0x5f, v2);
5192 if((!(reg & 0x02)) && (v2 & 0x0e))
5193 v1 |= 0x08;
5194 outSISIDXREG(SISSR, 0x27, v1);
5196 if(bios[0x64] & 0x01) {
5197 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5200 v1 = bios[0x4f7];
5201 pci_read_config_dword(pdev, 0x50, &regd);
5202 regd = (regd >> 20) & 0x0f;
5203 if(regd == 1) {
5204 v1 &= 0xfc;
5205 orSISIDXREG(SISCR, 0x5f, 0x08);
5207 outSISIDXREG(SISCR, 0x48, v1);
5209 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5210 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5211 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5212 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5213 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5214 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5215 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5216 outSISIDXREG(SISCR, 0x74, 0xd0);
5217 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5218 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5219 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5220 v1 = bios[0x501];
5221 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
5222 v1 = 0xf0;
5223 pci_dev_put(mypdev);
5225 outSISIDXREG(SISCR, 0x77, v1);
5228 /* RAM type */
5230 regb = 0; /* ! */
5232 v1 = 0xff;
5233 if(ivideo->haveXGIROM) {
5234 v1 = bios[0x140 + regb];
5236 outSISIDXREG(SISCR, 0x6d, v1);
5238 ptr = cs128;
5239 if(ivideo->haveXGIROM) {
5240 ptr = (const u8 *)&bios[0x128];
5242 for(i = 0, j = 0; i < 3; i++, j += 8) {
5243 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5246 ptr = cs31a;
5247 ptr2 = cs33a;
5248 if(ivideo->haveXGIROM) {
5249 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5250 ptr = (const u8 *)&bios[index];
5251 ptr2 = (const u8 *)&bios[index + 0x20];
5253 for(i = 0; i < 2; i++) {
5254 if(i == 0) {
5255 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5256 rega = 0x6b;
5257 } else {
5258 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5259 rega = 0x6e;
5261 reg = 0x00;
5262 for(j = 0; j < 16; j++) {
5263 reg &= 0xf3;
5264 if(regd & 0x01) reg |= 0x04;
5265 if(regd & 0x02) reg |= 0x08;
5266 regd >>= 2;
5267 outSISIDXREG(SISCR, rega, reg);
5268 inSISIDXREG(SISCR, rega, reg);
5269 inSISIDXREG(SISCR, rega, reg);
5270 reg += 0x10;
5274 andSISIDXREG(SISCR, 0x6e, 0xfc);
5276 ptr = NULL;
5277 if(ivideo->haveXGIROM) {
5278 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5279 ptr = (const u8 *)&bios[index];
5281 for(i = 0; i < 4; i++) {
5282 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5283 reg = 0x00;
5284 for(j = 0; j < 2; j++) {
5285 regd = 0;
5286 if(ptr) {
5287 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5288 ptr += 4;
5290 /* reg = 0x00; */
5291 for(k = 0; k < 16; k++) {
5292 reg &= 0xfc;
5293 if(regd & 0x01) reg |= 0x01;
5294 if(regd & 0x02) reg |= 0x02;
5295 regd >>= 2;
5296 outSISIDXREG(SISCR, 0x6f, reg);
5297 inSISIDXREG(SISCR, 0x6f, reg);
5298 inSISIDXREG(SISCR, 0x6f, reg);
5299 reg += 0x08;
5304 ptr = cs148;
5305 if(ivideo->haveXGIROM) {
5306 ptr = (const u8 *)&bios[0x148];
5308 for(i = 0, j = 0; i < 2; i++, j += 8) {
5309 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5312 andSISIDXREG(SISCR, 0x89, 0x8f);
5314 ptr = cs45a;
5315 if(ivideo->haveXGIROM) {
5316 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5317 ptr = (const u8 *)&bios[index];
5319 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5320 reg = 0x80;
5321 for(i = 0; i < 5; i++) {
5322 reg &= 0xfc;
5323 if(regd & 0x01) reg |= 0x01;
5324 if(regd & 0x02) reg |= 0x02;
5325 regd >>= 2;
5326 outSISIDXREG(SISCR, 0x89, reg);
5327 inSISIDXREG(SISCR, 0x89, reg);
5328 inSISIDXREG(SISCR, 0x89, reg);
5329 reg += 0x10;
5332 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5333 if(ivideo->haveXGIROM) {
5334 v1 = bios[0x118 + regb];
5335 v2 = bios[0xf8 + regb];
5336 v3 = bios[0x120 + regb];
5337 v4 = bios[0x1ca];
5339 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5340 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5341 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5342 outSISIDXREG(SISCR, 0x41, v2);
5344 ptr = cs170;
5345 if(ivideo->haveXGIROM) {
5346 ptr = (const u8 *)&bios[0x170];
5348 for(i = 0, j = 0; i < 7; i++, j += 8) {
5349 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5352 outSISIDXREG(SISCR, 0x59, v3);
5354 ptr = cs1a8;
5355 if(ivideo->haveXGIROM) {
5356 ptr = (const u8 *)&bios[0x1a8];
5358 for(i = 0, j = 0; i < 3; i++, j += 8) {
5359 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5362 ptr = cs100;
5363 if(ivideo->haveXGIROM) {
5364 ptr = (const u8 *)&bios[0x100];
5366 for(i = 0, j = 0; i < 2; i++, j += 8) {
5367 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5370 outSISIDXREG(SISCR, 0xcf, v4);
5372 outSISIDXREG(SISCR, 0x83, 0x09);
5373 outSISIDXREG(SISCR, 0x87, 0x00);
5375 if(ivideo->chip == XGI_40) {
5376 if( (ivideo->revision_id == 1) ||
5377 (ivideo->revision_id == 2) ) {
5378 outSISIDXREG(SISCR, 0x8c, 0x87);
5382 outSISIDXREG(SISSR, 0x17, 0x00);
5383 outSISIDXREG(SISSR, 0x1a, 0x87);
5385 if(ivideo->chip == XGI_20) {
5386 outSISIDXREG(SISSR, 0x15, 0x00);
5387 outSISIDXREG(SISSR, 0x1c, 0x00);
5390 ramtype = 0x00; v1 = 0x10;
5391 if(ivideo->haveXGIROM) {
5392 ramtype = bios[0x62];
5393 v1 = bios[0x1d2];
5395 if(!(ramtype & 0x80)) {
5396 if(ivideo->chip == XGI_20) {
5397 outSISIDXREG(SISCR, 0x97, v1);
5398 inSISIDXREG(SISCR, 0x97, reg);
5399 if(reg & 0x10) {
5400 ramtype = (reg & 0x01) << 1;
5402 } else {
5403 inSISIDXREG(SISSR, 0x39, reg);
5404 ramtype = reg & 0x02;
5405 if(!(ramtype)) {
5406 inSISIDXREG(SISSR, 0x3a, reg);
5407 ramtype = (reg >> 1) & 0x01;
5411 ramtype &= 0x07;
5413 regb = 0; /* ! */
5415 switch(ramtype) {
5416 case 0:
5417 sisfb_post_xgi_setclocks(ivideo, regb);
5418 if((ivideo->chip == XGI_20) ||
5419 (ivideo->revision_id == 1) ||
5420 (ivideo->revision_id == 2)) {
5421 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5422 if(ivideo->haveXGIROM) {
5423 v1 = bios[regb + 0x158];
5424 v2 = bios[regb + 0x160];
5425 v3 = bios[regb + 0x168];
5427 outSISIDXREG(SISCR, 0x82, v1);
5428 outSISIDXREG(SISCR, 0x85, v2);
5429 outSISIDXREG(SISCR, 0x86, v3);
5430 } else {
5431 outSISIDXREG(SISCR, 0x82, 0x88);
5432 outSISIDXREG(SISCR, 0x86, 0x00);
5433 inSISIDXREG(SISCR, 0x86, reg);
5434 outSISIDXREG(SISCR, 0x86, 0x88);
5435 inSISIDXREG(SISCR, 0x86, reg);
5436 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5437 outSISIDXREG(SISCR, 0x82, 0x77);
5438 outSISIDXREG(SISCR, 0x85, 0x00);
5439 inSISIDXREG(SISCR, 0x85, reg);
5440 outSISIDXREG(SISCR, 0x85, 0x88);
5441 inSISIDXREG(SISCR, 0x85, reg);
5442 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5443 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5445 if(ivideo->chip == XGI_40) {
5446 outSISIDXREG(SISCR, 0x97, 0x00);
5448 outSISIDXREG(SISCR, 0x98, 0x01);
5449 outSISIDXREG(SISCR, 0x9a, 0x02);
5451 outSISIDXREG(SISSR, 0x18, 0x01);
5452 if((ivideo->chip == XGI_20) ||
5453 (ivideo->revision_id == 2)) {
5454 outSISIDXREG(SISSR, 0x19, 0x40);
5455 } else {
5456 outSISIDXREG(SISSR, 0x19, 0x20);
5458 outSISIDXREG(SISSR, 0x16, 0x00);
5459 outSISIDXREG(SISSR, 0x16, 0x80);
5460 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5461 sisfb_post_xgi_delay(ivideo, 0x43);
5462 sisfb_post_xgi_delay(ivideo, 0x43);
5463 sisfb_post_xgi_delay(ivideo, 0x43);
5464 outSISIDXREG(SISSR, 0x18, 0x00);
5465 if((ivideo->chip == XGI_20) ||
5466 (ivideo->revision_id == 2)) {
5467 outSISIDXREG(SISSR, 0x19, 0x40);
5468 } else {
5469 outSISIDXREG(SISSR, 0x19, 0x20);
5471 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5472 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5474 outSISIDXREG(SISSR, 0x16, 0x00);
5475 outSISIDXREG(SISSR, 0x16, 0x80);
5476 sisfb_post_xgi_delay(ivideo, 4);
5477 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5478 if(ivideo->haveXGIROM) {
5479 v1 = bios[0xf0];
5480 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5481 v2 = bios[index];
5482 v3 = bios[index + 1];
5483 v4 = bios[index + 2];
5484 v5 = bios[index + 3];
5486 outSISIDXREG(SISSR, 0x18, v1);
5487 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5488 outSISIDXREG(SISSR, 0x16, v2);
5489 outSISIDXREG(SISSR, 0x16, v3);
5490 sisfb_post_xgi_delay(ivideo, 0x43);
5491 outSISIDXREG(SISSR, 0x1b, 0x03);
5492 sisfb_post_xgi_delay(ivideo, 0x22);
5493 outSISIDXREG(SISSR, 0x18, v1);
5494 outSISIDXREG(SISSR, 0x19, 0x00);
5495 outSISIDXREG(SISSR, 0x16, v4);
5496 outSISIDXREG(SISSR, 0x16, v5);
5497 outSISIDXREG(SISSR, 0x1b, 0x00);
5498 break;
5499 case 1:
5500 outSISIDXREG(SISCR, 0x82, 0x77);
5501 outSISIDXREG(SISCR, 0x86, 0x00);
5502 inSISIDXREG(SISCR, 0x86, reg);
5503 outSISIDXREG(SISCR, 0x86, 0x88);
5504 inSISIDXREG(SISCR, 0x86, reg);
5505 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5506 if(ivideo->haveXGIROM) {
5507 v1 = bios[regb + 0x168];
5508 v2 = bios[regb + 0x160];
5509 v3 = bios[regb + 0x158];
5511 outSISIDXREG(SISCR, 0x86, v1);
5512 outSISIDXREG(SISCR, 0x82, 0x77);
5513 outSISIDXREG(SISCR, 0x85, 0x00);
5514 inSISIDXREG(SISCR, 0x85, reg);
5515 outSISIDXREG(SISCR, 0x85, 0x88);
5516 inSISIDXREG(SISCR, 0x85, reg);
5517 outSISIDXREG(SISCR, 0x85, v2);
5518 outSISIDXREG(SISCR, 0x82, v3);
5519 outSISIDXREG(SISCR, 0x98, 0x01);
5520 outSISIDXREG(SISCR, 0x9a, 0x02);
5522 outSISIDXREG(SISSR, 0x28, 0x64);
5523 outSISIDXREG(SISSR, 0x29, 0x63);
5524 sisfb_post_xgi_delay(ivideo, 15);
5525 outSISIDXREG(SISSR, 0x18, 0x00);
5526 outSISIDXREG(SISSR, 0x19, 0x20);
5527 outSISIDXREG(SISSR, 0x16, 0x00);
5528 outSISIDXREG(SISSR, 0x16, 0x80);
5529 outSISIDXREG(SISSR, 0x18, 0xc5);
5530 outSISIDXREG(SISSR, 0x19, 0x23);
5531 outSISIDXREG(SISSR, 0x16, 0x00);
5532 outSISIDXREG(SISSR, 0x16, 0x80);
5533 sisfb_post_xgi_delay(ivideo, 1);
5534 outSISIDXREG(SISCR, 0x97,0x11);
5535 sisfb_post_xgi_setclocks(ivideo, regb);
5536 sisfb_post_xgi_delay(ivideo, 0x46);
5537 outSISIDXREG(SISSR, 0x18, 0xc5);
5538 outSISIDXREG(SISSR, 0x19, 0x23);
5539 outSISIDXREG(SISSR, 0x16, 0x00);
5540 outSISIDXREG(SISSR, 0x16, 0x80);
5541 sisfb_post_xgi_delay(ivideo, 1);
5542 outSISIDXREG(SISSR, 0x1b, 0x04);
5543 sisfb_post_xgi_delay(ivideo, 1);
5544 outSISIDXREG(SISSR, 0x1b, 0x00);
5545 sisfb_post_xgi_delay(ivideo, 1);
5546 v1 = 0x31;
5547 if(ivideo->haveXGIROM) {
5548 v1 = bios[0xf0];
5550 outSISIDXREG(SISSR, 0x18, v1);
5551 outSISIDXREG(SISSR, 0x19, 0x06);
5552 outSISIDXREG(SISSR, 0x16, 0x04);
5553 outSISIDXREG(SISSR, 0x16, 0x84);
5554 sisfb_post_xgi_delay(ivideo, 1);
5555 break;
5556 default:
5557 sisfb_post_xgi_setclocks(ivideo, regb);
5558 if((ivideo->chip == XGI_40) &&
5559 ((ivideo->revision_id == 1) ||
5560 (ivideo->revision_id == 2))) {
5561 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5562 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5563 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5564 } else {
5565 outSISIDXREG(SISCR, 0x82, 0x88);
5566 outSISIDXREG(SISCR, 0x86, 0x00);
5567 inSISIDXREG(SISCR, 0x86, reg);
5568 outSISIDXREG(SISCR, 0x86, 0x88);
5569 outSISIDXREG(SISCR, 0x82, 0x77);
5570 outSISIDXREG(SISCR, 0x85, 0x00);
5571 inSISIDXREG(SISCR, 0x85, reg);
5572 outSISIDXREG(SISCR, 0x85, 0x88);
5573 inSISIDXREG(SISCR, 0x85, reg);
5574 v1 = cs160[regb]; v2 = cs158[regb];
5575 if(ivideo->haveXGIROM) {
5576 v1 = bios[regb + 0x160];
5577 v2 = bios[regb + 0x158];
5579 outSISIDXREG(SISCR, 0x85, v1);
5580 outSISIDXREG(SISCR, 0x82, v2);
5582 if(ivideo->chip == XGI_40) {
5583 outSISIDXREG(SISCR, 0x97, 0x11);
5585 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5586 outSISIDXREG(SISCR, 0x98, 0x01);
5587 } else {
5588 outSISIDXREG(SISCR, 0x98, 0x03);
5590 outSISIDXREG(SISCR, 0x9a, 0x02);
5592 if(ivideo->chip == XGI_40) {
5593 outSISIDXREG(SISSR, 0x18, 0x01);
5594 } else {
5595 outSISIDXREG(SISSR, 0x18, 0x00);
5597 outSISIDXREG(SISSR, 0x19, 0x40);
5598 outSISIDXREG(SISSR, 0x16, 0x00);
5599 outSISIDXREG(SISSR, 0x16, 0x80);
5600 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5601 sisfb_post_xgi_delay(ivideo, 0x43);
5602 sisfb_post_xgi_delay(ivideo, 0x43);
5603 sisfb_post_xgi_delay(ivideo, 0x43);
5604 outSISIDXREG(SISSR, 0x18, 0x00);
5605 outSISIDXREG(SISSR, 0x19, 0x40);
5606 outSISIDXREG(SISSR, 0x16, 0x00);
5607 outSISIDXREG(SISSR, 0x16, 0x80);
5609 sisfb_post_xgi_delay(ivideo, 4);
5610 v1 = 0x31;
5611 if(ivideo->haveXGIROM) {
5612 v1 = bios[0xf0];
5614 outSISIDXREG(SISSR, 0x18, v1);
5615 outSISIDXREG(SISSR, 0x19, 0x01);
5616 if(ivideo->chip == XGI_40) {
5617 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5618 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5619 } else {
5620 outSISIDXREG(SISSR, 0x16, 0x05);
5621 outSISIDXREG(SISSR, 0x16, 0x85);
5623 sisfb_post_xgi_delay(ivideo, 0x43);
5624 if(ivideo->chip == XGI_40) {
5625 outSISIDXREG(SISSR, 0x1b, 0x01);
5626 } else {
5627 outSISIDXREG(SISSR, 0x1b, 0x03);
5629 sisfb_post_xgi_delay(ivideo, 0x22);
5630 outSISIDXREG(SISSR, 0x18, v1);
5631 outSISIDXREG(SISSR, 0x19, 0x00);
5632 if(ivideo->chip == XGI_40) {
5633 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5634 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5635 } else {
5636 outSISIDXREG(SISSR, 0x16, 0x05);
5637 outSISIDXREG(SISSR, 0x16, 0x85);
5639 outSISIDXREG(SISSR, 0x1b, 0x00);
5642 regb = 0; /* ! */
5643 v1 = 0x03;
5644 if(ivideo->haveXGIROM) {
5645 v1 = bios[0x110 + regb];
5647 outSISIDXREG(SISSR, 0x1b, v1);
5649 /* RAM size */
5650 v1 = 0x00; v2 = 0x00;
5651 if(ivideo->haveXGIROM) {
5652 v1 = bios[0x62];
5653 v2 = bios[0x63];
5655 regb = 0; /* ! */
5656 regd = 1 << regb;
5657 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5659 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5660 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5662 } else {
5664 /* Set default mode, don't clear screen */
5665 ivideo->SiS_Pr.SiS_UseOEM = false;
5666 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5667 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5668 ivideo->curFSTN = ivideo->curDSTN = 0;
5669 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5670 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5672 outSISIDXREG(SISSR, 0x05, 0x86);
5674 /* Disable read-cache */
5675 andSISIDXREG(SISSR, 0x21, 0xdf);
5676 sisfb_post_xgi_ramsize(ivideo);
5677 /* Enable read-cache */
5678 orSISIDXREG(SISSR, 0x21, 0x20);
5682 #if 0
5683 printk(KERN_DEBUG "-----------------\n");
5684 for(i = 0; i < 0xff; i++) {
5685 inSISIDXREG(SISCR, i, reg);
5686 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5688 for(i = 0; i < 0x40; i++) {
5689 inSISIDXREG(SISSR, i, reg);
5690 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5692 printk(KERN_DEBUG "-----------------\n");
5693 #endif
5695 /* Sense CRT1 */
5696 if(ivideo->chip == XGI_20) {
5697 orSISIDXREG(SISCR, 0x32, 0x20);
5698 } else {
5699 inSISIDXREG(SISPART4, 0x00, reg);
5700 if((reg == 1) || (reg == 2)) {
5701 sisfb_sense_crt1(ivideo);
5702 } else {
5703 orSISIDXREG(SISCR, 0x32, 0x20);
5707 /* Set default mode, don't clear screen */
5708 ivideo->SiS_Pr.SiS_UseOEM = false;
5709 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5710 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5711 ivideo->curFSTN = ivideo->curDSTN = 0;
5712 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5714 outSISIDXREG(SISSR, 0x05, 0x86);
5716 /* Display off */
5717 orSISIDXREG(SISSR, 0x01, 0x20);
5719 /* Save mode number in CR34 */
5720 outSISIDXREG(SISCR, 0x34, 0x2e);
5722 /* Let everyone know what the current mode is */
5723 ivideo->modeprechange = 0x2e;
5725 if(ivideo->chip == XGI_40) {
5726 inSISIDXREG(SISCR, 0xca, reg);
5727 inSISIDXREG(SISCR, 0xcc, v1);
5728 if((reg & 0x10) && (!(v1 & 0x04))) {
5729 printk(KERN_ERR
5730 "sisfb: Please connect power to the card.\n");
5731 return 0;
5735 return 1;
5737 #endif
5739 static int __devinit
5740 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5742 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5743 struct sis_video_info *ivideo = NULL;
5744 struct fb_info *sis_fb_info = NULL;
5745 u16 reg16;
5746 u8 reg;
5747 int i, ret;
5749 if(sisfb_off)
5750 return -ENXIO;
5752 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5753 if(!sis_fb_info)
5754 return -ENOMEM;
5756 ivideo = (struct sis_video_info *)sis_fb_info->par;
5757 ivideo->memyselfandi = sis_fb_info;
5759 ivideo->sisfb_id = SISFB_ID;
5761 if(card_list == NULL) {
5762 ivideo->cardnumber = 0;
5763 } else {
5764 struct sis_video_info *countvideo = card_list;
5765 ivideo->cardnumber = 1;
5766 while((countvideo = countvideo->next) != NULL)
5767 ivideo->cardnumber++;
5770 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5772 ivideo->warncount = 0;
5773 ivideo->chip_id = pdev->device;
5774 ivideo->chip_vendor = pdev->vendor;
5775 ivideo->revision_id = pdev->revision;
5776 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5777 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
5778 ivideo->sisvga_enabled = reg16 & 0x01;
5779 ivideo->pcibus = pdev->bus->number;
5780 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5781 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5782 ivideo->subsysvendor = pdev->subsystem_vendor;
5783 ivideo->subsysdevice = pdev->subsystem_device;
5785 #ifndef MODULE
5786 if(sisfb_mode_idx == -1) {
5787 sisfb_get_vga_mode_from_kernel();
5789 #endif
5791 ivideo->chip = chipinfo->chip;
5792 ivideo->sisvga_engine = chipinfo->vgaengine;
5793 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5794 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5795 ivideo->mni = chipinfo->mni;
5797 ivideo->detectedpdc = 0xff;
5798 ivideo->detectedpdca = 0xff;
5799 ivideo->detectedlcda = 0xff;
5801 ivideo->sisfb_thismonitor.datavalid = false;
5803 ivideo->current_base = 0;
5805 ivideo->engineok = 0;
5807 ivideo->sisfb_was_boot_device = 0;
5809 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5810 if(ivideo->sisvga_enabled)
5811 ivideo->sisfb_was_boot_device = 1;
5812 else {
5813 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5814 "but marked as boot video device ???\n");
5815 printk(KERN_DEBUG "sisfb: I will not accept this "
5816 "as the primary VGA device\n");
5820 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5821 ivideo->sisfb_accel = sisfb_accel;
5822 ivideo->sisfb_ypan = sisfb_ypan;
5823 ivideo->sisfb_max = sisfb_max;
5824 ivideo->sisfb_userom = sisfb_userom;
5825 ivideo->sisfb_useoem = sisfb_useoem;
5826 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5827 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5828 ivideo->sisfb_crt1off = sisfb_crt1off;
5829 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5830 ivideo->sisfb_crt2type = sisfb_crt2type;
5831 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5832 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5833 ivideo->sisfb_dstn = sisfb_dstn;
5834 ivideo->sisfb_fstn = sisfb_fstn;
5835 ivideo->sisfb_tvplug = sisfb_tvplug;
5836 ivideo->sisfb_tvstd = sisfb_tvstd;
5837 ivideo->tvxpos = sisfb_tvxposoffset;
5838 ivideo->tvypos = sisfb_tvyposoffset;
5839 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5840 ivideo->refresh_rate = 0;
5841 if(ivideo->sisfb_parm_rate != -1) {
5842 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5845 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5846 ivideo->SiS_Pr.CenterScreen = -1;
5847 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5848 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5850 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5851 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5852 ivideo->SiS_Pr.SiS_ChSW = false;
5853 ivideo->SiS_Pr.SiS_UseLCDA = false;
5854 ivideo->SiS_Pr.HaveEMI = false;
5855 ivideo->SiS_Pr.HaveEMILCD = false;
5856 ivideo->SiS_Pr.OverruleEMI = false;
5857 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
5858 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5859 ivideo->SiS_Pr.PDC = -1;
5860 ivideo->SiS_Pr.PDCA = -1;
5861 ivideo->SiS_Pr.DDCPortMixup = false;
5862 #ifdef CONFIG_FB_SIS_315
5863 if(ivideo->chip >= SIS_330) {
5864 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5865 if(ivideo->chip >= SIS_661) {
5866 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
5869 #endif
5871 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5873 pci_set_drvdata(pdev, ivideo);
5875 /* Patch special cases */
5876 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5877 switch(ivideo->nbridge->device) {
5878 #ifdef CONFIG_FB_SIS_300
5879 case PCI_DEVICE_ID_SI_730:
5880 ivideo->chip = SIS_730;
5881 strcpy(ivideo->myid, "SiS 730");
5882 break;
5883 #endif
5884 #ifdef CONFIG_FB_SIS_315
5885 case PCI_DEVICE_ID_SI_651:
5886 /* ivideo->chip is ok */
5887 strcpy(ivideo->myid, "SiS 651");
5888 break;
5889 case PCI_DEVICE_ID_SI_740:
5890 ivideo->chip = SIS_740;
5891 strcpy(ivideo->myid, "SiS 740");
5892 break;
5893 case PCI_DEVICE_ID_SI_661:
5894 ivideo->chip = SIS_661;
5895 strcpy(ivideo->myid, "SiS 661");
5896 break;
5897 case PCI_DEVICE_ID_SI_741:
5898 ivideo->chip = SIS_741;
5899 strcpy(ivideo->myid, "SiS 741");
5900 break;
5901 case PCI_DEVICE_ID_SI_760:
5902 ivideo->chip = SIS_760;
5903 strcpy(ivideo->myid, "SiS 760");
5904 break;
5905 case PCI_DEVICE_ID_SI_761:
5906 ivideo->chip = SIS_761;
5907 strcpy(ivideo->myid, "SiS 761");
5908 break;
5909 #endif
5910 default:
5911 break;
5915 ivideo->SiS_Pr.ChipType = ivideo->chip;
5917 ivideo->SiS_Pr.ivideo = (void *)ivideo;
5919 #ifdef CONFIG_FB_SIS_315
5920 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5921 (ivideo->SiS_Pr.ChipType == SIS_315)) {
5922 ivideo->SiS_Pr.ChipType = SIS_315H;
5924 #endif
5926 if(!ivideo->sisvga_enabled) {
5927 if(pci_enable_device(pdev)) {
5928 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
5929 pci_set_drvdata(pdev, NULL);
5930 framebuffer_release(sis_fb_info);
5931 return -EIO;
5935 ivideo->video_base = pci_resource_start(pdev, 0);
5936 ivideo->mmio_base = pci_resource_start(pdev, 1);
5937 ivideo->mmio_size = pci_resource_len(pdev, 1);
5938 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
5939 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
5941 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
5943 #ifdef CONFIG_FB_SIS_300
5944 /* Find PCI systems for Chrontel/GPIO communication setup */
5945 if(ivideo->chip == SIS_630) {
5946 i = 0;
5947 do {
5948 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5949 mychswtable[i].subsysCard == ivideo->subsysdevice) {
5950 ivideo->SiS_Pr.SiS_ChSW = true;
5951 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5952 "requiring Chrontel/GPIO setup\n",
5953 mychswtable[i].vendorName,
5954 mychswtable[i].cardName);
5955 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
5956 break;
5958 i++;
5959 } while(mychswtable[i].subsysVendor != 0);
5961 #endif
5963 #ifdef CONFIG_FB_SIS_315
5964 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
5965 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
5967 #endif
5969 outSISIDXREG(SISSR, 0x05, 0x86);
5971 if( (!ivideo->sisvga_enabled)
5972 #if !defined(__i386__) && !defined(__x86_64__)
5973 || (sisfb_resetcard)
5974 #endif
5976 for(i = 0x30; i <= 0x3f; i++) {
5977 outSISIDXREG(SISCR, i, 0x00);
5981 /* Find out about current video mode */
5982 ivideo->modeprechange = 0x03;
5983 inSISIDXREG(SISCR, 0x34, reg);
5984 if(reg & 0x7f) {
5985 ivideo->modeprechange = reg & 0x7f;
5986 } else if(ivideo->sisvga_enabled) {
5987 #if defined(__i386__) || defined(__x86_64__)
5988 unsigned char __iomem *tt = ioremap(0x400, 0x100);
5989 if(tt) {
5990 ivideo->modeprechange = readb(tt + 0x49);
5991 iounmap(tt);
5993 #endif
5996 /* Search and copy ROM image */
5997 ivideo->bios_abase = NULL;
5998 ivideo->SiS_Pr.VirtualRomBase = NULL;
5999 ivideo->SiS_Pr.UseROM = false;
6000 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
6001 if(ivideo->sisfb_userom) {
6002 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6003 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6004 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
6005 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6006 ivideo->SiS_Pr.UseROM ? "" : "not ");
6007 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6008 ivideo->SiS_Pr.UseROM = false;
6009 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
6010 if( (ivideo->revision_id == 2) &&
6011 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6012 ivideo->SiS_Pr.DDCPortMixup = true;
6015 } else {
6016 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6019 /* Find systems for special custom timing */
6020 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6021 sisfb_detect_custom_timing(ivideo);
6024 /* POST card in case this has not been done by the BIOS */
6025 if( (!ivideo->sisvga_enabled)
6026 #if !defined(__i386__) && !defined(__x86_64__)
6027 || (sisfb_resetcard)
6028 #endif
6030 #ifdef CONFIG_FB_SIS_300
6031 if(ivideo->sisvga_engine == SIS_300_VGA) {
6032 if(ivideo->chip == SIS_300) {
6033 sisfb_post_sis300(pdev);
6034 ivideo->sisfb_can_post = 1;
6037 #endif
6039 #ifdef CONFIG_FB_SIS_315
6040 if(ivideo->sisvga_engine == SIS_315_VGA) {
6041 int result = 1;
6042 /* if((ivideo->chip == SIS_315H) ||
6043 (ivideo->chip == SIS_315) ||
6044 (ivideo->chip == SIS_315PRO) ||
6045 (ivideo->chip == SIS_330)) {
6046 sisfb_post_sis315330(pdev);
6047 } else */ if(ivideo->chip == XGI_20) {
6048 result = sisfb_post_xgi(pdev);
6049 ivideo->sisfb_can_post = 1;
6050 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6051 result = sisfb_post_xgi(pdev);
6052 ivideo->sisfb_can_post = 1;
6053 } else {
6054 printk(KERN_INFO "sisfb: Card is not "
6055 "POSTed and sisfb can't do this either.\n");
6057 if(!result) {
6058 printk(KERN_ERR "sisfb: Failed to POST card\n");
6059 ret = -ENODEV;
6060 goto error_3;
6063 #endif
6066 ivideo->sisfb_card_posted = 1;
6068 /* Find out about RAM size */
6069 if(sisfb_get_dram_size(ivideo)) {
6070 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6071 ret = -ENODEV;
6072 goto error_3;
6076 /* Enable PCI addressing and MMIO */
6077 if((ivideo->sisfb_mode_idx < 0) ||
6078 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6079 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6080 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6081 /* Enable 2D accelerator engine */
6082 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6085 if(sisfb_pdc != 0xff) {
6086 if(ivideo->sisvga_engine == SIS_300_VGA)
6087 sisfb_pdc &= 0x3c;
6088 else
6089 sisfb_pdc &= 0x1f;
6090 ivideo->SiS_Pr.PDC = sisfb_pdc;
6092 #ifdef CONFIG_FB_SIS_315
6093 if(ivideo->sisvga_engine == SIS_315_VGA) {
6094 if(sisfb_pdca != 0xff)
6095 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6097 #endif
6099 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6100 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6101 (int)(ivideo->video_size >> 20));
6102 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6103 ret = -ENODEV;
6104 goto error_3;
6107 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6108 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6109 ret = -ENODEV;
6110 goto error_2;
6113 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6114 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6115 if(!ivideo->video_vbase) {
6116 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6117 ret = -ENODEV;
6118 goto error_1;
6121 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6122 if(!ivideo->mmio_vbase) {
6123 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6124 ret = -ENODEV;
6125 error_0: iounmap(ivideo->video_vbase);
6126 error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6127 error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6128 error_3: vfree(ivideo->bios_abase);
6129 if(ivideo->lpcdev)
6130 pci_dev_put(ivideo->lpcdev);
6131 if(ivideo->nbridge)
6132 pci_dev_put(ivideo->nbridge);
6133 pci_set_drvdata(pdev, NULL);
6134 if(!ivideo->sisvga_enabled)
6135 pci_disable_device(pdev);
6136 framebuffer_release(sis_fb_info);
6137 return ret;
6140 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6141 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6143 if(ivideo->video_offset) {
6144 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6145 ivideo->video_offset / 1024);
6148 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6149 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6152 /* Determine the size of the command queue */
6153 if(ivideo->sisvga_engine == SIS_300_VGA) {
6154 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6155 } else {
6156 if(ivideo->chip == XGI_20) {
6157 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6158 } else {
6159 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6163 /* Engines are no longer initialized here; this is
6164 * now done after the first mode-switch (if the
6165 * submitted var has its acceleration flags set).
6168 /* Calculate the base of the (unused) hw cursor */
6169 ivideo->hwcursor_vbase = ivideo->video_vbase
6170 + ivideo->video_size
6171 - ivideo->cmdQueueSize
6172 - ivideo->hwcursor_size;
6173 ivideo->caps |= HW_CURSOR_CAP;
6175 /* Initialize offscreen memory manager */
6176 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6177 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6180 /* Used for clearing the screen only, therefore respect our mem limit */
6181 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6182 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6184 ivideo->mtrr = -1;
6186 ivideo->vbflags = 0;
6187 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6188 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6189 ivideo->defmodeidx = DEFAULT_MODE;
6191 ivideo->newrom = 0;
6192 if(ivideo->chip < XGI_20) {
6193 if(ivideo->bios_abase) {
6194 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6198 if((ivideo->sisfb_mode_idx < 0) ||
6199 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6201 sisfb_sense_crt1(ivideo);
6203 sisfb_get_VB_type(ivideo);
6205 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6206 sisfb_detect_VB_connect(ivideo);
6209 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6211 /* Decide on which CRT2 device to use */
6212 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6213 if(ivideo->sisfb_crt2type != -1) {
6214 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6215 (ivideo->vbflags & CRT2_LCD)) {
6216 ivideo->currentvbflags |= CRT2_LCD;
6217 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6218 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6220 } else {
6221 /* Chrontel 700x TV detection often unreliable, therefore
6222 * use a different default order on such machines
6224 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6225 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6226 if(ivideo->vbflags & CRT2_LCD)
6227 ivideo->currentvbflags |= CRT2_LCD;
6228 else if(ivideo->vbflags & CRT2_TV)
6229 ivideo->currentvbflags |= CRT2_TV;
6230 else if(ivideo->vbflags & CRT2_VGA)
6231 ivideo->currentvbflags |= CRT2_VGA;
6232 } else {
6233 if(ivideo->vbflags & CRT2_TV)
6234 ivideo->currentvbflags |= CRT2_TV;
6235 else if(ivideo->vbflags & CRT2_LCD)
6236 ivideo->currentvbflags |= CRT2_LCD;
6237 else if(ivideo->vbflags & CRT2_VGA)
6238 ivideo->currentvbflags |= CRT2_VGA;
6243 if(ivideo->vbflags & CRT2_LCD) {
6244 sisfb_detect_lcd_type(ivideo);
6247 sisfb_save_pdc_emi(ivideo);
6249 if(!ivideo->sisfb_crt1off) {
6250 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6251 } else {
6252 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6253 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6254 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6258 if(ivideo->sisfb_mode_idx >= 0) {
6259 int bu = ivideo->sisfb_mode_idx;
6260 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6261 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6262 if(bu != ivideo->sisfb_mode_idx) {
6263 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6264 sisbios_mode[bu].xres,
6265 sisbios_mode[bu].yres,
6266 sisbios_mode[bu].bpp);
6270 if(ivideo->sisfb_mode_idx < 0) {
6271 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6272 case CRT2_LCD:
6273 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6274 break;
6275 case CRT2_TV:
6276 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6277 break;
6278 default:
6279 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6280 break;
6284 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6286 if(ivideo->refresh_rate != 0) {
6287 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6288 ivideo->sisfb_mode_idx);
6291 if(ivideo->rate_idx == 0) {
6292 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6293 ivideo->refresh_rate = 60;
6296 if(ivideo->sisfb_thismonitor.datavalid) {
6297 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6298 ivideo->sisfb_mode_idx,
6299 ivideo->rate_idx,
6300 ivideo->refresh_rate)) {
6301 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6302 "exceeds monitor specs!\n");
6306 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6307 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6308 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6310 sisfb_set_vparms(ivideo);
6312 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6313 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6314 ivideo->refresh_rate);
6316 /* Set up the default var according to chosen default display mode */
6317 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6318 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6319 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6321 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6323 ivideo->default_var.pixclock = (u32) (1000000000 /
6324 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6326 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6327 ivideo->rate_idx, &ivideo->default_var)) {
6328 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6329 ivideo->default_var.pixclock <<= 1;
6333 if(ivideo->sisfb_ypan) {
6334 /* Maximize regardless of sisfb_max at startup */
6335 ivideo->default_var.yres_virtual =
6336 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6337 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6338 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6342 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6344 ivideo->accel = 0;
6345 if(ivideo->sisfb_accel) {
6346 ivideo->accel = -1;
6347 #ifdef STUPID_ACCELF_TEXT_SHIT
6348 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6349 #endif
6351 sisfb_initaccel(ivideo);
6353 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6354 sis_fb_info->flags = FBINFO_DEFAULT |
6355 FBINFO_HWACCEL_YPAN |
6356 FBINFO_HWACCEL_XPAN |
6357 FBINFO_HWACCEL_COPYAREA |
6358 FBINFO_HWACCEL_FILLRECT |
6359 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6360 #else
6361 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6362 #endif
6363 sis_fb_info->var = ivideo->default_var;
6364 sis_fb_info->fix = ivideo->sisfb_fix;
6365 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6366 sis_fb_info->fbops = &sisfb_ops;
6367 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6369 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6371 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6373 #ifdef CONFIG_MTRR
6374 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6375 MTRR_TYPE_WRCOMB, 1);
6376 if(ivideo->mtrr < 0) {
6377 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6379 #endif
6381 if(register_framebuffer(sis_fb_info) < 0) {
6382 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6383 ret = -EINVAL;
6384 iounmap(ivideo->mmio_vbase);
6385 goto error_0;
6388 ivideo->registered = 1;
6390 /* Enlist us */
6391 ivideo->next = card_list;
6392 card_list = ivideo;
6394 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6395 ivideo->sisfb_accel ? "enabled" : "disabled",
6396 ivideo->sisfb_ypan ?
6397 (ivideo->sisfb_max ? "enabled (auto-max)" :
6398 "enabled (no auto-max)") :
6399 "disabled");
6402 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6403 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6405 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6407 } /* if mode = "none" */
6409 return 0;
6412 /*****************************************************/
6413 /* PCI DEVICE HANDLING */
6414 /*****************************************************/
6416 static void __devexit sisfb_remove(struct pci_dev *pdev)
6418 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6419 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6420 int registered = ivideo->registered;
6421 int modechanged = ivideo->modechanged;
6423 /* Unmap */
6424 iounmap(ivideo->mmio_vbase);
6425 iounmap(ivideo->video_vbase);
6427 /* Release mem regions */
6428 release_mem_region(ivideo->video_base, ivideo->video_size);
6429 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6431 vfree(ivideo->bios_abase);
6433 if(ivideo->lpcdev)
6434 pci_dev_put(ivideo->lpcdev);
6436 if(ivideo->nbridge)
6437 pci_dev_put(ivideo->nbridge);
6439 #ifdef CONFIG_MTRR
6440 /* Release MTRR region */
6441 if(ivideo->mtrr >= 0)
6442 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6443 #endif
6445 pci_set_drvdata(pdev, NULL);
6447 /* If device was disabled when starting, disable
6448 * it when quitting.
6450 if(!ivideo->sisvga_enabled)
6451 pci_disable_device(pdev);
6453 /* Unregister the framebuffer */
6454 if(ivideo->registered) {
6455 unregister_framebuffer(sis_fb_info);
6456 framebuffer_release(sis_fb_info);
6459 /* OK, our ivideo is gone for good from here. */
6461 /* TODO: Restore the initial mode
6462 * This sounds easy but is as good as impossible
6463 * on many machines with SiS chip and video bridge
6464 * since text modes are always set up differently
6465 * from machine to machine. Depends on the type
6466 * of integration between chipset and bridge.
6468 if(registered && modechanged)
6469 printk(KERN_INFO
6470 "sisfb: Restoring of text mode not supported yet\n");
6473 static struct pci_driver sisfb_driver = {
6474 .name = "sisfb",
6475 .id_table = sisfb_pci_table,
6476 .probe = sisfb_probe,
6477 .remove = __devexit_p(sisfb_remove)
6480 static int __init sisfb_init(void)
6482 #ifndef MODULE
6483 char *options = NULL;
6485 if(fb_get_options("sisfb", &options))
6486 return -ENODEV;
6488 sisfb_setup(options);
6489 #endif
6490 return pci_register_driver(&sisfb_driver);
6493 #ifndef MODULE
6494 module_init(sisfb_init);
6495 #endif
6497 /*****************************************************/
6498 /* MODULE */
6499 /*****************************************************/
6501 #ifdef MODULE
6503 static char *mode = NULL;
6504 static int vesa = -1;
6505 static unsigned int rate = 0;
6506 static unsigned int crt1off = 1;
6507 static unsigned int mem = 0;
6508 static char *forcecrt2type = NULL;
6509 static int forcecrt1 = -1;
6510 static int pdc = -1;
6511 static int pdc1 = -1;
6512 static int noaccel = -1;
6513 static int noypan = -1;
6514 static int nomax = -1;
6515 static int userom = -1;
6516 static int useoem = -1;
6517 static char *tvstandard = NULL;
6518 static int nocrt2rate = 0;
6519 static int scalelcd = -1;
6520 static char *specialtiming = NULL;
6521 static int lvdshl = -1;
6522 static int tvxposoffset = 0, tvyposoffset = 0;
6523 #if !defined(__i386__) && !defined(__x86_64__)
6524 static int resetcard = 0;
6525 static int videoram = 0;
6526 #endif
6528 static int __init sisfb_init_module(void)
6530 sisfb_setdefaultparms();
6532 if(rate)
6533 sisfb_parm_rate = rate;
6535 if((scalelcd == 0) || (scalelcd == 1))
6536 sisfb_scalelcd = scalelcd ^ 1;
6538 /* Need to check crt2 type first for fstn/dstn */
6540 if(forcecrt2type)
6541 sisfb_search_crt2type(forcecrt2type);
6543 if(tvstandard)
6544 sisfb_search_tvstd(tvstandard);
6546 if(mode)
6547 sisfb_search_mode(mode, false);
6548 else if(vesa != -1)
6549 sisfb_search_vesamode(vesa, false);
6551 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6553 sisfb_forcecrt1 = forcecrt1;
6554 if(forcecrt1 == 1)
6555 sisfb_crt1off = 0;
6556 else if(forcecrt1 == 0)
6557 sisfb_crt1off = 1;
6559 if(noaccel == 1)
6560 sisfb_accel = 0;
6561 else if(noaccel == 0)
6562 sisfb_accel = 1;
6564 if(noypan == 1)
6565 sisfb_ypan = 0;
6566 else if(noypan == 0)
6567 sisfb_ypan = 1;
6569 if(nomax == 1)
6570 sisfb_max = 0;
6571 else if(nomax == 0)
6572 sisfb_max = 1;
6574 if(mem)
6575 sisfb_parm_mem = mem;
6577 if(userom != -1)
6578 sisfb_userom = userom;
6580 if(useoem != -1)
6581 sisfb_useoem = useoem;
6583 if(pdc != -1)
6584 sisfb_pdc = (pdc & 0x7f);
6586 if(pdc1 != -1)
6587 sisfb_pdca = (pdc1 & 0x1f);
6589 sisfb_nocrt2rate = nocrt2rate;
6591 if(specialtiming)
6592 sisfb_search_specialtiming(specialtiming);
6594 if((lvdshl >= 0) && (lvdshl <= 3))
6595 sisfb_lvdshl = lvdshl;
6597 sisfb_tvxposoffset = tvxposoffset;
6598 sisfb_tvyposoffset = tvyposoffset;
6600 #if !defined(__i386__) && !defined(__x86_64__)
6601 sisfb_resetcard = (resetcard) ? 1 : 0;
6602 if(videoram)
6603 sisfb_videoram = videoram;
6604 #endif
6606 return sisfb_init();
6609 static void __exit sisfb_remove_module(void)
6611 pci_unregister_driver(&sisfb_driver);
6612 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6615 module_init(sisfb_init_module);
6616 module_exit(sisfb_remove_module);
6618 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6619 MODULE_LICENSE("GPL");
6620 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6622 module_param(mem, int, 0);
6623 module_param(noaccel, int, 0);
6624 module_param(noypan, int, 0);
6625 module_param(nomax, int, 0);
6626 module_param(userom, int, 0);
6627 module_param(useoem, int, 0);
6628 module_param(mode, charp, 0);
6629 module_param(vesa, int, 0);
6630 module_param(rate, int, 0);
6631 module_param(forcecrt1, int, 0);
6632 module_param(forcecrt2type, charp, 0);
6633 module_param(scalelcd, int, 0);
6634 module_param(pdc, int, 0);
6635 module_param(pdc1, int, 0);
6636 module_param(specialtiming, charp, 0);
6637 module_param(lvdshl, int, 0);
6638 module_param(tvstandard, charp, 0);
6639 module_param(tvxposoffset, int, 0);
6640 module_param(tvyposoffset, int, 0);
6641 module_param(nocrt2rate, int, 0);
6642 #if !defined(__i386__) && !defined(__x86_64__)
6643 module_param(resetcard, int, 0);
6644 module_param(videoram, int, 0);
6645 #endif
6647 MODULE_PARM_DESC(mem,
6648 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6649 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6650 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6651 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6652 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6653 "The value is to be specified without 'KB'.\n");
6655 MODULE_PARM_DESC(noaccel,
6656 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6657 "(default: 0)\n");
6659 MODULE_PARM_DESC(noypan,
6660 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6661 "will be performed by redrawing the screen. (default: 0)\n");
6663 MODULE_PARM_DESC(nomax,
6664 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
6665 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6666 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6667 "enable the user to positively specify a virtual Y size of the screen using\n"
6668 "fbset. (default: 0)\n");
6670 MODULE_PARM_DESC(mode,
6671 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6672 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
6673 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6674 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6676 MODULE_PARM_DESC(vesa,
6677 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6678 "0x117 (default: 0x0103)\n");
6680 MODULE_PARM_DESC(rate,
6681 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6682 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6683 "will be ignored (default: 60)\n");
6685 MODULE_PARM_DESC(forcecrt1,
6686 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6687 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6688 "0=CRT1 OFF) (default: [autodetected])\n");
6690 MODULE_PARM_DESC(forcecrt2type,
6691 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6692 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6693 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6694 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6695 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6696 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6697 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6698 "depends on the very hardware in use. (default: [autodetected])\n");
6700 MODULE_PARM_DESC(scalelcd,
6701 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6702 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6703 "show black bars around the image, TMDS panels will probably do the scaling\n"
6704 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6706 MODULE_PARM_DESC(pdc,
6707 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
6708 "should detect this correctly in most cases; however, sometimes this is not\n"
6709 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
6710 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6711 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6712 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
6714 #ifdef CONFIG_FB_SIS_315
6715 MODULE_PARM_DESC(pdc1,
6716 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
6717 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6718 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6719 "implemented yet.\n");
6720 #endif
6722 MODULE_PARM_DESC(specialtiming,
6723 "\nPlease refer to documentation for more information on this option.\n");
6725 MODULE_PARM_DESC(lvdshl,
6726 "\nPlease refer to documentation for more information on this option.\n");
6728 MODULE_PARM_DESC(tvstandard,
6729 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6730 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6732 MODULE_PARM_DESC(tvxposoffset,
6733 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6734 "Default: 0\n");
6736 MODULE_PARM_DESC(tvyposoffset,
6737 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6738 "Default: 0\n");
6740 MODULE_PARM_DESC(nocrt2rate,
6741 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6742 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6744 #if !defined(__i386__) && !defined(__x86_64__)
6745 #ifdef CONFIG_FB_SIS_300
6746 MODULE_PARM_DESC(resetcard,
6747 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
6748 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6749 "currently). Default: 0\n");
6751 MODULE_PARM_DESC(videoram,
6752 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6753 "some non-x86 architectures where the memory auto detection fails. Only\n"
6754 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
6755 #endif
6756 #endif
6758 #endif /* /MODULE */
6760 /* _GPL only for new symbols. */
6761 EXPORT_SYMBOL(sis_malloc);
6762 EXPORT_SYMBOL(sis_free);
6763 EXPORT_SYMBOL_GPL(sis_malloc_new);
6764 EXPORT_SYMBOL_GPL(sis_free_new);