added 2.6.29.6 aldebaran kernel
[nao-ulib.git] / kernel / 2.6.29.6-aldebaran-rt / drivers / video / sis / sis_main.c
bloba8617c3591aa790803b0759eb5c583a6d4578d22
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(((rate - sisfb_vrate[i-1].refresh) <= 2)
702 && (sisfb_vrate[i].idx != 1)) {
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 = 6;
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 fix->smem_start = ivideo->video_base + ivideo->video_offset;
1851 fix->smem_len = ivideo->sisfb_mem;
1852 fix->type = FB_TYPE_PACKED_PIXELS;
1853 fix->type_aux = 0;
1854 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1855 fix->xpanstep = 1;
1856 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1857 fix->ywrapstep = 0;
1858 fix->line_length = ivideo->video_linelength;
1859 fix->mmio_start = ivideo->mmio_base;
1860 fix->mmio_len = ivideo->mmio_size;
1861 if(ivideo->sisvga_engine == SIS_300_VGA) {
1862 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1863 } else if((ivideo->chip == SIS_330) ||
1864 (ivideo->chip == SIS_760) ||
1865 (ivideo->chip == SIS_761)) {
1866 fix->accel = FB_ACCEL_SIS_XABRE;
1867 } else if(ivideo->chip == XGI_20) {
1868 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1869 } else if(ivideo->chip >= XGI_40) {
1870 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1871 } else {
1872 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1875 return 0;
1878 /* ---------------- fb_ops structures ----------------- */
1880 static struct fb_ops sisfb_ops = {
1881 .owner = THIS_MODULE,
1882 .fb_open = sisfb_open,
1883 .fb_release = sisfb_release,
1884 .fb_check_var = sisfb_check_var,
1885 .fb_set_par = sisfb_set_par,
1886 .fb_setcolreg = sisfb_setcolreg,
1887 .fb_pan_display = sisfb_pan_display,
1888 .fb_blank = sisfb_blank,
1889 .fb_fillrect = fbcon_sis_fillrect,
1890 .fb_copyarea = fbcon_sis_copyarea,
1891 .fb_imageblit = cfb_imageblit,
1892 #ifdef CONFIG_FB_SOFT_CURSOR
1893 .fb_cursor = soft_cursor,
1894 #endif
1895 .fb_sync = fbcon_sis_sync,
1896 #ifdef SIS_NEW_CONFIG_COMPAT
1897 .fb_compat_ioctl= sisfb_ioctl,
1898 #endif
1899 .fb_ioctl = sisfb_ioctl
1902 /* ---------------- Chip generation dependent routines ---------------- */
1904 static struct pci_dev * __devinit
1905 sisfb_get_northbridge(int basechipid)
1907 struct pci_dev *pdev = NULL;
1908 int nbridgenum, nbridgeidx, i;
1909 static const unsigned short nbridgeids[] = {
1910 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1911 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1912 PCI_DEVICE_ID_SI_730,
1913 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1914 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1915 PCI_DEVICE_ID_SI_651,
1916 PCI_DEVICE_ID_SI_740,
1917 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
1918 PCI_DEVICE_ID_SI_741,
1919 PCI_DEVICE_ID_SI_660,
1920 PCI_DEVICE_ID_SI_760,
1921 PCI_DEVICE_ID_SI_761
1924 switch(basechipid) {
1925 #ifdef CONFIG_FB_SIS_300
1926 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1927 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1928 #endif
1929 #ifdef CONFIG_FB_SIS_315
1930 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1931 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
1932 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
1933 #endif
1934 default: return NULL;
1936 for(i = 0; i < nbridgenum; i++) {
1937 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
1938 nbridgeids[nbridgeidx+i], NULL)))
1939 break;
1941 return pdev;
1944 static int __devinit
1945 sisfb_get_dram_size(struct sis_video_info *ivideo)
1947 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1948 u8 reg;
1949 #endif
1951 ivideo->video_size = 0;
1952 ivideo->UMAsize = ivideo->LFBsize = 0;
1954 switch(ivideo->chip) {
1955 #ifdef CONFIG_FB_SIS_300
1956 case SIS_300:
1957 inSISIDXREG(SISSR, 0x14, reg);
1958 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1959 break;
1960 case SIS_540:
1961 case SIS_630:
1962 case SIS_730:
1963 if(!ivideo->nbridge)
1964 return -1;
1965 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
1966 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1967 break;
1968 #endif
1969 #ifdef CONFIG_FB_SIS_315
1970 case SIS_315H:
1971 case SIS_315PRO:
1972 case SIS_315:
1973 inSISIDXREG(SISSR, 0x14, reg);
1974 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1975 switch((reg >> 2) & 0x03) {
1976 case 0x01:
1977 case 0x03:
1978 ivideo->video_size <<= 1;
1979 break;
1980 case 0x02:
1981 ivideo->video_size += (ivideo->video_size/2);
1983 break;
1984 case SIS_330:
1985 inSISIDXREG(SISSR, 0x14, reg);
1986 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1987 if(reg & 0x0c) ivideo->video_size <<= 1;
1988 break;
1989 case SIS_550:
1990 case SIS_650:
1991 case SIS_740:
1992 inSISIDXREG(SISSR, 0x14, reg);
1993 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
1994 break;
1995 case SIS_661:
1996 case SIS_741:
1997 inSISIDXREG(SISCR, 0x79, reg);
1998 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1999 break;
2000 case SIS_660:
2001 case SIS_760:
2002 case SIS_761:
2003 inSISIDXREG(SISCR, 0x79, reg);
2004 reg = (reg & 0xf0) >> 4;
2005 if(reg) {
2006 ivideo->video_size = (1 << reg) << 20;
2007 ivideo->UMAsize = ivideo->video_size;
2009 inSISIDXREG(SISCR, 0x78, reg);
2010 reg &= 0x30;
2011 if(reg) {
2012 if(reg == 0x10) {
2013 ivideo->LFBsize = (32 << 20);
2014 } else {
2015 ivideo->LFBsize = (64 << 20);
2017 ivideo->video_size += ivideo->LFBsize;
2019 break;
2020 case SIS_340:
2021 case XGI_20:
2022 case XGI_40:
2023 inSISIDXREG(SISSR, 0x14, reg);
2024 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2025 if(ivideo->chip != XGI_20) {
2026 reg = (reg & 0x0c) >> 2;
2027 if(ivideo->revision_id == 2) {
2028 if(reg & 0x01) reg = 0x02;
2029 else reg = 0x00;
2031 if(reg == 0x02) ivideo->video_size <<= 1;
2032 else if(reg == 0x03) ivideo->video_size <<= 2;
2034 break;
2035 #endif
2036 default:
2037 return -1;
2039 return 0;
2042 /* -------------- video bridge device detection --------------- */
2044 static void __devinit
2045 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2047 u8 cr32, temp;
2049 /* No CRT2 on XGI Z7 */
2050 if(ivideo->chip == XGI_20) {
2051 ivideo->sisfb_crt1off = 0;
2052 return;
2055 #ifdef CONFIG_FB_SIS_300
2056 if(ivideo->sisvga_engine == SIS_300_VGA) {
2057 inSISIDXREG(SISSR, 0x17, temp);
2058 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2059 /* PAL/NTSC is stored on SR16 on such machines */
2060 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2061 inSISIDXREG(SISSR, 0x16, temp);
2062 if(temp & 0x20)
2063 ivideo->vbflags |= TV_PAL;
2064 else
2065 ivideo->vbflags |= TV_NTSC;
2069 #endif
2071 inSISIDXREG(SISCR, 0x32, cr32);
2073 if(cr32 & SIS_CRT1) {
2074 ivideo->sisfb_crt1off = 0;
2075 } else {
2076 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2079 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2081 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2082 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2083 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2085 /* Check given parms for hardware compatibility.
2086 * (Cannot do this in the search_xx routines since we don't
2087 * know what hardware we are running on then)
2090 if(ivideo->chip != SIS_550) {
2091 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2094 if(ivideo->sisfb_tvplug != -1) {
2095 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2096 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2097 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2098 ivideo->sisfb_tvplug = -1;
2099 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2103 if(ivideo->sisfb_tvplug != -1) {
2104 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2105 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2106 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2107 ivideo->sisfb_tvplug = -1;
2108 printk(KERN_ERR "sisfb: HiVision not supported\n");
2112 if(ivideo->sisfb_tvstd != -1) {
2113 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2114 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2115 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2116 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2117 ivideo->sisfb_tvstd = -1;
2118 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2123 /* Detect/set TV plug & type */
2124 if(ivideo->sisfb_tvplug != -1) {
2125 ivideo->vbflags |= ivideo->sisfb_tvplug;
2126 } else {
2127 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2128 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2129 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2130 else {
2131 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2132 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2136 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2137 if(ivideo->sisfb_tvstd != -1) {
2138 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2139 ivideo->vbflags |= ivideo->sisfb_tvstd;
2141 if(ivideo->vbflags & TV_SCART) {
2142 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2143 ivideo->vbflags |= TV_PAL;
2145 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2146 if(ivideo->sisvga_engine == SIS_300_VGA) {
2147 inSISIDXREG(SISSR, 0x38, temp);
2148 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2149 else ivideo->vbflags |= TV_NTSC;
2150 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2151 inSISIDXREG(SISSR, 0x38, temp);
2152 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2153 else ivideo->vbflags |= TV_NTSC;
2154 } else {
2155 inSISIDXREG(SISCR, 0x79, temp);
2156 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2157 else ivideo->vbflags |= TV_NTSC;
2162 /* Copy forceCRT1 option to CRT1off if option is given */
2163 if(ivideo->sisfb_forcecrt1 != -1) {
2164 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2168 /* ------------------ Sensing routines ------------------ */
2170 static bool __devinit
2171 sisfb_test_DDC1(struct sis_video_info *ivideo)
2173 unsigned short old;
2174 int count = 48;
2176 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2177 do {
2178 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2179 } while(count--);
2180 return (count != -1);
2183 static void __devinit
2184 sisfb_sense_crt1(struct sis_video_info *ivideo)
2186 bool mustwait = false;
2187 u8 sr1F, cr17;
2188 #ifdef CONFIG_FB_SIS_315
2189 u8 cr63=0;
2190 #endif
2191 u16 temp = 0xffff;
2192 int i;
2194 inSISIDXREG(SISSR,0x1F,sr1F);
2195 orSISIDXREG(SISSR,0x1F,0x04);
2196 andSISIDXREG(SISSR,0x1F,0x3F);
2197 if(sr1F & 0xc0) mustwait = true;
2199 #ifdef CONFIG_FB_SIS_315
2200 if(ivideo->sisvga_engine == SIS_315_VGA) {
2201 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2202 cr63 &= 0x40;
2203 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2205 #endif
2207 inSISIDXREG(SISCR,0x17,cr17);
2208 cr17 &= 0x80;
2209 if(!cr17) {
2210 orSISIDXREG(SISCR,0x17,0x80);
2211 mustwait = true;
2212 outSISIDXREG(SISSR, 0x00, 0x01);
2213 outSISIDXREG(SISSR, 0x00, 0x03);
2216 if(mustwait) {
2217 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2220 #ifdef CONFIG_FB_SIS_315
2221 if(ivideo->chip >= SIS_330) {
2222 andSISIDXREG(SISCR,0x32,~0x20);
2223 if(ivideo->chip >= SIS_340) {
2224 outSISIDXREG(SISCR, 0x57, 0x4a);
2225 } else {
2226 outSISIDXREG(SISCR, 0x57, 0x5f);
2228 orSISIDXREG(SISCR, 0x53, 0x02);
2229 while((inSISREG(SISINPSTAT)) & 0x01) break;
2230 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2231 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2232 andSISIDXREG(SISCR, 0x53, 0xfd);
2233 andSISIDXREG(SISCR, 0x57, 0x00);
2235 #endif
2237 if(temp == 0xffff) {
2238 i = 3;
2239 do {
2240 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2241 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2242 } while(((temp == 0) || (temp == 0xffff)) && i--);
2244 if((temp == 0) || (temp == 0xffff)) {
2245 if(sisfb_test_DDC1(ivideo)) temp = 1;
2249 if((temp) && (temp != 0xffff)) {
2250 orSISIDXREG(SISCR,0x32,0x20);
2253 #ifdef CONFIG_FB_SIS_315
2254 if(ivideo->sisvga_engine == SIS_315_VGA) {
2255 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2257 #endif
2259 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2261 outSISIDXREG(SISSR,0x1F,sr1F);
2264 /* Determine and detect attached devices on SiS30x */
2265 static void __devinit
2266 SiS_SenseLCD(struct sis_video_info *ivideo)
2268 unsigned char buffer[256];
2269 unsigned short temp, realcrtno, i;
2270 u8 reg, cr37 = 0, paneltype = 0;
2271 u16 xres, yres;
2273 ivideo->SiS_Pr.PanelSelfDetected = false;
2275 /* LCD detection only for TMDS bridges */
2276 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2277 return;
2278 if(ivideo->vbflags2 & VB2_30xBDH)
2279 return;
2281 /* If LCD already set up by BIOS, skip it */
2282 inSISIDXREG(SISCR, 0x32, reg);
2283 if(reg & 0x08)
2284 return;
2286 realcrtno = 1;
2287 if(ivideo->SiS_Pr.DDCPortMixup)
2288 realcrtno = 0;
2290 /* Check DDC capabilities */
2291 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2292 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2294 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2295 return;
2297 /* Read DDC data */
2298 i = 3; /* Number of retrys */
2299 do {
2300 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2301 ivideo->sisvga_engine, realcrtno, 1,
2302 &buffer[0], ivideo->vbflags2);
2303 } while((temp) && i--);
2305 if(temp)
2306 return;
2308 /* No digital device */
2309 if(!(buffer[0x14] & 0x80))
2310 return;
2312 /* First detailed timing preferred timing? */
2313 if(!(buffer[0x18] & 0x02))
2314 return;
2316 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2317 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2319 switch(xres) {
2320 case 1024:
2321 if(yres == 768)
2322 paneltype = 0x02;
2323 break;
2324 case 1280:
2325 if(yres == 1024)
2326 paneltype = 0x03;
2327 break;
2328 case 1600:
2329 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2330 paneltype = 0x0b;
2331 break;
2334 if(!paneltype)
2335 return;
2337 if(buffer[0x23])
2338 cr37 |= 0x10;
2340 if((buffer[0x47] & 0x18) == 0x18)
2341 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2342 else
2343 cr37 |= 0xc0;
2345 outSISIDXREG(SISCR, 0x36, paneltype);
2346 cr37 &= 0xf1;
2347 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2348 orSISIDXREG(SISCR, 0x32, 0x08);
2350 ivideo->SiS_Pr.PanelSelfDetected = true;
2353 static int __devinit
2354 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2356 int temp, mytest, result, i, j;
2358 for(j = 0; j < 10; j++) {
2359 result = 0;
2360 for(i = 0; i < 3; i++) {
2361 mytest = test;
2362 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2363 temp = (type >> 8) | (mytest & 0x00ff);
2364 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2365 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2366 mytest >>= 8;
2367 mytest &= 0x7f;
2368 inSISIDXREG(SISPART4,0x03,temp);
2369 temp ^= 0x0e;
2370 temp &= mytest;
2371 if(temp == mytest) result++;
2372 #if 1
2373 outSISIDXREG(SISPART4,0x11,0x00);
2374 andSISIDXREG(SISPART4,0x10,0xe0);
2375 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2376 #endif
2378 if((result == 0) || (result >= 2)) break;
2380 return result;
2383 static void __devinit
2384 SiS_Sense30x(struct sis_video_info *ivideo)
2386 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2387 u16 svhs=0, svhs_c=0;
2388 u16 cvbs=0, cvbs_c=0;
2389 u16 vga2=0, vga2_c=0;
2390 int myflag, result;
2391 char stdstr[] = "sisfb: Detected";
2392 char tvstr[] = "TV connected to";
2394 if(ivideo->vbflags2 & VB2_301) {
2395 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2396 inSISIDXREG(SISPART4,0x01,myflag);
2397 if(myflag & 0x04) {
2398 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2400 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2401 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2402 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2403 svhs = 0x0200; cvbs = 0x0100;
2404 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2405 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2406 } else
2407 return;
2409 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2410 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2411 svhs_c = 0x0408; cvbs_c = 0x0808;
2414 biosflag = 2;
2415 if(ivideo->haveXGIROM) {
2416 biosflag = ivideo->bios_abase[0x58] & 0x03;
2417 } else if(ivideo->newrom) {
2418 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2419 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2420 if(ivideo->bios_abase) {
2421 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2425 if(ivideo->chip == SIS_300) {
2426 inSISIDXREG(SISSR,0x3b,myflag);
2427 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2430 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2431 vga2 = vga2_c = 0;
2434 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2435 orSISIDXREG(SISSR,0x1e,0x20);
2437 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2438 if(ivideo->vbflags2 & VB2_30xC) {
2439 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2440 } else {
2441 orSISIDXREG(SISPART4,0x0d,0x04);
2443 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2445 inSISIDXREG(SISPART2,0x00,backupP2_00);
2446 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2448 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2449 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2450 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2453 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2454 SISDoSense(ivideo, 0, 0);
2457 andSISIDXREG(SISCR, 0x32, ~0x14);
2459 if(vga2_c || vga2) {
2460 if(SISDoSense(ivideo, vga2, vga2_c)) {
2461 if(biosflag & 0x01) {
2462 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2463 orSISIDXREG(SISCR, 0x32, 0x04);
2464 } else {
2465 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2466 orSISIDXREG(SISCR, 0x32, 0x10);
2471 andSISIDXREG(SISCR, 0x32, 0x3f);
2473 if(ivideo->vbflags2 & VB2_30xCLV) {
2474 orSISIDXREG(SISPART4,0x0d,0x04);
2477 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2478 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2479 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2480 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2481 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2482 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2483 orSISIDXREG(SISCR,0x32,0x80);
2486 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2489 andSISIDXREG(SISCR, 0x32, ~0x03);
2491 if(!(ivideo->vbflags & TV_YPBPR)) {
2492 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2493 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2494 orSISIDXREG(SISCR, 0x32, 0x02);
2496 if((biosflag & 0x02) || (!result)) {
2497 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2498 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2499 orSISIDXREG(SISCR, 0x32, 0x01);
2504 SISDoSense(ivideo, 0, 0);
2506 outSISIDXREG(SISPART2,0x00,backupP2_00);
2507 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2508 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2510 if(ivideo->vbflags2 & VB2_30xCLV) {
2511 inSISIDXREG(SISPART2,0x00,biosflag);
2512 if(biosflag & 0x20) {
2513 for(myflag = 2; myflag > 0; myflag--) {
2514 biosflag ^= 0x20;
2515 outSISIDXREG(SISPART2,0x00,biosflag);
2520 outSISIDXREG(SISPART2,0x00,backupP2_00);
2523 /* Determine and detect attached TV's on Chrontel */
2524 static void __devinit
2525 SiS_SenseCh(struct sis_video_info *ivideo)
2527 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2528 u8 temp1, temp2;
2529 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2530 #endif
2531 #ifdef CONFIG_FB_SIS_300
2532 unsigned char test[3];
2533 int i;
2534 #endif
2536 if(ivideo->chip < SIS_315H) {
2538 #ifdef CONFIG_FB_SIS_300
2539 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2540 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2541 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2542 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2543 /* See Chrontel TB31 for explanation */
2544 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2545 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2546 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2547 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2549 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2550 if(temp2 != temp1) temp1 = temp2;
2552 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2553 /* Read power status */
2554 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2555 if((temp1 & 0x03) != 0x03) {
2556 /* Power all outputs */
2557 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2558 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2560 /* Sense connected TV devices */
2561 for(i = 0; i < 3; i++) {
2562 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2563 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2564 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2565 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2566 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2567 if(!(temp1 & 0x08)) test[i] = 0x02;
2568 else if(!(temp1 & 0x02)) test[i] = 0x01;
2569 else test[i] = 0;
2570 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2573 if(test[0] == test[1]) temp1 = test[0];
2574 else if(test[0] == test[2]) temp1 = test[0];
2575 else if(test[1] == test[2]) temp1 = test[1];
2576 else {
2577 printk(KERN_INFO
2578 "sisfb: TV detection unreliable - test results varied\n");
2579 temp1 = test[2];
2581 if(temp1 == 0x02) {
2582 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2583 ivideo->vbflags |= TV_SVIDEO;
2584 orSISIDXREG(SISCR, 0x32, 0x02);
2585 andSISIDXREG(SISCR, 0x32, ~0x05);
2586 } else if (temp1 == 0x01) {
2587 printk(KERN_INFO "%s CVBS output\n", stdstr);
2588 ivideo->vbflags |= TV_AVIDEO;
2589 orSISIDXREG(SISCR, 0x32, 0x01);
2590 andSISIDXREG(SISCR, 0x32, ~0x06);
2591 } else {
2592 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2593 andSISIDXREG(SISCR, 0x32, ~0x07);
2595 } else if(temp1 == 0) {
2596 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2597 andSISIDXREG(SISCR, 0x32, ~0x07);
2599 /* Set general purpose IO for Chrontel communication */
2600 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2601 #endif
2603 } else {
2605 #ifdef CONFIG_FB_SIS_315
2606 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2607 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2608 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2609 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2610 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2611 temp2 |= 0x01;
2612 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2613 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2614 temp2 ^= 0x01;
2615 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2616 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2617 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2618 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2619 temp1 = 0;
2620 if(temp2 & 0x02) temp1 |= 0x01;
2621 if(temp2 & 0x10) temp1 |= 0x01;
2622 if(temp2 & 0x04) temp1 |= 0x02;
2623 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2624 switch(temp1) {
2625 case 0x01:
2626 printk(KERN_INFO "%s CVBS output\n", stdstr);
2627 ivideo->vbflags |= TV_AVIDEO;
2628 orSISIDXREG(SISCR, 0x32, 0x01);
2629 andSISIDXREG(SISCR, 0x32, ~0x06);
2630 break;
2631 case 0x02:
2632 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2633 ivideo->vbflags |= TV_SVIDEO;
2634 orSISIDXREG(SISCR, 0x32, 0x02);
2635 andSISIDXREG(SISCR, 0x32, ~0x05);
2636 break;
2637 case 0x04:
2638 printk(KERN_INFO "%s SCART output\n", stdstr);
2639 orSISIDXREG(SISCR, 0x32, 0x04);
2640 andSISIDXREG(SISCR, 0x32, ~0x03);
2641 break;
2642 default:
2643 andSISIDXREG(SISCR, 0x32, ~0x07);
2645 #endif
2649 static void __devinit
2650 sisfb_get_VB_type(struct sis_video_info *ivideo)
2652 char stdstr[] = "sisfb: Detected";
2653 char bridgestr[] = "video bridge";
2654 u8 vb_chipid;
2655 u8 reg;
2657 /* No CRT2 on XGI Z7 */
2658 if(ivideo->chip == XGI_20)
2659 return;
2661 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2662 switch(vb_chipid) {
2663 case 0x01:
2664 inSISIDXREG(SISPART4, 0x01, reg);
2665 if(reg < 0xb0) {
2666 ivideo->vbflags |= VB_301; /* Deprecated */
2667 ivideo->vbflags2 |= VB2_301;
2668 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2669 } else if(reg < 0xc0) {
2670 ivideo->vbflags |= VB_301B; /* Deprecated */
2671 ivideo->vbflags2 |= VB2_301B;
2672 inSISIDXREG(SISPART4,0x23,reg);
2673 if(!(reg & 0x02)) {
2674 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2675 ivideo->vbflags2 |= VB2_30xBDH;
2676 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2677 } else {
2678 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2680 } else if(reg < 0xd0) {
2681 ivideo->vbflags |= VB_301C; /* Deprecated */
2682 ivideo->vbflags2 |= VB2_301C;
2683 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2684 } else if(reg < 0xe0) {
2685 ivideo->vbflags |= VB_301LV; /* Deprecated */
2686 ivideo->vbflags2 |= VB2_301LV;
2687 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2688 } else if(reg <= 0xe1) {
2689 inSISIDXREG(SISPART4,0x39,reg);
2690 if(reg == 0xff) {
2691 ivideo->vbflags |= VB_302LV; /* Deprecated */
2692 ivideo->vbflags2 |= VB2_302LV;
2693 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2694 } else {
2695 ivideo->vbflags |= VB_301C; /* Deprecated */
2696 ivideo->vbflags2 |= VB2_301C;
2697 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2698 #if 0
2699 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2700 ivideo->vbflags2 |= VB2_302ELV;
2701 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2702 #endif
2705 break;
2706 case 0x02:
2707 ivideo->vbflags |= VB_302B; /* Deprecated */
2708 ivideo->vbflags2 |= VB2_302B;
2709 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2710 break;
2713 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2714 inSISIDXREG(SISCR, 0x37, reg);
2715 reg &= SIS_EXTERNAL_CHIP_MASK;
2716 reg >>= 1;
2717 if(ivideo->sisvga_engine == SIS_300_VGA) {
2718 #ifdef CONFIG_FB_SIS_300
2719 switch(reg) {
2720 case SIS_EXTERNAL_CHIP_LVDS:
2721 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2722 ivideo->vbflags2 |= VB2_LVDS;
2723 break;
2724 case SIS_EXTERNAL_CHIP_TRUMPION:
2725 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2726 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2727 break;
2728 case SIS_EXTERNAL_CHIP_CHRONTEL:
2729 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2730 ivideo->vbflags2 |= VB2_CHRONTEL;
2731 break;
2732 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2733 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2734 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2735 break;
2737 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2738 #endif
2739 } else if(ivideo->chip < SIS_661) {
2740 #ifdef CONFIG_FB_SIS_315
2741 switch (reg) {
2742 case SIS310_EXTERNAL_CHIP_LVDS:
2743 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2744 ivideo->vbflags2 |= VB2_LVDS;
2745 break;
2746 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2747 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2748 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2749 break;
2751 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2752 #endif
2753 } else if(ivideo->chip >= SIS_661) {
2754 #ifdef CONFIG_FB_SIS_315
2755 inSISIDXREG(SISCR, 0x38, reg);
2756 reg >>= 5;
2757 switch(reg) {
2758 case 0x02:
2759 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2760 ivideo->vbflags2 |= VB2_LVDS;
2761 break;
2762 case 0x03:
2763 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2764 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2765 break;
2766 case 0x04:
2767 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2768 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2769 break;
2771 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2772 #endif
2774 if(ivideo->vbflags2 & VB2_LVDS) {
2775 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2777 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2778 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2780 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2781 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2783 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2784 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2788 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2789 SiS_SenseLCD(ivideo);
2790 SiS_Sense30x(ivideo);
2791 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2792 SiS_SenseCh(ivideo);
2796 /* ---------- Engine initialization routines ------------ */
2798 static void
2799 sisfb_engine_init(struct sis_video_info *ivideo)
2802 /* Initialize command queue (we use MMIO only) */
2804 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2806 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2807 MMIO_CMD_QUEUE_CAP |
2808 VM_CMD_QUEUE_CAP |
2809 AGP_CMD_QUEUE_CAP);
2811 #ifdef CONFIG_FB_SIS_300
2812 if(ivideo->sisvga_engine == SIS_300_VGA) {
2813 u32 tqueue_pos;
2814 u8 tq_state;
2816 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2818 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2819 tq_state |= 0xf0;
2820 tq_state &= 0xfc;
2821 tq_state |= (u8)(tqueue_pos >> 8);
2822 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2824 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2826 ivideo->caps |= TURBO_QUEUE_CAP;
2828 #endif
2830 #ifdef CONFIG_FB_SIS_315
2831 if(ivideo->sisvga_engine == SIS_315_VGA) {
2832 u32 tempq = 0, templ;
2833 u8 temp;
2835 if(ivideo->chip == XGI_20) {
2836 switch(ivideo->cmdQueueSize) {
2837 case (64 * 1024):
2838 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2839 break;
2840 case (128 * 1024):
2841 default:
2842 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2844 } else {
2845 switch(ivideo->cmdQueueSize) {
2846 case (4 * 1024 * 1024):
2847 temp = SIS_CMD_QUEUE_SIZE_4M;
2848 break;
2849 case (2 * 1024 * 1024):
2850 temp = SIS_CMD_QUEUE_SIZE_2M;
2851 break;
2852 case (1 * 1024 * 1024):
2853 temp = SIS_CMD_QUEUE_SIZE_1M;
2854 break;
2855 default:
2856 case (512 * 1024):
2857 temp = SIS_CMD_QUEUE_SIZE_512k;
2861 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2862 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2864 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2865 /* Must disable dual pipe on XGI_40. Can't do
2866 * this in MMIO mode, because it requires
2867 * setting/clearing a bit in the MMIO fire trigger
2868 * register.
2870 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2872 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2874 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2876 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2877 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2879 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2880 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2882 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2883 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2884 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2885 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2887 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2889 sisfb_syncaccel(ivideo);
2891 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2896 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2897 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2899 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2900 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2902 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2903 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2905 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2907 #endif
2909 ivideo->engineok = 1;
2912 static void __devinit
2913 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2915 u8 reg;
2916 int i;
2918 inSISIDXREG(SISCR, 0x36, reg);
2919 reg &= 0x0f;
2920 if(ivideo->sisvga_engine == SIS_300_VGA) {
2921 ivideo->CRT2LCDType = sis300paneltype[reg];
2922 } else if(ivideo->chip >= SIS_661) {
2923 ivideo->CRT2LCDType = sis661paneltype[reg];
2924 } else {
2925 ivideo->CRT2LCDType = sis310paneltype[reg];
2926 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2927 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2928 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2929 ivideo->CRT2LCDType = LCD_320x240;
2934 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2935 /* For broken BIOSes: Assume 1024x768, RGB18 */
2936 ivideo->CRT2LCDType = LCD_1024x768;
2937 setSISIDXREG(SISCR,0x36,0xf0,0x02);
2938 setSISIDXREG(SISCR,0x37,0xee,0x01);
2939 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2942 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2943 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2944 ivideo->lcdxres = sis_lcd_data[i].xres;
2945 ivideo->lcdyres = sis_lcd_data[i].yres;
2946 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2947 break;
2951 #ifdef CONFIG_FB_SIS_300
2952 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2953 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2954 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2955 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2956 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2957 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2958 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2959 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2960 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2962 #endif
2964 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2965 ivideo->lcdxres, ivideo->lcdyres);
2968 static void __devinit
2969 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2971 #ifdef CONFIG_FB_SIS_300
2972 /* Save the current PanelDelayCompensation if the LCD is currently used */
2973 if(ivideo->sisvga_engine == SIS_300_VGA) {
2974 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2975 int tmp;
2976 inSISIDXREG(SISCR,0x30,tmp);
2977 if(tmp & 0x20) {
2978 /* Currently on LCD? If yes, read current pdc */
2979 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2980 ivideo->detectedpdc &= 0x3c;
2981 if(ivideo->SiS_Pr.PDC == -1) {
2982 /* Let option override detection */
2983 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2985 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2986 ivideo->detectedpdc);
2988 if((ivideo->SiS_Pr.PDC != -1) &&
2989 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2990 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2991 ivideo->SiS_Pr.PDC);
2995 #endif
2997 #ifdef CONFIG_FB_SIS_315
2998 if(ivideo->sisvga_engine == SIS_315_VGA) {
3000 /* Try to find about LCDA */
3001 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3002 int tmp;
3003 inSISIDXREG(SISPART1,0x13,tmp);
3004 if(tmp & 0x04) {
3005 ivideo->SiS_Pr.SiS_UseLCDA = true;
3006 ivideo->detectedlcda = 0x03;
3010 /* Save PDC */
3011 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3012 int tmp;
3013 inSISIDXREG(SISCR,0x30,tmp);
3014 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3015 /* Currently on LCD? If yes, read current pdc */
3016 u8 pdc;
3017 inSISIDXREG(SISPART1,0x2D,pdc);
3018 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3019 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3020 inSISIDXREG(SISPART1,0x35,pdc);
3021 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3022 inSISIDXREG(SISPART1,0x20,pdc);
3023 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3024 if(ivideo->newrom) {
3025 /* New ROM invalidates other PDC resp. */
3026 if(ivideo->detectedlcda != 0xff) {
3027 ivideo->detectedpdc = 0xff;
3028 } else {
3029 ivideo->detectedpdca = 0xff;
3032 if(ivideo->SiS_Pr.PDC == -1) {
3033 if(ivideo->detectedpdc != 0xff) {
3034 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3037 if(ivideo->SiS_Pr.PDCA == -1) {
3038 if(ivideo->detectedpdca != 0xff) {
3039 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3042 if(ivideo->detectedpdc != 0xff) {
3043 printk(KERN_INFO
3044 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3045 ivideo->detectedpdc);
3047 if(ivideo->detectedpdca != 0xff) {
3048 printk(KERN_INFO
3049 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3050 ivideo->detectedpdca);
3054 /* Save EMI */
3055 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3056 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3057 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3058 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3059 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3060 ivideo->SiS_Pr.HaveEMI = true;
3061 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3062 ivideo->SiS_Pr.HaveEMILCD = true;
3067 /* Let user override detected PDCs (all bridges) */
3068 if(ivideo->vbflags2 & VB2_30xBLV) {
3069 if((ivideo->SiS_Pr.PDC != -1) &&
3070 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3071 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3072 ivideo->SiS_Pr.PDC);
3074 if((ivideo->SiS_Pr.PDCA != -1) &&
3075 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3076 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3077 ivideo->SiS_Pr.PDCA);
3082 #endif
3085 /* -------------------- Memory manager routines ---------------------- */
3087 static u32 __devinit
3088 sisfb_getheapstart(struct sis_video_info *ivideo)
3090 u32 ret = ivideo->sisfb_parm_mem * 1024;
3091 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3092 u32 def;
3094 /* Calculate heap start = end of memory for console
3096 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3097 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3099 * On 76x in UMA+LFB mode, the layout is as follows:
3100 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3101 * where the heap is the entire UMA area, eventually
3102 * into the LFB area if the given mem parameter is
3103 * higher than the size of the UMA memory.
3105 * Basically given by "mem" parameter
3107 * maximum = videosize - cmd_queue - hwcursor
3108 * (results in a heap of size 0)
3109 * default = SiS 300: depends on videosize
3110 * SiS 315/330/340/XGI: 32k below max
3113 if(ivideo->sisvga_engine == SIS_300_VGA) {
3114 if(ivideo->video_size > 0x1000000) {
3115 def = 0xc00000;
3116 } else if(ivideo->video_size > 0x800000) {
3117 def = 0x800000;
3118 } else {
3119 def = 0x400000;
3121 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3122 ret = def = 0;
3123 } else {
3124 def = maxoffs - 0x8000;
3127 /* Use default for secondary card for now (FIXME) */
3128 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3129 ret = def;
3131 return ret;
3134 static u32 __devinit
3135 sisfb_getheapsize(struct sis_video_info *ivideo)
3137 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3138 u32 ret = 0;
3140 if(ivideo->UMAsize && ivideo->LFBsize) {
3141 if( (!ivideo->sisfb_parm_mem) ||
3142 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3143 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3144 ret = ivideo->UMAsize;
3145 max -= ivideo->UMAsize;
3146 } else {
3147 ret = max - (ivideo->sisfb_parm_mem * 1024);
3148 max = ivideo->sisfb_parm_mem * 1024;
3150 ivideo->video_offset = ret;
3151 ivideo->sisfb_mem = max;
3152 } else {
3153 ret = max - ivideo->heapstart;
3154 ivideo->sisfb_mem = ivideo->heapstart;
3157 return ret;
3160 static int __devinit
3161 sisfb_heap_init(struct sis_video_info *ivideo)
3163 struct SIS_OH *poh;
3165 ivideo->video_offset = 0;
3166 if(ivideo->sisfb_parm_mem) {
3167 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3168 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3169 ivideo->sisfb_parm_mem = 0;
3173 ivideo->heapstart = sisfb_getheapstart(ivideo);
3174 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3176 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3177 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3179 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3180 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3182 ivideo->sisfb_heap.vinfo = ivideo;
3184 ivideo->sisfb_heap.poha_chain = NULL;
3185 ivideo->sisfb_heap.poh_freelist = NULL;
3187 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3188 if(poh == NULL)
3189 return 1;
3191 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3192 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3193 poh->size = ivideo->sisfb_heap_size;
3194 poh->offset = ivideo->heapstart;
3196 ivideo->sisfb_heap.oh_free.poh_next = poh;
3197 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3198 ivideo->sisfb_heap.oh_free.size = 0;
3199 ivideo->sisfb_heap.max_freesize = poh->size;
3201 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3202 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3203 ivideo->sisfb_heap.oh_used.size = SENTINEL;
3205 if(ivideo->cardnumber == 0) {
3206 /* For the first card, make this heap the "global" one
3207 * for old DRM (which could handle only one card)
3209 sisfb_heap = &ivideo->sisfb_heap;
3212 return 0;
3215 static struct SIS_OH *
3216 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3218 struct SIS_OHALLOC *poha;
3219 struct SIS_OH *poh;
3220 unsigned long cOhs;
3221 int i;
3223 if(memheap->poh_freelist == NULL) {
3224 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3225 if(!poha)
3226 return NULL;
3228 poha->poha_next = memheap->poha_chain;
3229 memheap->poha_chain = poha;
3231 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3233 poh = &poha->aoh[0];
3234 for(i = cOhs - 1; i != 0; i--) {
3235 poh->poh_next = poh + 1;
3236 poh = poh + 1;
3239 poh->poh_next = NULL;
3240 memheap->poh_freelist = &poha->aoh[0];
3243 poh = memheap->poh_freelist;
3244 memheap->poh_freelist = poh->poh_next;
3246 return poh;
3249 static struct SIS_OH *
3250 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3252 struct SIS_OH *pohThis;
3253 struct SIS_OH *pohRoot;
3254 int bAllocated = 0;
3256 if(size > memheap->max_freesize) {
3257 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3258 (unsigned int) size / 1024);
3259 return NULL;
3262 pohThis = memheap->oh_free.poh_next;
3264 while(pohThis != &memheap->oh_free) {
3265 if(size <= pohThis->size) {
3266 bAllocated = 1;
3267 break;
3269 pohThis = pohThis->poh_next;
3272 if(!bAllocated) {
3273 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3274 (unsigned int) size / 1024);
3275 return NULL;
3278 if(size == pohThis->size) {
3279 pohRoot = pohThis;
3280 sisfb_delete_node(pohThis);
3281 } else {
3282 pohRoot = sisfb_poh_new_node(memheap);
3283 if(pohRoot == NULL)
3284 return NULL;
3286 pohRoot->offset = pohThis->offset;
3287 pohRoot->size = size;
3289 pohThis->offset += size;
3290 pohThis->size -= size;
3293 memheap->max_freesize -= size;
3295 pohThis = &memheap->oh_used;
3296 sisfb_insert_node(pohThis, pohRoot);
3298 return pohRoot;
3301 static void
3302 sisfb_delete_node(struct SIS_OH *poh)
3304 poh->poh_prev->poh_next = poh->poh_next;
3305 poh->poh_next->poh_prev = poh->poh_prev;
3308 static void
3309 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3311 struct SIS_OH *pohTemp = pohList->poh_next;
3313 pohList->poh_next = poh;
3314 pohTemp->poh_prev = poh;
3316 poh->poh_prev = pohList;
3317 poh->poh_next = pohTemp;
3320 static struct SIS_OH *
3321 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3323 struct SIS_OH *pohThis;
3324 struct SIS_OH *poh_freed;
3325 struct SIS_OH *poh_prev;
3326 struct SIS_OH *poh_next;
3327 u32 ulUpper;
3328 u32 ulLower;
3329 int foundNode = 0;
3331 poh_freed = memheap->oh_used.poh_next;
3333 while(poh_freed != &memheap->oh_used) {
3334 if(poh_freed->offset == base) {
3335 foundNode = 1;
3336 break;
3339 poh_freed = poh_freed->poh_next;
3342 if(!foundNode)
3343 return NULL;
3345 memheap->max_freesize += poh_freed->size;
3347 poh_prev = poh_next = NULL;
3348 ulUpper = poh_freed->offset + poh_freed->size;
3349 ulLower = poh_freed->offset;
3351 pohThis = memheap->oh_free.poh_next;
3353 while(pohThis != &memheap->oh_free) {
3354 if(pohThis->offset == ulUpper) {
3355 poh_next = pohThis;
3356 } else if((pohThis->offset + pohThis->size) == ulLower) {
3357 poh_prev = pohThis;
3359 pohThis = pohThis->poh_next;
3362 sisfb_delete_node(poh_freed);
3364 if(poh_prev && poh_next) {
3365 poh_prev->size += (poh_freed->size + poh_next->size);
3366 sisfb_delete_node(poh_next);
3367 sisfb_free_node(memheap, poh_freed);
3368 sisfb_free_node(memheap, poh_next);
3369 return poh_prev;
3372 if(poh_prev) {
3373 poh_prev->size += poh_freed->size;
3374 sisfb_free_node(memheap, poh_freed);
3375 return poh_prev;
3378 if(poh_next) {
3379 poh_next->size += poh_freed->size;
3380 poh_next->offset = poh_freed->offset;
3381 sisfb_free_node(memheap, poh_freed);
3382 return poh_next;
3385 sisfb_insert_node(&memheap->oh_free, poh_freed);
3387 return poh_freed;
3390 static void
3391 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3393 if(poh == NULL)
3394 return;
3396 poh->poh_next = memheap->poh_freelist;
3397 memheap->poh_freelist = poh;
3400 static void
3401 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3403 struct SIS_OH *poh = NULL;
3405 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3406 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3408 if(poh == NULL) {
3409 req->offset = req->size = 0;
3410 DPRINTK("sisfb: Video RAM allocation failed\n");
3411 } else {
3412 req->offset = poh->offset;
3413 req->size = poh->size;
3414 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3415 (poh->offset + ivideo->video_vbase));
3419 void
3420 sis_malloc(struct sis_memreq *req)
3422 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3424 if(&ivideo->sisfb_heap == sisfb_heap)
3425 sis_int_malloc(ivideo, req);
3426 else
3427 req->offset = req->size = 0;
3430 void
3431 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3433 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3435 sis_int_malloc(ivideo, req);
3438 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3440 static void
3441 sis_int_free(struct sis_video_info *ivideo, u32 base)
3443 struct SIS_OH *poh;
3445 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3446 return;
3448 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3450 if(poh == NULL) {
3451 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3452 (unsigned int) base);
3456 void
3457 sis_free(u32 base)
3459 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3461 sis_int_free(ivideo, base);
3464 void
3465 sis_free_new(struct pci_dev *pdev, u32 base)
3467 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3469 sis_int_free(ivideo, base);
3472 /* --------------------- SetMode routines ------------------------- */
3474 static void
3475 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3477 u8 cr30, cr31;
3479 /* Check if MMIO and engines are enabled,
3480 * and sync in case they are. Can't use
3481 * ivideo->accel here, as this might have
3482 * been changed before this is called.
3484 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3485 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3486 /* MMIO and 2D/3D engine enabled? */
3487 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3488 #ifdef CONFIG_FB_SIS_300
3489 if(ivideo->sisvga_engine == SIS_300_VGA) {
3490 /* Don't care about TurboQueue. It's
3491 * enough to know that the engines
3492 * are enabled
3494 sisfb_syncaccel(ivideo);
3496 #endif
3497 #ifdef CONFIG_FB_SIS_315
3498 if(ivideo->sisvga_engine == SIS_315_VGA) {
3499 /* Check that any queue mode is
3500 * enabled, and that the queue
3501 * is not in the state of "reset"
3503 inSISIDXREG(SISSR, 0x26, cr30);
3504 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3505 sisfb_syncaccel(ivideo);
3508 #endif
3512 static void
3513 sisfb_pre_setmode(struct sis_video_info *ivideo)
3515 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3516 int tvregnum = 0;
3518 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3520 outSISIDXREG(SISSR, 0x05, 0x86);
3522 inSISIDXREG(SISCR, 0x31, cr31);
3523 cr31 &= ~0x60;
3524 cr31 |= 0x04;
3526 cr33 = ivideo->rate_idx & 0x0F;
3528 #ifdef CONFIG_FB_SIS_315
3529 if(ivideo->sisvga_engine == SIS_315_VGA) {
3530 if(ivideo->chip >= SIS_661) {
3531 inSISIDXREG(SISCR, 0x38, cr38);
3532 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3533 } else {
3534 tvregnum = 0x38;
3535 inSISIDXREG(SISCR, tvregnum, cr38);
3536 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3539 #endif
3540 #ifdef CONFIG_FB_SIS_300
3541 if(ivideo->sisvga_engine == SIS_300_VGA) {
3542 tvregnum = 0x35;
3543 inSISIDXREG(SISCR, tvregnum, cr38);
3545 #endif
3547 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3548 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
3549 ivideo->curFSTN = ivideo->curDSTN = 0;
3551 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3553 case CRT2_TV:
3554 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3555 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3556 #ifdef CONFIG_FB_SIS_315
3557 if(ivideo->chip >= SIS_661) {
3558 cr38 |= 0x04;
3559 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3560 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3561 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3562 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3563 cr35 &= ~0x01;
3564 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3565 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3566 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3567 cr38 |= 0x08;
3568 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3569 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3570 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3571 cr31 &= ~0x01;
3572 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3574 #endif
3575 } else if((ivideo->vbflags & TV_HIVISION) &&
3576 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3577 if(ivideo->chip >= SIS_661) {
3578 cr38 |= 0x04;
3579 cr35 |= 0x60;
3580 } else {
3581 cr30 |= 0x80;
3583 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3584 cr31 |= 0x01;
3585 cr35 |= 0x01;
3586 ivideo->currentvbflags |= TV_HIVISION;
3587 } else if(ivideo->vbflags & TV_SCART) {
3588 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3589 cr31 |= 0x01;
3590 cr35 |= 0x01;
3591 ivideo->currentvbflags |= TV_SCART;
3592 } else {
3593 if(ivideo->vbflags & TV_SVIDEO) {
3594 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3595 ivideo->currentvbflags |= TV_SVIDEO;
3597 if(ivideo->vbflags & TV_AVIDEO) {
3598 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3599 ivideo->currentvbflags |= TV_AVIDEO;
3602 cr31 |= SIS_DRIVER_MODE;
3604 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3605 if(ivideo->vbflags & TV_PAL) {
3606 cr31 |= 0x01; cr35 |= 0x01;
3607 ivideo->currentvbflags |= TV_PAL;
3608 if(ivideo->vbflags & TV_PALM) {
3609 cr38 |= 0x40; cr35 |= 0x04;
3610 ivideo->currentvbflags |= TV_PALM;
3611 } else if(ivideo->vbflags & TV_PALN) {
3612 cr38 |= 0x80; cr35 |= 0x08;
3613 ivideo->currentvbflags |= TV_PALN;
3615 } else {
3616 cr31 &= ~0x01; cr35 &= ~0x01;
3617 ivideo->currentvbflags |= TV_NTSC;
3618 if(ivideo->vbflags & TV_NTSCJ) {
3619 cr38 |= 0x40; cr35 |= 0x02;
3620 ivideo->currentvbflags |= TV_NTSCJ;
3624 break;
3626 case CRT2_LCD:
3627 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3628 cr31 |= SIS_DRIVER_MODE;
3629 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3630 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3631 ivideo->curFSTN = ivideo->sisfb_fstn;
3632 ivideo->curDSTN = ivideo->sisfb_dstn;
3633 break;
3635 case CRT2_VGA:
3636 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3637 cr31 |= SIS_DRIVER_MODE;
3638 if(ivideo->sisfb_nocrt2rate) {
3639 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3640 } else {
3641 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3643 break;
3645 default: /* disable CRT2 */
3646 cr30 = 0x00;
3647 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3650 outSISIDXREG(SISCR, 0x30, cr30);
3651 outSISIDXREG(SISCR, 0x33, cr33);
3653 if(ivideo->chip >= SIS_661) {
3654 #ifdef CONFIG_FB_SIS_315
3655 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3656 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3657 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3658 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3659 #endif
3660 } else if(ivideo->chip != SIS_300) {
3661 outSISIDXREG(SISCR, tvregnum, cr38);
3663 outSISIDXREG(SISCR, 0x31, cr31);
3665 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3667 sisfb_check_engine_and_sync(ivideo);
3670 /* Fix SR11 for 661 and later */
3671 #ifdef CONFIG_FB_SIS_315
3672 static void
3673 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3675 u8 tmpreg;
3677 if(ivideo->chip >= SIS_661) {
3678 inSISIDXREG(SISSR,0x11,tmpreg);
3679 if(tmpreg & 0x20) {
3680 inSISIDXREG(SISSR,0x3e,tmpreg);
3681 tmpreg = (tmpreg + 1) & 0xff;
3682 outSISIDXREG(SISSR,0x3e,tmpreg);
3683 inSISIDXREG(SISSR,0x11,tmpreg);
3685 if(tmpreg & 0xf0) {
3686 andSISIDXREG(SISSR,0x11,0x0f);
3690 #endif
3692 static void
3693 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3695 if(val > 32) val = 32;
3696 if(val < -32) val = -32;
3697 ivideo->tvxpos = val;
3699 if(ivideo->sisfblocked) return;
3700 if(!ivideo->modechanged) return;
3702 if(ivideo->currentvbflags & CRT2_TV) {
3704 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3706 int x = ivideo->tvx;
3708 switch(ivideo->chronteltype) {
3709 case 1:
3710 x += val;
3711 if(x < 0) x = 0;
3712 outSISIDXREG(SISSR,0x05,0x86);
3713 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3714 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3715 break;
3716 case 2:
3717 /* Not supported by hardware */
3718 break;
3721 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3723 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3724 unsigned short temp;
3726 p2_1f = ivideo->p2_1f;
3727 p2_20 = ivideo->p2_20;
3728 p2_2b = ivideo->p2_2b;
3729 p2_42 = ivideo->p2_42;
3730 p2_43 = ivideo->p2_43;
3732 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3733 temp += (val * 2);
3734 p2_1f = temp & 0xff;
3735 p2_20 = (temp & 0xf00) >> 4;
3736 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3737 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3738 temp += (val * 2);
3739 p2_43 = temp & 0xff;
3740 p2_42 = (temp & 0xf00) >> 4;
3741 outSISIDXREG(SISPART2,0x1f,p2_1f);
3742 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3743 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3744 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3745 outSISIDXREG(SISPART2,0x43,p2_43);
3750 static void
3751 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3753 if(val > 32) val = 32;
3754 if(val < -32) val = -32;
3755 ivideo->tvypos = val;
3757 if(ivideo->sisfblocked) return;
3758 if(!ivideo->modechanged) return;
3760 if(ivideo->currentvbflags & CRT2_TV) {
3762 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3764 int y = ivideo->tvy;
3766 switch(ivideo->chronteltype) {
3767 case 1:
3768 y -= val;
3769 if(y < 0) y = 0;
3770 outSISIDXREG(SISSR,0x05,0x86);
3771 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3772 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3773 break;
3774 case 2:
3775 /* Not supported by hardware */
3776 break;
3779 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3781 char p2_01, p2_02;
3782 val /= 2;
3783 p2_01 = ivideo->p2_01;
3784 p2_02 = ivideo->p2_02;
3786 p2_01 += val;
3787 p2_02 += val;
3788 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3789 while((p2_01 <= 0) || (p2_02 <= 0)) {
3790 p2_01 += 2;
3791 p2_02 += 2;
3794 outSISIDXREG(SISPART2,0x01,p2_01);
3795 outSISIDXREG(SISPART2,0x02,p2_02);
3800 static void
3801 sisfb_post_setmode(struct sis_video_info *ivideo)
3803 bool crt1isoff = false;
3804 bool doit = true;
3805 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3806 u8 reg;
3807 #endif
3808 #ifdef CONFIG_FB_SIS_315
3809 u8 reg1;
3810 #endif
3812 outSISIDXREG(SISSR, 0x05, 0x86);
3814 #ifdef CONFIG_FB_SIS_315
3815 sisfb_fixup_SR11(ivideo);
3816 #endif
3818 /* Now we actually HAVE changed the display mode */
3819 ivideo->modechanged = 1;
3821 /* We can't switch off CRT1 if bridge is in slave mode */
3822 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3823 if(sisfb_bridgeisslave(ivideo)) doit = false;
3824 } else
3825 ivideo->sisfb_crt1off = 0;
3827 #ifdef CONFIG_FB_SIS_300
3828 if(ivideo->sisvga_engine == SIS_300_VGA) {
3829 if((ivideo->sisfb_crt1off) && (doit)) {
3830 crt1isoff = true;
3831 reg = 0x00;
3832 } else {
3833 crt1isoff = false;
3834 reg = 0x80;
3836 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3838 #endif
3839 #ifdef CONFIG_FB_SIS_315
3840 if(ivideo->sisvga_engine == SIS_315_VGA) {
3841 if((ivideo->sisfb_crt1off) && (doit)) {
3842 crt1isoff = true;
3843 reg = 0x40;
3844 reg1 = 0xc0;
3845 } else {
3846 crt1isoff = false;
3847 reg = 0x00;
3848 reg1 = 0x00;
3850 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3851 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3853 #endif
3855 if(crt1isoff) {
3856 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3857 ivideo->currentvbflags |= VB_SINGLE_MODE;
3858 } else {
3859 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3860 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3861 ivideo->currentvbflags |= VB_MIRROR_MODE;
3862 } else {
3863 ivideo->currentvbflags |= VB_SINGLE_MODE;
3867 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3869 if(ivideo->currentvbflags & CRT2_TV) {
3870 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3871 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3872 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3873 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3874 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3875 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3876 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3877 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3878 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3879 if(ivideo->chronteltype == 1) {
3880 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3881 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3882 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3883 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3888 if(ivideo->tvxpos) {
3889 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3891 if(ivideo->tvypos) {
3892 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3895 /* Eventually sync engines */
3896 sisfb_check_engine_and_sync(ivideo);
3898 /* (Re-)Initialize chip engines */
3899 if(ivideo->accel) {
3900 sisfb_engine_init(ivideo);
3901 } else {
3902 ivideo->engineok = 0;
3906 static int
3907 sisfb_reset_mode(struct sis_video_info *ivideo)
3909 if(sisfb_set_mode(ivideo, 0))
3910 return 1;
3912 sisfb_set_pitch(ivideo);
3913 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3914 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3916 return 0;
3919 static void
3920 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3922 int mycrt1off;
3924 switch(sisfb_command->sisfb_cmd) {
3925 case SISFB_CMD_GETVBFLAGS:
3926 if(!ivideo->modechanged) {
3927 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3928 } else {
3929 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3930 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3931 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
3933 break;
3934 case SISFB_CMD_SWITCHCRT1:
3935 /* arg[0]: 0 = off, 1 = on, 99 = query */
3936 if(!ivideo->modechanged) {
3937 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3938 } else if(sisfb_command->sisfb_arg[0] == 99) {
3939 /* Query */
3940 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3941 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3942 } else if(ivideo->sisfblocked) {
3943 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3944 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3945 (sisfb_command->sisfb_arg[0] == 0)) {
3946 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3947 } else {
3948 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3949 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3950 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3951 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3952 ivideo->sisfb_crt1off = mycrt1off;
3953 if(sisfb_reset_mode(ivideo)) {
3954 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
3957 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3959 break;
3960 /* more to come */
3961 default:
3962 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3963 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3964 sisfb_command->sisfb_cmd);
3968 #ifndef MODULE
3969 static int __init sisfb_setup(char *options)
3971 char *this_opt;
3973 sisfb_setdefaultparms();
3975 if(!options || !(*options))
3976 return 0;
3978 while((this_opt = strsep(&options, ",")) != NULL) {
3980 if(!(*this_opt)) continue;
3982 if(!strnicmp(this_opt, "off", 3)) {
3983 sisfb_off = 1;
3984 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3985 /* Need to check crt2 type first for fstn/dstn */
3986 sisfb_search_crt2type(this_opt + 14);
3987 } else if(!strnicmp(this_opt, "tvmode:",7)) {
3988 sisfb_search_tvstd(this_opt + 7);
3989 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3990 sisfb_search_tvstd(this_opt + 11);
3991 } else if(!strnicmp(this_opt, "mode:", 5)) {
3992 sisfb_search_mode(this_opt + 5, false);
3993 } else if(!strnicmp(this_opt, "vesa:", 5)) {
3994 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
3995 } else if(!strnicmp(this_opt, "rate:", 5)) {
3996 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
3997 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3998 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
3999 } else if(!strnicmp(this_opt, "mem:",4)) {
4000 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4001 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4002 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4003 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4004 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4005 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4006 sisfb_accel = 0;
4007 } else if(!strnicmp(this_opt, "accel", 5)) {
4008 sisfb_accel = -1;
4009 } else if(!strnicmp(this_opt, "noypan", 6)) {
4010 sisfb_ypan = 0;
4011 } else if(!strnicmp(this_opt, "ypan", 4)) {
4012 sisfb_ypan = -1;
4013 } else if(!strnicmp(this_opt, "nomax", 5)) {
4014 sisfb_max = 0;
4015 } else if(!strnicmp(this_opt, "max", 3)) {
4016 sisfb_max = -1;
4017 } else if(!strnicmp(this_opt, "userom:", 7)) {
4018 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4019 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4020 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4021 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4022 sisfb_nocrt2rate = 1;
4023 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4024 unsigned long temp = 2;
4025 temp = simple_strtoul(this_opt + 9, NULL, 0);
4026 if((temp == 0) || (temp == 1)) {
4027 sisfb_scalelcd = temp ^ 1;
4029 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4030 int temp = 0;
4031 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4032 if((temp >= -32) && (temp <= 32)) {
4033 sisfb_tvxposoffset = temp;
4035 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4036 int temp = 0;
4037 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4038 if((temp >= -32) && (temp <= 32)) {
4039 sisfb_tvyposoffset = temp;
4041 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4042 sisfb_search_specialtiming(this_opt + 14);
4043 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4044 int temp = 4;
4045 temp = simple_strtoul(this_opt + 7, NULL, 0);
4046 if((temp >= 0) && (temp <= 3)) {
4047 sisfb_lvdshl = temp;
4049 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4050 sisfb_search_mode(this_opt, true);
4051 #if !defined(__i386__) && !defined(__x86_64__)
4052 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4053 sisfb_resetcard = 1;
4054 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4055 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4056 #endif
4057 } else {
4058 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4063 return 0;
4065 #endif
4067 static int __devinit
4068 sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
4070 void __iomem *rom;
4071 int romptr;
4073 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4074 return 0;
4076 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4077 if(romptr > (0x10000 - 8))
4078 return 0;
4080 rom = rom_base + romptr;
4082 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4083 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4084 return 0;
4086 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4087 return 0;
4089 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4090 return 0;
4092 return 1;
4095 static unsigned char * __devinit
4096 sisfb_find_rom(struct pci_dev *pdev)
4098 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4099 void __iomem *rom_base;
4100 unsigned char *myrombase = NULL;
4101 u32 temp;
4102 size_t romsize;
4104 /* First, try the official pci ROM functions (except
4105 * on integrated chipsets which have no ROM).
4108 if(!ivideo->nbridge) {
4110 if((rom_base = pci_map_rom(pdev, &romsize))) {
4112 if(sisfb_check_rom(rom_base, ivideo)) {
4114 if((myrombase = vmalloc(65536))) {
4116 /* Work around bug in pci/rom.c: Folks forgot to check
4117 * whether the size retrieved from the BIOS image eventually
4118 * is larger than the mapped size
4120 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4121 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4123 memcpy_fromio(myrombase, rom_base,
4124 (romsize > 65536) ? 65536 : romsize);
4127 pci_unmap_rom(pdev, rom_base);
4131 if(myrombase) return myrombase;
4133 /* Otherwise do it the conventional way. */
4135 #if defined(__i386__) || defined(__x86_64__)
4137 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4139 rom_base = ioremap(temp, 65536);
4140 if(!rom_base)
4141 continue;
4143 if(!sisfb_check_rom(rom_base, ivideo)) {
4144 iounmap(rom_base);
4145 continue;
4148 if((myrombase = vmalloc(65536)))
4149 memcpy_fromio(myrombase, rom_base, 65536);
4151 iounmap(rom_base);
4152 break;
4156 #else
4158 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4159 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4160 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4162 rom_base = ioremap(ivideo->video_base, 65536);
4163 if(rom_base) {
4164 if(sisfb_check_rom(rom_base, ivideo)) {
4165 if((myrombase = vmalloc(65536)))
4166 memcpy_fromio(myrombase, rom_base, 65536);
4168 iounmap(rom_base);
4171 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4173 #endif
4175 return myrombase;
4178 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
4179 static void __devinit
4180 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4181 unsigned int min)
4183 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4185 if(!ivideo->video_vbase) {
4186 printk(KERN_ERR
4187 "sisfb: Unable to map maximum video RAM for size detection\n");
4188 (*mapsize) >>= 1;
4189 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4190 (*mapsize) >>= 1;
4191 if((*mapsize) < (min << 20))
4192 break;
4194 if(ivideo->video_vbase) {
4195 printk(KERN_ERR
4196 "sisfb: Video RAM size detection limited to %dMB\n",
4197 (int)((*mapsize) >> 20));
4201 #endif
4203 #ifdef CONFIG_FB_SIS_300
4204 static int __devinit
4205 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4207 void __iomem *FBAddress = ivideo->video_vbase;
4208 unsigned short temp;
4209 unsigned char reg;
4210 int i, j;
4212 andSISIDXREG(SISSR, 0x15, 0xFB);
4213 orSISIDXREG(SISSR, 0x15, 0x04);
4214 outSISIDXREG(SISSR, 0x13, 0x00);
4215 outSISIDXREG(SISSR, 0x14, 0xBF);
4217 for(i = 0; i < 2; i++) {
4218 temp = 0x1234;
4219 for(j = 0; j < 4; j++) {
4220 writew(temp, FBAddress);
4221 if(readw(FBAddress) == temp)
4222 break;
4223 orSISIDXREG(SISSR, 0x3c, 0x01);
4224 inSISIDXREG(SISSR, 0x05, reg);
4225 inSISIDXREG(SISSR, 0x05, reg);
4226 andSISIDXREG(SISSR, 0x3c, 0xfe);
4227 inSISIDXREG(SISSR, 0x05, reg);
4228 inSISIDXREG(SISSR, 0x05, reg);
4229 temp++;
4233 writel(0x01234567L, FBAddress);
4234 writel(0x456789ABL, (FBAddress + 4));
4235 writel(0x89ABCDEFL, (FBAddress + 8));
4236 writel(0xCDEF0123L, (FBAddress + 12));
4238 inSISIDXREG(SISSR, 0x3b, reg);
4239 if(reg & 0x01) {
4240 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4241 return 4; /* Channel A 128bit */
4244 if(readl((FBAddress + 4)) == 0x456789ABL)
4245 return 2; /* Channel B 64bit */
4247 return 1; /* 32bit */
4250 static int __devinit
4251 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4252 int PseudoRankCapacity, int PseudoAdrPinCount,
4253 unsigned int mapsize)
4255 void __iomem *FBAddr = ivideo->video_vbase;
4256 unsigned short sr14;
4257 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4258 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4259 static const unsigned short SiS_DRAMType[17][5] = {
4260 {0x0C,0x0A,0x02,0x40,0x39},
4261 {0x0D,0x0A,0x01,0x40,0x48},
4262 {0x0C,0x09,0x02,0x20,0x35},
4263 {0x0D,0x09,0x01,0x20,0x44},
4264 {0x0C,0x08,0x02,0x10,0x31},
4265 {0x0D,0x08,0x01,0x10,0x40},
4266 {0x0C,0x0A,0x01,0x20,0x34},
4267 {0x0C,0x09,0x01,0x08,0x32},
4268 {0x0B,0x08,0x02,0x08,0x21},
4269 {0x0C,0x08,0x01,0x08,0x30},
4270 {0x0A,0x08,0x02,0x04,0x11},
4271 {0x0B,0x0A,0x01,0x10,0x28},
4272 {0x09,0x08,0x02,0x02,0x01},
4273 {0x0B,0x09,0x01,0x08,0x24},
4274 {0x0B,0x08,0x01,0x04,0x20},
4275 {0x0A,0x08,0x01,0x02,0x10},
4276 {0x09,0x08,0x01,0x01,0x00}
4279 for(k = 0; k <= 16; k++) {
4281 RankCapacity = buswidth * SiS_DRAMType[k][3];
4283 if(RankCapacity != PseudoRankCapacity)
4284 continue;
4286 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4287 continue;
4289 BankNumHigh = RankCapacity * 16 * iteration - 1;
4290 if(iteration == 3) { /* Rank No */
4291 BankNumMid = RankCapacity * 16 - 1;
4292 } else {
4293 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4296 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4297 PhysicalAdrHigh = BankNumHigh;
4298 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4299 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4301 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4302 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4303 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4304 if(buswidth == 4) sr14 |= 0x80;
4305 else if(buswidth == 2) sr14 |= 0x40;
4306 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4307 outSISIDXREG(SISSR, 0x14, sr14);
4309 BankNumHigh <<= 16;
4310 BankNumMid <<= 16;
4312 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4313 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4314 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4315 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4316 continue;
4318 /* Write data */
4319 writew(((unsigned short)PhysicalAdrHigh),
4320 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4321 writew(((unsigned short)BankNumMid),
4322 (FBAddr + BankNumMid + PhysicalAdrHigh));
4323 writew(((unsigned short)PhysicalAdrHalfPage),
4324 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4325 writew(((unsigned short)PhysicalAdrOtherPage),
4326 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4328 /* Read data */
4329 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4330 return 1;
4333 return 0;
4336 static void __devinit
4337 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4339 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4340 int i, j, buswidth;
4341 int PseudoRankCapacity, PseudoAdrPinCount;
4343 buswidth = sisfb_post_300_buswidth(ivideo);
4345 for(i = 6; i >= 0; i--) {
4346 PseudoRankCapacity = 1 << i;
4347 for(j = 4; j >= 1; j--) {
4348 PseudoAdrPinCount = 15 - j;
4349 if((PseudoRankCapacity * j) <= 64) {
4350 if(sisfb_post_300_rwtest(ivideo,
4352 buswidth,
4353 PseudoRankCapacity,
4354 PseudoAdrPinCount,
4355 mapsize))
4356 return;
4362 static void __devinit
4363 sisfb_post_sis300(struct pci_dev *pdev)
4365 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4366 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4367 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4368 u16 index, rindex, memtype = 0;
4369 unsigned int mapsize;
4371 if(!ivideo->SiS_Pr.UseROM)
4372 bios = NULL;
4374 outSISIDXREG(SISSR, 0x05, 0x86);
4376 if(bios) {
4377 if(bios[0x52] & 0x80) {
4378 memtype = bios[0x52];
4379 } else {
4380 inSISIDXREG(SISSR, 0x3a, memtype);
4382 memtype &= 0x07;
4385 v3 = 0x80; v6 = 0x80;
4386 if(ivideo->revision_id <= 0x13) {
4387 v1 = 0x44; v2 = 0x42;
4388 v4 = 0x44; v5 = 0x42;
4389 } else {
4390 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4391 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4392 if(bios) {
4393 index = memtype * 5;
4394 rindex = index + 0x54;
4395 v1 = bios[rindex++];
4396 v2 = bios[rindex++];
4397 v3 = bios[rindex++];
4398 rindex = index + 0x7c;
4399 v4 = bios[rindex++];
4400 v5 = bios[rindex++];
4401 v6 = bios[rindex++];
4404 outSISIDXREG(SISSR, 0x28, v1);
4405 outSISIDXREG(SISSR, 0x29, v2);
4406 outSISIDXREG(SISSR, 0x2a, v3);
4407 outSISIDXREG(SISSR, 0x2e, v4);
4408 outSISIDXREG(SISSR, 0x2f, v5);
4409 outSISIDXREG(SISSR, 0x30, v6);
4411 v1 = 0x10;
4412 if(bios)
4413 v1 = bios[0xa4];
4414 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4416 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4418 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4419 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4420 if(bios) {
4421 memtype += 0xa5;
4422 v1 = bios[memtype];
4423 v2 = bios[memtype + 8];
4424 v3 = bios[memtype + 16];
4425 v4 = bios[memtype + 24];
4426 v5 = bios[memtype + 32];
4427 v6 = bios[memtype + 40];
4428 v7 = bios[memtype + 48];
4429 v8 = bios[memtype + 56];
4431 if(ivideo->revision_id >= 0x80)
4432 v3 &= 0xfd;
4433 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4434 outSISIDXREG(SISSR, 0x16, v2);
4435 outSISIDXREG(SISSR, 0x17, v3);
4436 outSISIDXREG(SISSR, 0x18, v4);
4437 outSISIDXREG(SISSR, 0x19, v5);
4438 outSISIDXREG(SISSR, 0x1a, v6);
4439 outSISIDXREG(SISSR, 0x1b, v7);
4440 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4441 andSISIDXREG(SISSR, 0x15 ,0xfb);
4442 orSISIDXREG(SISSR, 0x15, 0x04);
4443 if(bios) {
4444 if(bios[0x53] & 0x02) {
4445 orSISIDXREG(SISSR, 0x19, 0x20);
4448 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4449 if(ivideo->revision_id >= 0x80)
4450 v1 |= 0x01;
4451 outSISIDXREG(SISSR, 0x1f, v1);
4452 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4453 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4454 if(bios) {
4455 v1 = bios[0xe8];
4456 v2 = bios[0xe9];
4457 v3 = bios[0xea];
4459 outSISIDXREG(SISSR, 0x23, v1);
4460 outSISIDXREG(SISSR, 0x24, v2);
4461 outSISIDXREG(SISSR, 0x25, v3);
4462 outSISIDXREG(SISSR, 0x21, 0x84);
4463 outSISIDXREG(SISSR, 0x22, 0x00);
4464 outSISIDXREG(SISCR, 0x37, 0x00);
4465 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4466 outSISIDXREG(SISPART1, 0x00, 0x00);
4467 v1 = 0x40; v2 = 0x11;
4468 if(bios) {
4469 v1 = bios[0xec];
4470 v2 = bios[0xeb];
4472 outSISIDXREG(SISPART1, 0x02, v1);
4474 if(ivideo->revision_id >= 0x80)
4475 v2 &= ~0x01;
4477 inSISIDXREG(SISPART4, 0x00, reg);
4478 if((reg == 1) || (reg == 2)) {
4479 outSISIDXREG(SISCR, 0x37, 0x02);
4480 outSISIDXREG(SISPART2, 0x00, 0x1c);
4481 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4482 if(ivideo->SiS_Pr.UseROM) {
4483 v4 = bios[0xf5];
4484 v5 = bios[0xf6];
4485 v6 = bios[0xf7];
4487 outSISIDXREG(SISPART4, 0x0d, v4);
4488 outSISIDXREG(SISPART4, 0x0e, v5);
4489 outSISIDXREG(SISPART4, 0x10, v6);
4490 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4491 inSISIDXREG(SISPART4, 0x01, reg);
4492 if(reg >= 0xb0) {
4493 inSISIDXREG(SISPART4, 0x23, reg);
4494 reg &= 0x20;
4495 reg <<= 1;
4496 outSISIDXREG(SISPART4, 0x23, reg);
4498 } else {
4499 v2 &= ~0x10;
4501 outSISIDXREG(SISSR, 0x32, v2);
4503 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4505 inSISIDXREG(SISSR, 0x16, reg);
4506 reg &= 0xc3;
4507 outSISIDXREG(SISCR, 0x35, reg);
4508 outSISIDXREG(SISCR, 0x83, 0x00);
4509 #if !defined(__i386__) && !defined(__x86_64__)
4510 if(sisfb_videoram) {
4511 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4512 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4513 outSISIDXREG(SISSR, 0x14, reg);
4514 } else {
4515 #endif
4516 /* Need to map max FB size for finding out about RAM size */
4517 mapsize = 64 << 20;
4518 sisfb_post_map_vram(ivideo, &mapsize, 4);
4520 if(ivideo->video_vbase) {
4521 sisfb_post_300_ramsize(pdev, mapsize);
4522 iounmap(ivideo->video_vbase);
4523 } else {
4524 printk(KERN_DEBUG
4525 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4526 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4527 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4529 #if !defined(__i386__) && !defined(__x86_64__)
4531 #endif
4532 if(bios) {
4533 v1 = bios[0xe6];
4534 v2 = bios[0xe7];
4535 } else {
4536 inSISIDXREG(SISSR, 0x3a, reg);
4537 if((reg & 0x30) == 0x30) {
4538 v1 = 0x04; /* PCI */
4539 v2 = 0x92;
4540 } else {
4541 v1 = 0x14; /* AGP */
4542 v2 = 0xb2;
4545 outSISIDXREG(SISSR, 0x21, v1);
4546 outSISIDXREG(SISSR, 0x22, v2);
4548 /* Sense CRT1 */
4549 sisfb_sense_crt1(ivideo);
4551 /* Set default mode, don't clear screen */
4552 ivideo->SiS_Pr.SiS_UseOEM = false;
4553 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4554 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
4555 ivideo->curFSTN = ivideo->curDSTN = 0;
4556 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4557 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4559 outSISIDXREG(SISSR, 0x05, 0x86);
4561 /* Display off */
4562 orSISIDXREG(SISSR, 0x01, 0x20);
4564 /* Save mode number in CR34 */
4565 outSISIDXREG(SISCR, 0x34, 0x2e);
4567 /* Let everyone know what the current mode is */
4568 ivideo->modeprechange = 0x2e;
4570 #endif
4572 #ifdef CONFIG_FB_SIS_315
4573 #if 0
4574 static void __devinit
4575 sisfb_post_sis315330(struct pci_dev *pdev)
4577 /* TODO */
4579 #endif
4581 static void __devinit
4582 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4584 unsigned int i;
4585 u8 reg;
4587 for(i = 0; i <= (delay * 10 * 36); i++) {
4588 inSISIDXREG(SISSR, 0x05, reg);
4589 reg++;
4593 static int __devinit
4594 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4595 unsigned short pcivendor)
4597 struct pci_dev *pdev = NULL;
4598 unsigned short temp;
4599 int ret = 0;
4601 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
4602 temp = pdev->vendor;
4603 if(temp == pcivendor) {
4604 ret = 1;
4605 pci_dev_put(pdev);
4606 break;
4610 return ret;
4613 static int __devinit
4614 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4615 unsigned int enda, unsigned int mapsize)
4617 unsigned int pos;
4618 int i;
4620 writel(0, ivideo->video_vbase);
4622 for(i = starta; i <= enda; i++) {
4623 pos = 1 << i;
4624 if(pos < mapsize)
4625 writel(pos, ivideo->video_vbase + pos);
4628 sisfb_post_xgi_delay(ivideo, 150);
4630 if(readl(ivideo->video_vbase) != 0)
4631 return 0;
4633 for(i = starta; i <= enda; i++) {
4634 pos = 1 << i;
4635 if(pos < mapsize) {
4636 if(readl(ivideo->video_vbase + pos) != pos)
4637 return 0;
4638 } else
4639 return 0;
4642 return 1;
4645 static void __devinit
4646 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4648 unsigned int buswidth, ranksize, channelab, mapsize;
4649 int i, j, k, l;
4650 u8 reg, sr14;
4651 static const u8 dramsr13[12 * 5] = {
4652 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4653 0x02, 0x0e, 0x0a, 0x40, 0x59,
4654 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4655 0x02, 0x0e, 0x09, 0x20, 0x55,
4656 0x02, 0x0d, 0x0a, 0x20, 0x49,
4657 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4658 0x02, 0x0e, 0x08, 0x10, 0x51,
4659 0x02, 0x0d, 0x09, 0x10, 0x45,
4660 0x02, 0x0c, 0x0a, 0x10, 0x39,
4661 0x02, 0x0d, 0x08, 0x08, 0x41,
4662 0x02, 0x0c, 0x09, 0x08, 0x35,
4663 0x02, 0x0c, 0x08, 0x04, 0x31
4665 static const u8 dramsr13_4[4 * 5] = {
4666 0x02, 0x0d, 0x09, 0x40, 0x45,
4667 0x02, 0x0c, 0x09, 0x20, 0x35,
4668 0x02, 0x0c, 0x08, 0x10, 0x31,
4669 0x02, 0x0b, 0x08, 0x08, 0x21
4672 /* Enable linear mode, disable 0xa0000 address decoding */
4673 /* We disable a0000 address decoding, because
4674 * - if running on x86, if the card is disabled, it means
4675 * that another card is in the system. We don't want
4676 * to interphere with that primary card's textmode.
4677 * - if running on non-x86, there usually is no VGA window
4678 * at a0000.
4680 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4682 /* Need to map max FB size for finding out about RAM size */
4683 mapsize = 256 << 20;
4684 sisfb_post_map_vram(ivideo, &mapsize, 32);
4686 if(!ivideo->video_vbase) {
4687 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4688 outSISIDXREG(SISSR, 0x13, 0x35);
4689 outSISIDXREG(SISSR, 0x14, 0x41);
4690 /* TODO */
4691 return;
4694 /* Non-interleaving */
4695 outSISIDXREG(SISSR, 0x15, 0x00);
4696 /* No tiling */
4697 outSISIDXREG(SISSR, 0x1c, 0x00);
4699 if(ivideo->chip == XGI_20) {
4701 channelab = 1;
4702 inSISIDXREG(SISCR, 0x97, reg);
4703 if(!(reg & 0x01)) { /* Single 32/16 */
4704 buswidth = 32;
4705 outSISIDXREG(SISSR, 0x13, 0xb1);
4706 outSISIDXREG(SISSR, 0x14, 0x52);
4707 sisfb_post_xgi_delay(ivideo, 1);
4708 sr14 = 0x02;
4709 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4710 goto bail_out;
4712 outSISIDXREG(SISSR, 0x13, 0x31);
4713 outSISIDXREG(SISSR, 0x14, 0x42);
4714 sisfb_post_xgi_delay(ivideo, 1);
4715 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4716 goto bail_out;
4718 buswidth = 16;
4719 outSISIDXREG(SISSR, 0x13, 0xb1);
4720 outSISIDXREG(SISSR, 0x14, 0x41);
4721 sisfb_post_xgi_delay(ivideo, 1);
4722 sr14 = 0x01;
4723 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4724 goto bail_out;
4725 else
4726 outSISIDXREG(SISSR, 0x13, 0x31);
4727 } else { /* Dual 16/8 */
4728 buswidth = 16;
4729 outSISIDXREG(SISSR, 0x13, 0xb1);
4730 outSISIDXREG(SISSR, 0x14, 0x41);
4731 sisfb_post_xgi_delay(ivideo, 1);
4732 sr14 = 0x01;
4733 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4734 goto bail_out;
4736 outSISIDXREG(SISSR, 0x13, 0x31);
4737 outSISIDXREG(SISSR, 0x14, 0x31);
4738 sisfb_post_xgi_delay(ivideo, 1);
4739 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4740 goto bail_out;
4742 buswidth = 8;
4743 outSISIDXREG(SISSR, 0x13, 0xb1);
4744 outSISIDXREG(SISSR, 0x14, 0x30);
4745 sisfb_post_xgi_delay(ivideo, 1);
4746 sr14 = 0x00;
4747 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4748 goto bail_out;
4749 else
4750 outSISIDXREG(SISSR, 0x13, 0x31);
4753 } else { /* XGI_40 */
4755 inSISIDXREG(SISCR, 0x97, reg);
4756 if(!(reg & 0x10)) {
4757 inSISIDXREG(SISSR, 0x39, reg);
4758 reg >>= 1;
4761 if(reg & 0x01) { /* DDRII */
4762 buswidth = 32;
4763 if(ivideo->revision_id == 2) {
4764 channelab = 2;
4765 outSISIDXREG(SISSR, 0x13, 0xa1);
4766 outSISIDXREG(SISSR, 0x14, 0x44);
4767 sr14 = 0x04;
4768 sisfb_post_xgi_delay(ivideo, 1);
4769 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4770 goto bail_out;
4772 outSISIDXREG(SISSR, 0x13, 0x21);
4773 outSISIDXREG(SISSR, 0x14, 0x34);
4774 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4775 goto bail_out;
4777 channelab = 1;
4778 outSISIDXREG(SISSR, 0x13, 0xa1);
4779 outSISIDXREG(SISSR, 0x14, 0x40);
4780 sr14 = 0x00;
4781 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4782 goto bail_out;
4784 outSISIDXREG(SISSR, 0x13, 0x21);
4785 outSISIDXREG(SISSR, 0x14, 0x30);
4786 } else {
4787 channelab = 3;
4788 outSISIDXREG(SISSR, 0x13, 0xa1);
4789 outSISIDXREG(SISSR, 0x14, 0x4c);
4790 sr14 = 0x0c;
4791 sisfb_post_xgi_delay(ivideo, 1);
4792 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4793 goto bail_out;
4795 channelab = 2;
4796 outSISIDXREG(SISSR, 0x14, 0x48);
4797 sisfb_post_xgi_delay(ivideo, 1);
4798 sr14 = 0x08;
4799 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4800 goto bail_out;
4802 outSISIDXREG(SISSR, 0x13, 0x21);
4803 outSISIDXREG(SISSR, 0x14, 0x3c);
4804 sr14 = 0x0c;
4806 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4807 channelab = 3;
4808 } else {
4809 channelab = 2;
4810 outSISIDXREG(SISSR, 0x14, 0x38);
4811 sr14 = 0x08;
4814 sisfb_post_xgi_delay(ivideo, 1);
4816 } else { /* DDR */
4818 buswidth = 64;
4819 if(ivideo->revision_id == 2) {
4820 channelab = 1;
4821 outSISIDXREG(SISSR, 0x13, 0xa1);
4822 outSISIDXREG(SISSR, 0x14, 0x52);
4823 sisfb_post_xgi_delay(ivideo, 1);
4824 sr14 = 0x02;
4825 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4826 goto bail_out;
4828 outSISIDXREG(SISSR, 0x13, 0x21);
4829 outSISIDXREG(SISSR, 0x14, 0x42);
4830 } else {
4831 channelab = 2;
4832 outSISIDXREG(SISSR, 0x13, 0xa1);
4833 outSISIDXREG(SISSR, 0x14, 0x5a);
4834 sisfb_post_xgi_delay(ivideo, 1);
4835 sr14 = 0x0a;
4836 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4837 goto bail_out;
4839 outSISIDXREG(SISSR, 0x13, 0x21);
4840 outSISIDXREG(SISSR, 0x14, 0x4a);
4842 sisfb_post_xgi_delay(ivideo, 1);
4847 bail_out:
4848 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4849 sisfb_post_xgi_delay(ivideo, 1);
4851 j = (ivideo->chip == XGI_20) ? 5 : 9;
4852 k = (ivideo->chip == XGI_20) ? 12 : 4;
4854 for(i = 0; i < k; i++) {
4856 reg = (ivideo->chip == XGI_20) ?
4857 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4858 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4859 sisfb_post_xgi_delay(ivideo, 50);
4861 ranksize = (ivideo->chip == XGI_20) ?
4862 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4864 inSISIDXREG(SISSR, 0x13, reg);
4865 if(reg & 0x80) ranksize <<= 1;
4867 if(ivideo->chip == XGI_20) {
4868 if(buswidth == 16) ranksize <<= 1;
4869 else if(buswidth == 32) ranksize <<= 2;
4870 } else {
4871 if(buswidth == 64) ranksize <<= 1;
4874 reg = 0;
4875 l = channelab;
4876 if(l == 3) l = 4;
4877 if((ranksize * l) <= 256) {
4878 while((ranksize >>= 1)) reg += 0x10;
4881 if(!reg) continue;
4883 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4884 sisfb_post_xgi_delay(ivideo, 1);
4886 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4887 break;
4890 iounmap(ivideo->video_vbase);
4893 static void __devinit
4894 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4896 u8 v1, v2, v3;
4897 int index;
4898 static const u8 cs90[8 * 3] = {
4899 0x16, 0x01, 0x01,
4900 0x3e, 0x03, 0x01,
4901 0x7c, 0x08, 0x01,
4902 0x79, 0x06, 0x01,
4903 0x29, 0x01, 0x81,
4904 0x5c, 0x23, 0x01,
4905 0x5c, 0x23, 0x01,
4906 0x5c, 0x23, 0x01
4908 static const u8 csb8[8 * 3] = {
4909 0x5c, 0x23, 0x01,
4910 0x29, 0x01, 0x01,
4911 0x7c, 0x08, 0x01,
4912 0x79, 0x06, 0x01,
4913 0x29, 0x01, 0x81,
4914 0x5c, 0x23, 0x01,
4915 0x5c, 0x23, 0x01,
4916 0x5c, 0x23, 0x01
4919 regb = 0; /* ! */
4921 index = regb * 3;
4922 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4923 if(ivideo->haveXGIROM) {
4924 v1 = ivideo->bios_abase[0x90 + index];
4925 v2 = ivideo->bios_abase[0x90 + index + 1];
4926 v3 = ivideo->bios_abase[0x90 + index + 2];
4928 outSISIDXREG(SISSR, 0x28, v1);
4929 outSISIDXREG(SISSR, 0x29, v2);
4930 outSISIDXREG(SISSR, 0x2a, v3);
4931 sisfb_post_xgi_delay(ivideo, 0x43);
4932 sisfb_post_xgi_delay(ivideo, 0x43);
4933 sisfb_post_xgi_delay(ivideo, 0x43);
4934 index = regb * 3;
4935 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4936 if(ivideo->haveXGIROM) {
4937 v1 = ivideo->bios_abase[0xb8 + index];
4938 v2 = ivideo->bios_abase[0xb8 + index + 1];
4939 v3 = ivideo->bios_abase[0xb8 + index + 2];
4941 outSISIDXREG(SISSR, 0x2e, v1);
4942 outSISIDXREG(SISSR, 0x2f, v2);
4943 outSISIDXREG(SISSR, 0x30, v3);
4944 sisfb_post_xgi_delay(ivideo, 0x43);
4945 sisfb_post_xgi_delay(ivideo, 0x43);
4946 sisfb_post_xgi_delay(ivideo, 0x43);
4949 static int __devinit
4950 sisfb_post_xgi(struct pci_dev *pdev)
4952 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4953 unsigned char *bios = ivideo->bios_abase;
4954 struct pci_dev *mypdev = NULL;
4955 const u8 *ptr, *ptr2;
4956 u8 v1, v2, v3, v4, v5, reg, ramtype;
4957 u32 rega, regb, regd;
4958 int i, j, k, index;
4959 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4960 static const u8 cs76[2] = { 0xa3, 0xfb };
4961 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4962 static const u8 cs158[8] = {
4963 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4965 static const u8 cs160[8] = {
4966 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4968 static const u8 cs168[8] = {
4969 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4971 static const u8 cs128[3 * 8] = {
4972 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4973 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4974 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4976 static const u8 cs148[2 * 8] = {
4977 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4978 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4980 static const u8 cs31a[8 * 4] = {
4981 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
4982 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
4983 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4984 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4986 static const u8 cs33a[8 * 4] = {
4987 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4988 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4989 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4990 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4992 static const u8 cs45a[8 * 2] = {
4993 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
4994 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4996 static const u8 cs170[7 * 8] = {
4997 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4998 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4999 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5000 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5001 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5002 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5003 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5005 static const u8 cs1a8[3 * 8] = {
5006 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5007 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5008 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5010 static const u8 cs100[2 * 8] = {
5011 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5012 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5015 /* VGA enable */
5016 reg = inSISREG(SISVGAENABLE) | 0x01;
5017 outSISREG(SISVGAENABLE, reg);
5019 /* Misc */
5020 reg = inSISREG(SISMISCR) | 0x01;
5021 outSISREG(SISMISCW, reg);
5023 /* Unlock SR */
5024 outSISIDXREG(SISSR, 0x05, 0x86);
5025 inSISIDXREG(SISSR, 0x05, reg);
5026 if(reg != 0xa1)
5027 return 0;
5029 /* Clear some regs */
5030 for(i = 0; i < 0x22; i++) {
5031 if(0x06 + i == 0x20) continue;
5032 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5034 for(i = 0; i < 0x0b; i++) {
5035 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5037 for(i = 0; i < 0x10; i++) {
5038 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5041 ptr = cs78;
5042 if(ivideo->haveXGIROM) {
5043 ptr = (const u8 *)&bios[0x78];
5045 for(i = 0; i < 3; i++) {
5046 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5049 ptr = cs76;
5050 if(ivideo->haveXGIROM) {
5051 ptr = (const u8 *)&bios[0x76];
5053 for(i = 0; i < 2; i++) {
5054 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5057 v1 = 0x18; v2 = 0x00;
5058 if(ivideo->haveXGIROM) {
5059 v1 = bios[0x74];
5060 v2 = bios[0x75];
5062 outSISIDXREG(SISSR, 0x07, v1);
5063 outSISIDXREG(SISSR, 0x11, 0x0f);
5064 outSISIDXREG(SISSR, 0x1f, v2);
5065 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5066 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5067 outSISIDXREG(SISSR, 0x27, 0x74);
5069 ptr = cs7b;
5070 if(ivideo->haveXGIROM) {
5071 ptr = (const u8 *)&bios[0x7b];
5073 for(i = 0; i < 3; i++) {
5074 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5077 if(ivideo->chip == XGI_40) {
5078 if(ivideo->revision_id == 2) {
5079 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5081 outSISIDXREG(SISCR, 0x7d, 0xfe);
5082 outSISIDXREG(SISCR, 0x7e, 0x0f);
5084 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5085 andSISIDXREG(SISCR, 0x58, 0xd7);
5086 inSISIDXREG(SISCR, 0xcb, reg);
5087 if(reg & 0x20) {
5088 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5092 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5093 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5095 if(ivideo->chip == XGI_20) {
5096 outSISIDXREG(SISSR, 0x36, 0x70);
5097 } else {
5098 outSISIDXREG(SISVID, 0x00, 0x86);
5099 outSISIDXREG(SISVID, 0x32, 0x00);
5100 outSISIDXREG(SISVID, 0x30, 0x00);
5101 outSISIDXREG(SISVID, 0x32, 0x01);
5102 outSISIDXREG(SISVID, 0x30, 0x00);
5103 andSISIDXREG(SISVID, 0x2f, 0xdf);
5104 andSISIDXREG(SISCAP, 0x00, 0x3f);
5106 outSISIDXREG(SISPART1, 0x2f, 0x01);
5107 outSISIDXREG(SISPART1, 0x00, 0x00);
5108 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5109 outSISIDXREG(SISPART1, 0x2e, 0x08);
5110 andSISIDXREG(SISPART1, 0x35, 0x7f);
5111 andSISIDXREG(SISPART1, 0x50, 0xfe);
5113 inSISIDXREG(SISPART4, 0x00, reg);
5114 if(reg == 1 || reg == 2) {
5115 outSISIDXREG(SISPART2, 0x00, 0x1c);
5116 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5117 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5118 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5119 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5121 inSISIDXREG(SISPART4, 0x01, reg);
5122 if((reg & 0xf0) >= 0xb0) {
5123 inSISIDXREG(SISPART4, 0x23, reg);
5124 if(reg & 0x20) reg |= 0x40;
5125 outSISIDXREG(SISPART4, 0x23, reg);
5126 reg = (reg & 0x20) ? 0x02 : 0x00;
5127 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5131 v1 = bios[0x77];
5133 inSISIDXREG(SISSR, 0x3b, reg);
5134 if(reg & 0x02) {
5135 inSISIDXREG(SISSR, 0x3a, reg);
5136 v2 = (reg & 0x30) >> 3;
5137 if(!(v2 & 0x04)) v2 ^= 0x02;
5138 inSISIDXREG(SISSR, 0x39, reg);
5139 if(reg & 0x80) v2 |= 0x80;
5140 v2 |= 0x01;
5142 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5143 pci_dev_put(mypdev);
5144 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5145 v2 &= 0xf9;
5146 v2 |= 0x08;
5147 v1 &= 0xfe;
5148 } else {
5149 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
5150 if(!mypdev)
5151 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
5152 if(!mypdev)
5153 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
5154 if(mypdev) {
5155 pci_read_config_dword(mypdev, 0x94, &regd);
5156 regd &= 0xfffffeff;
5157 pci_write_config_dword(mypdev, 0x94, regd);
5158 v1 &= 0xfe;
5159 pci_dev_put(mypdev);
5160 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5161 v1 &= 0xfe;
5162 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5163 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5164 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5165 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5166 if((v2 & 0x06) == 4)
5167 v2 ^= 0x06;
5168 v2 |= 0x08;
5171 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5173 outSISIDXREG(SISSR, 0x22, v1);
5175 if(ivideo->revision_id == 2) {
5176 inSISIDXREG(SISSR, 0x3b, v1);
5177 inSISIDXREG(SISSR, 0x3a, v2);
5178 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5179 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5180 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5182 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
5183 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5184 * of nforce 2 ROM
5186 if(0)
5187 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5188 pci_dev_put(mypdev);
5192 v1 = 0x30;
5193 inSISIDXREG(SISSR, 0x3b, reg);
5194 inSISIDXREG(SISCR, 0x5f, v2);
5195 if((!(reg & 0x02)) && (v2 & 0x0e))
5196 v1 |= 0x08;
5197 outSISIDXREG(SISSR, 0x27, v1);
5199 if(bios[0x64] & 0x01) {
5200 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5203 v1 = bios[0x4f7];
5204 pci_read_config_dword(pdev, 0x50, &regd);
5205 regd = (regd >> 20) & 0x0f;
5206 if(regd == 1) {
5207 v1 &= 0xfc;
5208 orSISIDXREG(SISCR, 0x5f, 0x08);
5210 outSISIDXREG(SISCR, 0x48, v1);
5212 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5213 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5214 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5215 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5216 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5217 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5218 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5219 outSISIDXREG(SISCR, 0x74, 0xd0);
5220 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5221 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5222 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5223 v1 = bios[0x501];
5224 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
5225 v1 = 0xf0;
5226 pci_dev_put(mypdev);
5228 outSISIDXREG(SISCR, 0x77, v1);
5231 /* RAM type */
5233 regb = 0; /* ! */
5235 v1 = 0xff;
5236 if(ivideo->haveXGIROM) {
5237 v1 = bios[0x140 + regb];
5239 outSISIDXREG(SISCR, 0x6d, v1);
5241 ptr = cs128;
5242 if(ivideo->haveXGIROM) {
5243 ptr = (const u8 *)&bios[0x128];
5245 for(i = 0, j = 0; i < 3; i++, j += 8) {
5246 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5249 ptr = cs31a;
5250 ptr2 = cs33a;
5251 if(ivideo->haveXGIROM) {
5252 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5253 ptr = (const u8 *)&bios[index];
5254 ptr2 = (const u8 *)&bios[index + 0x20];
5256 for(i = 0; i < 2; i++) {
5257 if(i == 0) {
5258 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5259 rega = 0x6b;
5260 } else {
5261 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5262 rega = 0x6e;
5264 reg = 0x00;
5265 for(j = 0; j < 16; j++) {
5266 reg &= 0xf3;
5267 if(regd & 0x01) reg |= 0x04;
5268 if(regd & 0x02) reg |= 0x08;
5269 regd >>= 2;
5270 outSISIDXREG(SISCR, rega, reg);
5271 inSISIDXREG(SISCR, rega, reg);
5272 inSISIDXREG(SISCR, rega, reg);
5273 reg += 0x10;
5277 andSISIDXREG(SISCR, 0x6e, 0xfc);
5279 ptr = NULL;
5280 if(ivideo->haveXGIROM) {
5281 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5282 ptr = (const u8 *)&bios[index];
5284 for(i = 0; i < 4; i++) {
5285 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5286 reg = 0x00;
5287 for(j = 0; j < 2; j++) {
5288 regd = 0;
5289 if(ptr) {
5290 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5291 ptr += 4;
5293 /* reg = 0x00; */
5294 for(k = 0; k < 16; k++) {
5295 reg &= 0xfc;
5296 if(regd & 0x01) reg |= 0x01;
5297 if(regd & 0x02) reg |= 0x02;
5298 regd >>= 2;
5299 outSISIDXREG(SISCR, 0x6f, reg);
5300 inSISIDXREG(SISCR, 0x6f, reg);
5301 inSISIDXREG(SISCR, 0x6f, reg);
5302 reg += 0x08;
5307 ptr = cs148;
5308 if(ivideo->haveXGIROM) {
5309 ptr = (const u8 *)&bios[0x148];
5311 for(i = 0, j = 0; i < 2; i++, j += 8) {
5312 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5315 andSISIDXREG(SISCR, 0x89, 0x8f);
5317 ptr = cs45a;
5318 if(ivideo->haveXGIROM) {
5319 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5320 ptr = (const u8 *)&bios[index];
5322 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5323 reg = 0x80;
5324 for(i = 0; i < 5; i++) {
5325 reg &= 0xfc;
5326 if(regd & 0x01) reg |= 0x01;
5327 if(regd & 0x02) reg |= 0x02;
5328 regd >>= 2;
5329 outSISIDXREG(SISCR, 0x89, reg);
5330 inSISIDXREG(SISCR, 0x89, reg);
5331 inSISIDXREG(SISCR, 0x89, reg);
5332 reg += 0x10;
5335 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5336 if(ivideo->haveXGIROM) {
5337 v1 = bios[0x118 + regb];
5338 v2 = bios[0xf8 + regb];
5339 v3 = bios[0x120 + regb];
5340 v4 = bios[0x1ca];
5342 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5343 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5344 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5345 outSISIDXREG(SISCR, 0x41, v2);
5347 ptr = cs170;
5348 if(ivideo->haveXGIROM) {
5349 ptr = (const u8 *)&bios[0x170];
5351 for(i = 0, j = 0; i < 7; i++, j += 8) {
5352 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5355 outSISIDXREG(SISCR, 0x59, v3);
5357 ptr = cs1a8;
5358 if(ivideo->haveXGIROM) {
5359 ptr = (const u8 *)&bios[0x1a8];
5361 for(i = 0, j = 0; i < 3; i++, j += 8) {
5362 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5365 ptr = cs100;
5366 if(ivideo->haveXGIROM) {
5367 ptr = (const u8 *)&bios[0x100];
5369 for(i = 0, j = 0; i < 2; i++, j += 8) {
5370 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5373 outSISIDXREG(SISCR, 0xcf, v4);
5375 outSISIDXREG(SISCR, 0x83, 0x09);
5376 outSISIDXREG(SISCR, 0x87, 0x00);
5378 if(ivideo->chip == XGI_40) {
5379 if( (ivideo->revision_id == 1) ||
5380 (ivideo->revision_id == 2) ) {
5381 outSISIDXREG(SISCR, 0x8c, 0x87);
5385 outSISIDXREG(SISSR, 0x17, 0x00);
5386 outSISIDXREG(SISSR, 0x1a, 0x87);
5388 if(ivideo->chip == XGI_20) {
5389 outSISIDXREG(SISSR, 0x15, 0x00);
5390 outSISIDXREG(SISSR, 0x1c, 0x00);
5393 ramtype = 0x00; v1 = 0x10;
5394 if(ivideo->haveXGIROM) {
5395 ramtype = bios[0x62];
5396 v1 = bios[0x1d2];
5398 if(!(ramtype & 0x80)) {
5399 if(ivideo->chip == XGI_20) {
5400 outSISIDXREG(SISCR, 0x97, v1);
5401 inSISIDXREG(SISCR, 0x97, reg);
5402 if(reg & 0x10) {
5403 ramtype = (reg & 0x01) << 1;
5405 } else {
5406 inSISIDXREG(SISSR, 0x39, reg);
5407 ramtype = reg & 0x02;
5408 if(!(ramtype)) {
5409 inSISIDXREG(SISSR, 0x3a, reg);
5410 ramtype = (reg >> 1) & 0x01;
5414 ramtype &= 0x07;
5416 regb = 0; /* ! */
5418 switch(ramtype) {
5419 case 0:
5420 sisfb_post_xgi_setclocks(ivideo, regb);
5421 if((ivideo->chip == XGI_20) ||
5422 (ivideo->revision_id == 1) ||
5423 (ivideo->revision_id == 2)) {
5424 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5425 if(ivideo->haveXGIROM) {
5426 v1 = bios[regb + 0x158];
5427 v2 = bios[regb + 0x160];
5428 v3 = bios[regb + 0x168];
5430 outSISIDXREG(SISCR, 0x82, v1);
5431 outSISIDXREG(SISCR, 0x85, v2);
5432 outSISIDXREG(SISCR, 0x86, v3);
5433 } else {
5434 outSISIDXREG(SISCR, 0x82, 0x88);
5435 outSISIDXREG(SISCR, 0x86, 0x00);
5436 inSISIDXREG(SISCR, 0x86, reg);
5437 outSISIDXREG(SISCR, 0x86, 0x88);
5438 inSISIDXREG(SISCR, 0x86, reg);
5439 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5440 outSISIDXREG(SISCR, 0x82, 0x77);
5441 outSISIDXREG(SISCR, 0x85, 0x00);
5442 inSISIDXREG(SISCR, 0x85, reg);
5443 outSISIDXREG(SISCR, 0x85, 0x88);
5444 inSISIDXREG(SISCR, 0x85, reg);
5445 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5446 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5448 if(ivideo->chip == XGI_40) {
5449 outSISIDXREG(SISCR, 0x97, 0x00);
5451 outSISIDXREG(SISCR, 0x98, 0x01);
5452 outSISIDXREG(SISCR, 0x9a, 0x02);
5454 outSISIDXREG(SISSR, 0x18, 0x01);
5455 if((ivideo->chip == XGI_20) ||
5456 (ivideo->revision_id == 2)) {
5457 outSISIDXREG(SISSR, 0x19, 0x40);
5458 } else {
5459 outSISIDXREG(SISSR, 0x19, 0x20);
5461 outSISIDXREG(SISSR, 0x16, 0x00);
5462 outSISIDXREG(SISSR, 0x16, 0x80);
5463 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5464 sisfb_post_xgi_delay(ivideo, 0x43);
5465 sisfb_post_xgi_delay(ivideo, 0x43);
5466 sisfb_post_xgi_delay(ivideo, 0x43);
5467 outSISIDXREG(SISSR, 0x18, 0x00);
5468 if((ivideo->chip == XGI_20) ||
5469 (ivideo->revision_id == 2)) {
5470 outSISIDXREG(SISSR, 0x19, 0x40);
5471 } else {
5472 outSISIDXREG(SISSR, 0x19, 0x20);
5474 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5475 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5477 outSISIDXREG(SISSR, 0x16, 0x00);
5478 outSISIDXREG(SISSR, 0x16, 0x80);
5479 sisfb_post_xgi_delay(ivideo, 4);
5480 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5481 if(ivideo->haveXGIROM) {
5482 v1 = bios[0xf0];
5483 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5484 v2 = bios[index];
5485 v3 = bios[index + 1];
5486 v4 = bios[index + 2];
5487 v5 = bios[index + 3];
5489 outSISIDXREG(SISSR, 0x18, v1);
5490 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5491 outSISIDXREG(SISSR, 0x16, v2);
5492 outSISIDXREG(SISSR, 0x16, v3);
5493 sisfb_post_xgi_delay(ivideo, 0x43);
5494 outSISIDXREG(SISSR, 0x1b, 0x03);
5495 sisfb_post_xgi_delay(ivideo, 0x22);
5496 outSISIDXREG(SISSR, 0x18, v1);
5497 outSISIDXREG(SISSR, 0x19, 0x00);
5498 outSISIDXREG(SISSR, 0x16, v4);
5499 outSISIDXREG(SISSR, 0x16, v5);
5500 outSISIDXREG(SISSR, 0x1b, 0x00);
5501 break;
5502 case 1:
5503 outSISIDXREG(SISCR, 0x82, 0x77);
5504 outSISIDXREG(SISCR, 0x86, 0x00);
5505 inSISIDXREG(SISCR, 0x86, reg);
5506 outSISIDXREG(SISCR, 0x86, 0x88);
5507 inSISIDXREG(SISCR, 0x86, reg);
5508 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5509 if(ivideo->haveXGIROM) {
5510 v1 = bios[regb + 0x168];
5511 v2 = bios[regb + 0x160];
5512 v3 = bios[regb + 0x158];
5514 outSISIDXREG(SISCR, 0x86, v1);
5515 outSISIDXREG(SISCR, 0x82, 0x77);
5516 outSISIDXREG(SISCR, 0x85, 0x00);
5517 inSISIDXREG(SISCR, 0x85, reg);
5518 outSISIDXREG(SISCR, 0x85, 0x88);
5519 inSISIDXREG(SISCR, 0x85, reg);
5520 outSISIDXREG(SISCR, 0x85, v2);
5521 outSISIDXREG(SISCR, 0x82, v3);
5522 outSISIDXREG(SISCR, 0x98, 0x01);
5523 outSISIDXREG(SISCR, 0x9a, 0x02);
5525 outSISIDXREG(SISSR, 0x28, 0x64);
5526 outSISIDXREG(SISSR, 0x29, 0x63);
5527 sisfb_post_xgi_delay(ivideo, 15);
5528 outSISIDXREG(SISSR, 0x18, 0x00);
5529 outSISIDXREG(SISSR, 0x19, 0x20);
5530 outSISIDXREG(SISSR, 0x16, 0x00);
5531 outSISIDXREG(SISSR, 0x16, 0x80);
5532 outSISIDXREG(SISSR, 0x18, 0xc5);
5533 outSISIDXREG(SISSR, 0x19, 0x23);
5534 outSISIDXREG(SISSR, 0x16, 0x00);
5535 outSISIDXREG(SISSR, 0x16, 0x80);
5536 sisfb_post_xgi_delay(ivideo, 1);
5537 outSISIDXREG(SISCR, 0x97,0x11);
5538 sisfb_post_xgi_setclocks(ivideo, regb);
5539 sisfb_post_xgi_delay(ivideo, 0x46);
5540 outSISIDXREG(SISSR, 0x18, 0xc5);
5541 outSISIDXREG(SISSR, 0x19, 0x23);
5542 outSISIDXREG(SISSR, 0x16, 0x00);
5543 outSISIDXREG(SISSR, 0x16, 0x80);
5544 sisfb_post_xgi_delay(ivideo, 1);
5545 outSISIDXREG(SISSR, 0x1b, 0x04);
5546 sisfb_post_xgi_delay(ivideo, 1);
5547 outSISIDXREG(SISSR, 0x1b, 0x00);
5548 sisfb_post_xgi_delay(ivideo, 1);
5549 v1 = 0x31;
5550 if(ivideo->haveXGIROM) {
5551 v1 = bios[0xf0];
5553 outSISIDXREG(SISSR, 0x18, v1);
5554 outSISIDXREG(SISSR, 0x19, 0x06);
5555 outSISIDXREG(SISSR, 0x16, 0x04);
5556 outSISIDXREG(SISSR, 0x16, 0x84);
5557 sisfb_post_xgi_delay(ivideo, 1);
5558 break;
5559 default:
5560 sisfb_post_xgi_setclocks(ivideo, regb);
5561 if((ivideo->chip == XGI_40) &&
5562 ((ivideo->revision_id == 1) ||
5563 (ivideo->revision_id == 2))) {
5564 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5565 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5566 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5567 } else {
5568 outSISIDXREG(SISCR, 0x82, 0x88);
5569 outSISIDXREG(SISCR, 0x86, 0x00);
5570 inSISIDXREG(SISCR, 0x86, reg);
5571 outSISIDXREG(SISCR, 0x86, 0x88);
5572 outSISIDXREG(SISCR, 0x82, 0x77);
5573 outSISIDXREG(SISCR, 0x85, 0x00);
5574 inSISIDXREG(SISCR, 0x85, reg);
5575 outSISIDXREG(SISCR, 0x85, 0x88);
5576 inSISIDXREG(SISCR, 0x85, reg);
5577 v1 = cs160[regb]; v2 = cs158[regb];
5578 if(ivideo->haveXGIROM) {
5579 v1 = bios[regb + 0x160];
5580 v2 = bios[regb + 0x158];
5582 outSISIDXREG(SISCR, 0x85, v1);
5583 outSISIDXREG(SISCR, 0x82, v2);
5585 if(ivideo->chip == XGI_40) {
5586 outSISIDXREG(SISCR, 0x97, 0x11);
5588 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5589 outSISIDXREG(SISCR, 0x98, 0x01);
5590 } else {
5591 outSISIDXREG(SISCR, 0x98, 0x03);
5593 outSISIDXREG(SISCR, 0x9a, 0x02);
5595 if(ivideo->chip == XGI_40) {
5596 outSISIDXREG(SISSR, 0x18, 0x01);
5597 } else {
5598 outSISIDXREG(SISSR, 0x18, 0x00);
5600 outSISIDXREG(SISSR, 0x19, 0x40);
5601 outSISIDXREG(SISSR, 0x16, 0x00);
5602 outSISIDXREG(SISSR, 0x16, 0x80);
5603 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5604 sisfb_post_xgi_delay(ivideo, 0x43);
5605 sisfb_post_xgi_delay(ivideo, 0x43);
5606 sisfb_post_xgi_delay(ivideo, 0x43);
5607 outSISIDXREG(SISSR, 0x18, 0x00);
5608 outSISIDXREG(SISSR, 0x19, 0x40);
5609 outSISIDXREG(SISSR, 0x16, 0x00);
5610 outSISIDXREG(SISSR, 0x16, 0x80);
5612 sisfb_post_xgi_delay(ivideo, 4);
5613 v1 = 0x31;
5614 if(ivideo->haveXGIROM) {
5615 v1 = bios[0xf0];
5617 outSISIDXREG(SISSR, 0x18, v1);
5618 outSISIDXREG(SISSR, 0x19, 0x01);
5619 if(ivideo->chip == XGI_40) {
5620 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5621 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5622 } else {
5623 outSISIDXREG(SISSR, 0x16, 0x05);
5624 outSISIDXREG(SISSR, 0x16, 0x85);
5626 sisfb_post_xgi_delay(ivideo, 0x43);
5627 if(ivideo->chip == XGI_40) {
5628 outSISIDXREG(SISSR, 0x1b, 0x01);
5629 } else {
5630 outSISIDXREG(SISSR, 0x1b, 0x03);
5632 sisfb_post_xgi_delay(ivideo, 0x22);
5633 outSISIDXREG(SISSR, 0x18, v1);
5634 outSISIDXREG(SISSR, 0x19, 0x00);
5635 if(ivideo->chip == XGI_40) {
5636 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5637 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5638 } else {
5639 outSISIDXREG(SISSR, 0x16, 0x05);
5640 outSISIDXREG(SISSR, 0x16, 0x85);
5642 outSISIDXREG(SISSR, 0x1b, 0x00);
5645 regb = 0; /* ! */
5646 v1 = 0x03;
5647 if(ivideo->haveXGIROM) {
5648 v1 = bios[0x110 + regb];
5650 outSISIDXREG(SISSR, 0x1b, v1);
5652 /* RAM size */
5653 v1 = 0x00; v2 = 0x00;
5654 if(ivideo->haveXGIROM) {
5655 v1 = bios[0x62];
5656 v2 = bios[0x63];
5658 regb = 0; /* ! */
5659 regd = 1 << regb;
5660 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5662 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5663 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5665 } else {
5667 /* Set default mode, don't clear screen */
5668 ivideo->SiS_Pr.SiS_UseOEM = false;
5669 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5670 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5671 ivideo->curFSTN = ivideo->curDSTN = 0;
5672 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5673 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5675 outSISIDXREG(SISSR, 0x05, 0x86);
5677 /* Disable read-cache */
5678 andSISIDXREG(SISSR, 0x21, 0xdf);
5679 sisfb_post_xgi_ramsize(ivideo);
5680 /* Enable read-cache */
5681 orSISIDXREG(SISSR, 0x21, 0x20);
5685 #if 0
5686 printk(KERN_DEBUG "-----------------\n");
5687 for(i = 0; i < 0xff; i++) {
5688 inSISIDXREG(SISCR, i, reg);
5689 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5691 for(i = 0; i < 0x40; i++) {
5692 inSISIDXREG(SISSR, i, reg);
5693 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5695 printk(KERN_DEBUG "-----------------\n");
5696 #endif
5698 /* Sense CRT1 */
5699 if(ivideo->chip == XGI_20) {
5700 orSISIDXREG(SISCR, 0x32, 0x20);
5701 } else {
5702 inSISIDXREG(SISPART4, 0x00, reg);
5703 if((reg == 1) || (reg == 2)) {
5704 sisfb_sense_crt1(ivideo);
5705 } else {
5706 orSISIDXREG(SISCR, 0x32, 0x20);
5710 /* Set default mode, don't clear screen */
5711 ivideo->SiS_Pr.SiS_UseOEM = false;
5712 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5713 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5714 ivideo->curFSTN = ivideo->curDSTN = 0;
5715 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5717 outSISIDXREG(SISSR, 0x05, 0x86);
5719 /* Display off */
5720 orSISIDXREG(SISSR, 0x01, 0x20);
5722 /* Save mode number in CR34 */
5723 outSISIDXREG(SISCR, 0x34, 0x2e);
5725 /* Let everyone know what the current mode is */
5726 ivideo->modeprechange = 0x2e;
5728 if(ivideo->chip == XGI_40) {
5729 inSISIDXREG(SISCR, 0xca, reg);
5730 inSISIDXREG(SISCR, 0xcc, v1);
5731 if((reg & 0x10) && (!(v1 & 0x04))) {
5732 printk(KERN_ERR
5733 "sisfb: Please connect power to the card.\n");
5734 return 0;
5738 return 1;
5740 #endif
5742 static int __devinit
5743 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5745 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5746 struct sis_video_info *ivideo = NULL;
5747 struct fb_info *sis_fb_info = NULL;
5748 u16 reg16;
5749 u8 reg;
5750 int i, ret;
5752 if(sisfb_off)
5753 return -ENXIO;
5755 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5756 if(!sis_fb_info)
5757 return -ENOMEM;
5759 ivideo = (struct sis_video_info *)sis_fb_info->par;
5760 ivideo->memyselfandi = sis_fb_info;
5762 ivideo->sisfb_id = SISFB_ID;
5764 if(card_list == NULL) {
5765 ivideo->cardnumber = 0;
5766 } else {
5767 struct sis_video_info *countvideo = card_list;
5768 ivideo->cardnumber = 1;
5769 while((countvideo = countvideo->next) != NULL)
5770 ivideo->cardnumber++;
5773 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5775 ivideo->warncount = 0;
5776 ivideo->chip_id = pdev->device;
5777 ivideo->chip_vendor = pdev->vendor;
5778 ivideo->revision_id = pdev->revision;
5779 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5780 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
5781 ivideo->sisvga_enabled = reg16 & 0x01;
5782 ivideo->pcibus = pdev->bus->number;
5783 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5784 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5785 ivideo->subsysvendor = pdev->subsystem_vendor;
5786 ivideo->subsysdevice = pdev->subsystem_device;
5788 #ifndef MODULE
5789 if(sisfb_mode_idx == -1) {
5790 sisfb_get_vga_mode_from_kernel();
5792 #endif
5794 ivideo->chip = chipinfo->chip;
5795 ivideo->sisvga_engine = chipinfo->vgaengine;
5796 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5797 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5798 ivideo->mni = chipinfo->mni;
5800 ivideo->detectedpdc = 0xff;
5801 ivideo->detectedpdca = 0xff;
5802 ivideo->detectedlcda = 0xff;
5804 ivideo->sisfb_thismonitor.datavalid = false;
5806 ivideo->current_base = 0;
5808 ivideo->engineok = 0;
5810 ivideo->sisfb_was_boot_device = 0;
5812 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5813 if(ivideo->sisvga_enabled)
5814 ivideo->sisfb_was_boot_device = 1;
5815 else {
5816 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5817 "but marked as boot video device ???\n");
5818 printk(KERN_DEBUG "sisfb: I will not accept this "
5819 "as the primary VGA device\n");
5823 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5824 ivideo->sisfb_accel = sisfb_accel;
5825 ivideo->sisfb_ypan = sisfb_ypan;
5826 ivideo->sisfb_max = sisfb_max;
5827 ivideo->sisfb_userom = sisfb_userom;
5828 ivideo->sisfb_useoem = sisfb_useoem;
5829 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5830 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5831 ivideo->sisfb_crt1off = sisfb_crt1off;
5832 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5833 ivideo->sisfb_crt2type = sisfb_crt2type;
5834 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5835 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5836 ivideo->sisfb_dstn = sisfb_dstn;
5837 ivideo->sisfb_fstn = sisfb_fstn;
5838 ivideo->sisfb_tvplug = sisfb_tvplug;
5839 ivideo->sisfb_tvstd = sisfb_tvstd;
5840 ivideo->tvxpos = sisfb_tvxposoffset;
5841 ivideo->tvypos = sisfb_tvyposoffset;
5842 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5843 ivideo->refresh_rate = 0;
5844 if(ivideo->sisfb_parm_rate != -1) {
5845 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5848 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5849 ivideo->SiS_Pr.CenterScreen = -1;
5850 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5851 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5853 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5854 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5855 ivideo->SiS_Pr.SiS_ChSW = false;
5856 ivideo->SiS_Pr.SiS_UseLCDA = false;
5857 ivideo->SiS_Pr.HaveEMI = false;
5858 ivideo->SiS_Pr.HaveEMILCD = false;
5859 ivideo->SiS_Pr.OverruleEMI = false;
5860 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
5861 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5862 ivideo->SiS_Pr.PDC = -1;
5863 ivideo->SiS_Pr.PDCA = -1;
5864 ivideo->SiS_Pr.DDCPortMixup = false;
5865 #ifdef CONFIG_FB_SIS_315
5866 if(ivideo->chip >= SIS_330) {
5867 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5868 if(ivideo->chip >= SIS_661) {
5869 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
5872 #endif
5874 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5876 pci_set_drvdata(pdev, ivideo);
5878 /* Patch special cases */
5879 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5880 switch(ivideo->nbridge->device) {
5881 #ifdef CONFIG_FB_SIS_300
5882 case PCI_DEVICE_ID_SI_730:
5883 ivideo->chip = SIS_730;
5884 strcpy(ivideo->myid, "SiS 730");
5885 break;
5886 #endif
5887 #ifdef CONFIG_FB_SIS_315
5888 case PCI_DEVICE_ID_SI_651:
5889 /* ivideo->chip is ok */
5890 strcpy(ivideo->myid, "SiS 651");
5891 break;
5892 case PCI_DEVICE_ID_SI_740:
5893 ivideo->chip = SIS_740;
5894 strcpy(ivideo->myid, "SiS 740");
5895 break;
5896 case PCI_DEVICE_ID_SI_661:
5897 ivideo->chip = SIS_661;
5898 strcpy(ivideo->myid, "SiS 661");
5899 break;
5900 case PCI_DEVICE_ID_SI_741:
5901 ivideo->chip = SIS_741;
5902 strcpy(ivideo->myid, "SiS 741");
5903 break;
5904 case PCI_DEVICE_ID_SI_760:
5905 ivideo->chip = SIS_760;
5906 strcpy(ivideo->myid, "SiS 760");
5907 break;
5908 case PCI_DEVICE_ID_SI_761:
5909 ivideo->chip = SIS_761;
5910 strcpy(ivideo->myid, "SiS 761");
5911 break;
5912 #endif
5913 default:
5914 break;
5918 ivideo->SiS_Pr.ChipType = ivideo->chip;
5920 ivideo->SiS_Pr.ivideo = (void *)ivideo;
5922 #ifdef CONFIG_FB_SIS_315
5923 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5924 (ivideo->SiS_Pr.ChipType == SIS_315)) {
5925 ivideo->SiS_Pr.ChipType = SIS_315H;
5927 #endif
5929 if(!ivideo->sisvga_enabled) {
5930 if(pci_enable_device(pdev)) {
5931 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
5932 pci_set_drvdata(pdev, NULL);
5933 kfree(sis_fb_info);
5934 return -EIO;
5938 ivideo->video_base = pci_resource_start(pdev, 0);
5939 ivideo->mmio_base = pci_resource_start(pdev, 1);
5940 ivideo->mmio_size = pci_resource_len(pdev, 1);
5941 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
5942 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
5944 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
5946 #ifdef CONFIG_FB_SIS_300
5947 /* Find PCI systems for Chrontel/GPIO communication setup */
5948 if(ivideo->chip == SIS_630) {
5949 i = 0;
5950 do {
5951 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5952 mychswtable[i].subsysCard == ivideo->subsysdevice) {
5953 ivideo->SiS_Pr.SiS_ChSW = true;
5954 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5955 "requiring Chrontel/GPIO setup\n",
5956 mychswtable[i].vendorName,
5957 mychswtable[i].cardName);
5958 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
5959 break;
5961 i++;
5962 } while(mychswtable[i].subsysVendor != 0);
5964 #endif
5966 #ifdef CONFIG_FB_SIS_315
5967 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
5968 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
5970 #endif
5972 outSISIDXREG(SISSR, 0x05, 0x86);
5974 if( (!ivideo->sisvga_enabled)
5975 #if !defined(__i386__) && !defined(__x86_64__)
5976 || (sisfb_resetcard)
5977 #endif
5979 for(i = 0x30; i <= 0x3f; i++) {
5980 outSISIDXREG(SISCR, i, 0x00);
5984 /* Find out about current video mode */
5985 ivideo->modeprechange = 0x03;
5986 inSISIDXREG(SISCR, 0x34, reg);
5987 if(reg & 0x7f) {
5988 ivideo->modeprechange = reg & 0x7f;
5989 } else if(ivideo->sisvga_enabled) {
5990 #if defined(__i386__) || defined(__x86_64__)
5991 unsigned char __iomem *tt = ioremap(0x400, 0x100);
5992 if(tt) {
5993 ivideo->modeprechange = readb(tt + 0x49);
5994 iounmap(tt);
5996 #endif
5999 /* Search and copy ROM image */
6000 ivideo->bios_abase = NULL;
6001 ivideo->SiS_Pr.VirtualRomBase = NULL;
6002 ivideo->SiS_Pr.UseROM = false;
6003 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
6004 if(ivideo->sisfb_userom) {
6005 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6006 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6007 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
6008 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6009 ivideo->SiS_Pr.UseROM ? "" : "not ");
6010 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6011 ivideo->SiS_Pr.UseROM = false;
6012 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
6013 if( (ivideo->revision_id == 2) &&
6014 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6015 ivideo->SiS_Pr.DDCPortMixup = true;
6018 } else {
6019 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6022 /* Find systems for special custom timing */
6023 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6024 sisfb_detect_custom_timing(ivideo);
6027 /* POST card in case this has not been done by the BIOS */
6028 if( (!ivideo->sisvga_enabled)
6029 #if !defined(__i386__) && !defined(__x86_64__)
6030 || (sisfb_resetcard)
6031 #endif
6033 #ifdef CONFIG_FB_SIS_300
6034 if(ivideo->sisvga_engine == SIS_300_VGA) {
6035 if(ivideo->chip == SIS_300) {
6036 sisfb_post_sis300(pdev);
6037 ivideo->sisfb_can_post = 1;
6040 #endif
6042 #ifdef CONFIG_FB_SIS_315
6043 if(ivideo->sisvga_engine == SIS_315_VGA) {
6044 int result = 1;
6045 /* if((ivideo->chip == SIS_315H) ||
6046 (ivideo->chip == SIS_315) ||
6047 (ivideo->chip == SIS_315PRO) ||
6048 (ivideo->chip == SIS_330)) {
6049 sisfb_post_sis315330(pdev);
6050 } else */ if(ivideo->chip == XGI_20) {
6051 result = sisfb_post_xgi(pdev);
6052 ivideo->sisfb_can_post = 1;
6053 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6054 result = sisfb_post_xgi(pdev);
6055 ivideo->sisfb_can_post = 1;
6056 } else {
6057 printk(KERN_INFO "sisfb: Card is not "
6058 "POSTed and sisfb can't do this either.\n");
6060 if(!result) {
6061 printk(KERN_ERR "sisfb: Failed to POST card\n");
6062 ret = -ENODEV;
6063 goto error_3;
6066 #endif
6069 ivideo->sisfb_card_posted = 1;
6071 /* Find out about RAM size */
6072 if(sisfb_get_dram_size(ivideo)) {
6073 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6074 ret = -ENODEV;
6075 goto error_3;
6079 /* Enable PCI addressing and MMIO */
6080 if((ivideo->sisfb_mode_idx < 0) ||
6081 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6082 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6083 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6084 /* Enable 2D accelerator engine */
6085 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6088 if(sisfb_pdc != 0xff) {
6089 if(ivideo->sisvga_engine == SIS_300_VGA)
6090 sisfb_pdc &= 0x3c;
6091 else
6092 sisfb_pdc &= 0x1f;
6093 ivideo->SiS_Pr.PDC = sisfb_pdc;
6095 #ifdef CONFIG_FB_SIS_315
6096 if(ivideo->sisvga_engine == SIS_315_VGA) {
6097 if(sisfb_pdca != 0xff)
6098 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6100 #endif
6102 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6103 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6104 (int)(ivideo->video_size >> 20));
6105 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6106 ret = -ENODEV;
6107 goto error_3;
6110 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6111 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6112 ret = -ENODEV;
6113 goto error_2;
6116 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6117 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6118 if(!ivideo->video_vbase) {
6119 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6120 ret = -ENODEV;
6121 goto error_1;
6124 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6125 if(!ivideo->mmio_vbase) {
6126 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6127 ret = -ENODEV;
6128 error_0: iounmap(ivideo->video_vbase);
6129 error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6130 error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6131 error_3: vfree(ivideo->bios_abase);
6132 if(ivideo->lpcdev)
6133 pci_dev_put(ivideo->lpcdev);
6134 if(ivideo->nbridge)
6135 pci_dev_put(ivideo->nbridge);
6136 pci_set_drvdata(pdev, NULL);
6137 if(!ivideo->sisvga_enabled)
6138 pci_disable_device(pdev);
6139 kfree(sis_fb_info);
6140 return ret;
6143 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6144 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6146 if(ivideo->video_offset) {
6147 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6148 ivideo->video_offset / 1024);
6151 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6152 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6155 /* Determine the size of the command queue */
6156 if(ivideo->sisvga_engine == SIS_300_VGA) {
6157 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6158 } else {
6159 if(ivideo->chip == XGI_20) {
6160 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6161 } else {
6162 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6166 /* Engines are no longer initialized here; this is
6167 * now done after the first mode-switch (if the
6168 * submitted var has its acceleration flags set).
6171 /* Calculate the base of the (unused) hw cursor */
6172 ivideo->hwcursor_vbase = ivideo->video_vbase
6173 + ivideo->video_size
6174 - ivideo->cmdQueueSize
6175 - ivideo->hwcursor_size;
6176 ivideo->caps |= HW_CURSOR_CAP;
6178 /* Initialize offscreen memory manager */
6179 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6180 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6183 /* Used for clearing the screen only, therefore respect our mem limit */
6184 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6185 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6187 ivideo->mtrr = -1;
6189 ivideo->vbflags = 0;
6190 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6191 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6192 ivideo->defmodeidx = DEFAULT_MODE;
6194 ivideo->newrom = 0;
6195 if(ivideo->chip < XGI_20) {
6196 if(ivideo->bios_abase) {
6197 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6201 if((ivideo->sisfb_mode_idx < 0) ||
6202 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6204 sisfb_sense_crt1(ivideo);
6206 sisfb_get_VB_type(ivideo);
6208 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6209 sisfb_detect_VB_connect(ivideo);
6212 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6214 /* Decide on which CRT2 device to use */
6215 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6216 if(ivideo->sisfb_crt2type != -1) {
6217 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6218 (ivideo->vbflags & CRT2_LCD)) {
6219 ivideo->currentvbflags |= CRT2_LCD;
6220 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6221 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6223 } else {
6224 /* Chrontel 700x TV detection often unreliable, therefore
6225 * use a different default order on such machines
6227 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6228 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6229 if(ivideo->vbflags & CRT2_LCD)
6230 ivideo->currentvbflags |= CRT2_LCD;
6231 else if(ivideo->vbflags & CRT2_TV)
6232 ivideo->currentvbflags |= CRT2_TV;
6233 else if(ivideo->vbflags & CRT2_VGA)
6234 ivideo->currentvbflags |= CRT2_VGA;
6235 } else {
6236 if(ivideo->vbflags & CRT2_TV)
6237 ivideo->currentvbflags |= CRT2_TV;
6238 else if(ivideo->vbflags & CRT2_LCD)
6239 ivideo->currentvbflags |= CRT2_LCD;
6240 else if(ivideo->vbflags & CRT2_VGA)
6241 ivideo->currentvbflags |= CRT2_VGA;
6246 if(ivideo->vbflags & CRT2_LCD) {
6247 sisfb_detect_lcd_type(ivideo);
6250 sisfb_save_pdc_emi(ivideo);
6252 if(!ivideo->sisfb_crt1off) {
6253 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6254 } else {
6255 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6256 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6257 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6261 if(ivideo->sisfb_mode_idx >= 0) {
6262 int bu = ivideo->sisfb_mode_idx;
6263 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6264 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6265 if(bu != ivideo->sisfb_mode_idx) {
6266 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6267 sisbios_mode[bu].xres,
6268 sisbios_mode[bu].yres,
6269 sisbios_mode[bu].bpp);
6273 if(ivideo->sisfb_mode_idx < 0) {
6274 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6275 case CRT2_LCD:
6276 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6277 break;
6278 case CRT2_TV:
6279 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6280 break;
6281 default:
6282 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6283 break;
6287 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6289 if(ivideo->refresh_rate != 0) {
6290 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6291 ivideo->sisfb_mode_idx);
6294 if(ivideo->rate_idx == 0) {
6295 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6296 ivideo->refresh_rate = 60;
6299 if(ivideo->sisfb_thismonitor.datavalid) {
6300 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6301 ivideo->sisfb_mode_idx,
6302 ivideo->rate_idx,
6303 ivideo->refresh_rate)) {
6304 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6305 "exceeds monitor specs!\n");
6309 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6310 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6311 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6313 sisfb_set_vparms(ivideo);
6315 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6316 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6317 ivideo->refresh_rate);
6319 /* Set up the default var according to chosen default display mode */
6320 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6321 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6322 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6324 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6326 ivideo->default_var.pixclock = (u32) (1000000000 /
6327 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6329 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6330 ivideo->rate_idx, &ivideo->default_var)) {
6331 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6332 ivideo->default_var.pixclock <<= 1;
6336 if(ivideo->sisfb_ypan) {
6337 /* Maximize regardless of sisfb_max at startup */
6338 ivideo->default_var.yres_virtual =
6339 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6340 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6341 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6345 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6347 ivideo->accel = 0;
6348 if(ivideo->sisfb_accel) {
6349 ivideo->accel = -1;
6350 #ifdef STUPID_ACCELF_TEXT_SHIT
6351 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6352 #endif
6354 sisfb_initaccel(ivideo);
6356 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6357 sis_fb_info->flags = FBINFO_DEFAULT |
6358 FBINFO_HWACCEL_YPAN |
6359 FBINFO_HWACCEL_XPAN |
6360 FBINFO_HWACCEL_COPYAREA |
6361 FBINFO_HWACCEL_FILLRECT |
6362 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6363 #else
6364 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6365 #endif
6366 sis_fb_info->var = ivideo->default_var;
6367 sis_fb_info->fix = ivideo->sisfb_fix;
6368 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6369 sis_fb_info->fbops = &sisfb_ops;
6370 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6371 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6373 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6375 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6377 #ifdef CONFIG_MTRR
6378 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6379 MTRR_TYPE_WRCOMB, 1);
6380 if(ivideo->mtrr < 0) {
6381 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6383 #endif
6385 if(register_framebuffer(sis_fb_info) < 0) {
6386 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6387 ret = -EINVAL;
6388 iounmap(ivideo->mmio_vbase);
6389 goto error_0;
6392 ivideo->registered = 1;
6394 /* Enlist us */
6395 ivideo->next = card_list;
6396 card_list = ivideo;
6398 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6399 ivideo->sisfb_accel ? "enabled" : "disabled",
6400 ivideo->sisfb_ypan ?
6401 (ivideo->sisfb_max ? "enabled (auto-max)" :
6402 "enabled (no auto-max)") :
6403 "disabled");
6406 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6407 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6409 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6411 } /* if mode = "none" */
6413 return 0;
6416 /*****************************************************/
6417 /* PCI DEVICE HANDLING */
6418 /*****************************************************/
6420 static void __devexit sisfb_remove(struct pci_dev *pdev)
6422 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6423 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6424 int registered = ivideo->registered;
6425 int modechanged = ivideo->modechanged;
6427 /* Unmap */
6428 iounmap(ivideo->mmio_vbase);
6429 iounmap(ivideo->video_vbase);
6431 /* Release mem regions */
6432 release_mem_region(ivideo->video_base, ivideo->video_size);
6433 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6435 vfree(ivideo->bios_abase);
6437 if(ivideo->lpcdev)
6438 pci_dev_put(ivideo->lpcdev);
6440 if(ivideo->nbridge)
6441 pci_dev_put(ivideo->nbridge);
6443 #ifdef CONFIG_MTRR
6444 /* Release MTRR region */
6445 if(ivideo->mtrr >= 0)
6446 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6447 #endif
6449 pci_set_drvdata(pdev, NULL);
6451 /* If device was disabled when starting, disable
6452 * it when quitting.
6454 if(!ivideo->sisvga_enabled)
6455 pci_disable_device(pdev);
6457 /* Unregister the framebuffer */
6458 if(ivideo->registered) {
6459 unregister_framebuffer(sis_fb_info);
6460 framebuffer_release(sis_fb_info);
6463 /* OK, our ivideo is gone for good from here. */
6465 /* TODO: Restore the initial mode
6466 * This sounds easy but is as good as impossible
6467 * on many machines with SiS chip and video bridge
6468 * since text modes are always set up differently
6469 * from machine to machine. Depends on the type
6470 * of integration between chipset and bridge.
6472 if(registered && modechanged)
6473 printk(KERN_INFO
6474 "sisfb: Restoring of text mode not supported yet\n");
6477 static struct pci_driver sisfb_driver = {
6478 .name = "sisfb",
6479 .id_table = sisfb_pci_table,
6480 .probe = sisfb_probe,
6481 .remove = __devexit_p(sisfb_remove)
6484 static int __init sisfb_init(void)
6486 #ifndef MODULE
6487 char *options = NULL;
6489 if(fb_get_options("sisfb", &options))
6490 return -ENODEV;
6492 sisfb_setup(options);
6493 #endif
6494 return pci_register_driver(&sisfb_driver);
6497 #ifndef MODULE
6498 module_init(sisfb_init);
6499 #endif
6501 /*****************************************************/
6502 /* MODULE */
6503 /*****************************************************/
6505 #ifdef MODULE
6507 static char *mode = NULL;
6508 static int vesa = -1;
6509 static unsigned int rate = 0;
6510 static unsigned int crt1off = 1;
6511 static unsigned int mem = 0;
6512 static char *forcecrt2type = NULL;
6513 static int forcecrt1 = -1;
6514 static int pdc = -1;
6515 static int pdc1 = -1;
6516 static int noaccel = -1;
6517 static int noypan = -1;
6518 static int nomax = -1;
6519 static int userom = -1;
6520 static int useoem = -1;
6521 static char *tvstandard = NULL;
6522 static int nocrt2rate = 0;
6523 static int scalelcd = -1;
6524 static char *specialtiming = NULL;
6525 static int lvdshl = -1;
6526 static int tvxposoffset = 0, tvyposoffset = 0;
6527 #if !defined(__i386__) && !defined(__x86_64__)
6528 static int resetcard = 0;
6529 static int videoram = 0;
6530 #endif
6532 static int __init sisfb_init_module(void)
6534 sisfb_setdefaultparms();
6536 if(rate)
6537 sisfb_parm_rate = rate;
6539 if((scalelcd == 0) || (scalelcd == 1))
6540 sisfb_scalelcd = scalelcd ^ 1;
6542 /* Need to check crt2 type first for fstn/dstn */
6544 if(forcecrt2type)
6545 sisfb_search_crt2type(forcecrt2type);
6547 if(tvstandard)
6548 sisfb_search_tvstd(tvstandard);
6550 if(mode)
6551 sisfb_search_mode(mode, false);
6552 else if(vesa != -1)
6553 sisfb_search_vesamode(vesa, false);
6555 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6557 sisfb_forcecrt1 = forcecrt1;
6558 if(forcecrt1 == 1)
6559 sisfb_crt1off = 0;
6560 else if(forcecrt1 == 0)
6561 sisfb_crt1off = 1;
6563 if(noaccel == 1)
6564 sisfb_accel = 0;
6565 else if(noaccel == 0)
6566 sisfb_accel = 1;
6568 if(noypan == 1)
6569 sisfb_ypan = 0;
6570 else if(noypan == 0)
6571 sisfb_ypan = 1;
6573 if(nomax == 1)
6574 sisfb_max = 0;
6575 else if(nomax == 0)
6576 sisfb_max = 1;
6578 if(mem)
6579 sisfb_parm_mem = mem;
6581 if(userom != -1)
6582 sisfb_userom = userom;
6584 if(useoem != -1)
6585 sisfb_useoem = useoem;
6587 if(pdc != -1)
6588 sisfb_pdc = (pdc & 0x7f);
6590 if(pdc1 != -1)
6591 sisfb_pdca = (pdc1 & 0x1f);
6593 sisfb_nocrt2rate = nocrt2rate;
6595 if(specialtiming)
6596 sisfb_search_specialtiming(specialtiming);
6598 if((lvdshl >= 0) && (lvdshl <= 3))
6599 sisfb_lvdshl = lvdshl;
6601 sisfb_tvxposoffset = tvxposoffset;
6602 sisfb_tvyposoffset = tvyposoffset;
6604 #if !defined(__i386__) && !defined(__x86_64__)
6605 sisfb_resetcard = (resetcard) ? 1 : 0;
6606 if(videoram)
6607 sisfb_videoram = videoram;
6608 #endif
6610 return sisfb_init();
6613 static void __exit sisfb_remove_module(void)
6615 pci_unregister_driver(&sisfb_driver);
6616 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6619 module_init(sisfb_init_module);
6620 module_exit(sisfb_remove_module);
6622 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6623 MODULE_LICENSE("GPL");
6624 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6626 module_param(mem, int, 0);
6627 module_param(noaccel, int, 0);
6628 module_param(noypan, int, 0);
6629 module_param(nomax, int, 0);
6630 module_param(userom, int, 0);
6631 module_param(useoem, int, 0);
6632 module_param(mode, charp, 0);
6633 module_param(vesa, int, 0);
6634 module_param(rate, int, 0);
6635 module_param(forcecrt1, int, 0);
6636 module_param(forcecrt2type, charp, 0);
6637 module_param(scalelcd, int, 0);
6638 module_param(pdc, int, 0);
6639 module_param(pdc1, int, 0);
6640 module_param(specialtiming, charp, 0);
6641 module_param(lvdshl, int, 0);
6642 module_param(tvstandard, charp, 0);
6643 module_param(tvxposoffset, int, 0);
6644 module_param(tvyposoffset, int, 0);
6645 module_param(nocrt2rate, int, 0);
6646 #if !defined(__i386__) && !defined(__x86_64__)
6647 module_param(resetcard, int, 0);
6648 module_param(videoram, int, 0);
6649 #endif
6651 MODULE_PARM_DESC(mem,
6652 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6653 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6654 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6655 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6656 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6657 "The value is to be specified without 'KB'.\n");
6659 MODULE_PARM_DESC(noaccel,
6660 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6661 "(default: 0)\n");
6663 MODULE_PARM_DESC(noypan,
6664 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6665 "will be performed by redrawing the screen. (default: 0)\n");
6667 MODULE_PARM_DESC(nomax,
6668 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
6669 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6670 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6671 "enable the user to positively specify a virtual Y size of the screen using\n"
6672 "fbset. (default: 0)\n");
6674 MODULE_PARM_DESC(mode,
6675 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6676 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
6677 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6678 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6680 MODULE_PARM_DESC(vesa,
6681 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6682 "0x117 (default: 0x0103)\n");
6684 MODULE_PARM_DESC(rate,
6685 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6686 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6687 "will be ignored (default: 60)\n");
6689 MODULE_PARM_DESC(forcecrt1,
6690 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6691 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6692 "0=CRT1 OFF) (default: [autodetected])\n");
6694 MODULE_PARM_DESC(forcecrt2type,
6695 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6696 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6697 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6698 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6699 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6700 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6701 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6702 "depends on the very hardware in use. (default: [autodetected])\n");
6704 MODULE_PARM_DESC(scalelcd,
6705 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6706 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6707 "show black bars around the image, TMDS panels will probably do the scaling\n"
6708 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6710 MODULE_PARM_DESC(pdc,
6711 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
6712 "should detect this correctly in most cases; however, sometimes this is not\n"
6713 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
6714 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6715 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6716 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
6718 #ifdef CONFIG_FB_SIS_315
6719 MODULE_PARM_DESC(pdc1,
6720 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
6721 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6722 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6723 "implemented yet.\n");
6724 #endif
6726 MODULE_PARM_DESC(specialtiming,
6727 "\nPlease refer to documentation for more information on this option.\n");
6729 MODULE_PARM_DESC(lvdshl,
6730 "\nPlease refer to documentation for more information on this option.\n");
6732 MODULE_PARM_DESC(tvstandard,
6733 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6734 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6736 MODULE_PARM_DESC(tvxposoffset,
6737 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6738 "Default: 0\n");
6740 MODULE_PARM_DESC(tvyposoffset,
6741 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6742 "Default: 0\n");
6744 MODULE_PARM_DESC(nocrt2rate,
6745 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6746 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6748 #if !defined(__i386__) && !defined(__x86_64__)
6749 #ifdef CONFIG_FB_SIS_300
6750 MODULE_PARM_DESC(resetcard,
6751 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
6752 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6753 "currently). Default: 0\n");
6755 MODULE_PARM_DESC(videoram,
6756 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6757 "some non-x86 architectures where the memory auto detection fails. Only\n"
6758 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
6759 #endif
6760 #endif
6762 #endif /* /MODULE */
6764 /* _GPL only for new symbols. */
6765 EXPORT_SYMBOL(sis_malloc);
6766 EXPORT_SYMBOL(sis_free);
6767 EXPORT_SYMBOL_GPL(sis_malloc_new);
6768 EXPORT_SYMBOL_GPL(sis_free_new);