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