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