1 /*
2 * SiS 300/305/540/630(S)/730(S)
3 * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760
4 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
5 *
6 * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the named License,
11 * or any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
21 *
22 * Author: Thomas Winischhofer <thomas@winischhofer.net>
23 *
24 * Author of (practically wiped) code base:
25 * SiS (www.sis.com)
26 * Copyright (C) 1999 Silicon Integrated Systems, Inc.
27 *
28 * See http://www.winischhofer.net/ for more information and updates
29 *
30 * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
31 * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
32 *
33 */
34
35 #include <linux/config.h>
36 #include <linux/version.h>
37 #include <linux/module.h>
38 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
39 #include <linux/moduleparam.h>
40 #endif
41 #include <linux/kernel.h>
42 #include <linux/spinlock.h>
43 #include <linux/errno.h>
44 #include <linux/string.h>
45 #include <linux/mm.h>
46 #include <linux/tty.h>
47 #include <linux/slab.h>
48 #include <linux/delay.h>
49 #include <linux/fb.h>
50 #include <linux/console.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 #include <linux/vt_kern.h>
57 #include <linux/capability.h>
58 #include <linux/fs.h>
59 #include <linux/types.h>
60 #include <asm/uaccess.h>
61 #include <asm/io.h>
62 #ifdef CONFIG_MTRR
63 #include <asm/mtrr.h>
64 #endif
65
66 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
67 #include <video/fbcon.h>
68 #include <video/fbcon-cfb8.h>
69 #include <video/fbcon-cfb16.h>
70 #include <video/fbcon-cfb24.h>
71 #include <video/fbcon-cfb32.h>
72 #endif
73
74 #include "sis.h"
75 #include "sis_main.h"
76
77 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
78 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
79 #error "This version of sisfb requires at least 2.6.3"
80 #endif
81 #endif
82
83 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
84 #ifdef FBCON_HAS_CFB8
85 extern struct display_switch fbcon_sis8;
86 #endif
87 #ifdef FBCON_HAS_CFB16
88 extern struct display_switch fbcon_sis16;
89 #endif
90 #ifdef FBCON_HAS_CFB32
91 extern struct display_switch fbcon_sis32;
92 #endif
93 #endif
94
95 /* ------------------ Internal helper routines ----------------- */
96
97 static void __init
sisfb_setdefaultparms(void)98 sisfb_setdefaultparms(void)
99 {
100 sisfb_off = 0;
101 sisfb_parm_mem = 0;
102 sisfb_accel = -1;
103 sisfb_ypan = -1;
104 sisfb_max = -1;
105 sisfb_userom = -1;
106 sisfb_useoem = -1;
107 #ifdef MODULE
108 /* Module: "None" for 2.4, default mode for 2.5+ */
109 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
110 sisfb_mode_idx = -1;
111 #else
112 sisfb_mode_idx = MODE_INDEX_NONE;
113 #endif
114 #else
115 /* Static: Default mode */
116 sisfb_mode_idx = -1;
117 #endif
118 sisfb_parm_rate = -1;
119 sisfb_crt1off = 0;
120 sisfb_forcecrt1 = -1;
121 sisfb_crt2type = -1;
122 sisfb_crt2flags = 0;
123 sisfb_pdc = 0xff;
124 sisfb_pdca = 0xff;
125 sisfb_scalelcd = -1;
126 sisfb_specialtiming = CUT_NONE;
127 sisfb_lvdshl = -1;
128 sisfb_dstn = 0;
129 sisfb_fstn = 0;
130 sisfb_tvplug = -1;
131 sisfb_tvstd = -1;
132 sisfb_tvxposoffset = 0;
133 sisfb_tvyposoffset = 0;
134 sisfb_filter = -1;
135 sisfb_nocrt2rate = 0;
136 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
137 sisfb_inverse = 0;
138 sisfb_fontname[0] = 0;
139 #endif
140 #if !defined(__i386__) && !defined(__x86_64__)
141 sisfb_resetcard = 0;
142 sisfb_videoram = 0;
143 #endif
144 }
145
146 static void __init
sisfb_search_vesamode(unsigned int vesamode,BOOLEAN quiet)147 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
148 {
149 int i = 0, j = 0;
150
151 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
152
153 if(vesamode == 0) {
154 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
155 sisfb_mode_idx = MODE_INDEX_NONE;
156 #else
157 if(!quiet) {
158 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
159 }
160 sisfb_mode_idx = DEFAULT_MODE;
161 #endif
162 return;
163 }
164
165 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
166
167 while(sisbios_mode[i++].mode_no[0] != 0) {
168 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
169 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
170 if(sisfb_fstn) {
171 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
172 sisbios_mode[i-1].mode_no[1] == 0x56 ||
173 sisbios_mode[i-1].mode_no[1] == 0x53) continue;
174 } else {
175 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
176 sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
177 }
178 sisfb_mode_idx = i - 1;
179 j = 1;
180 break;
181 }
182 }
183 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
184 }
185
186 static void
sisfb_search_mode(char * name,BOOLEAN quiet)187 sisfb_search_mode(char *name, BOOLEAN quiet)
188 {
189 int i = 0;
190 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
191 char strbuf[16], strbuf1[20];
192 char *nameptr = name;
193
194 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
195
196 if(name == NULL) {
197 if(!quiet) {
198 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
199 }
200 sisfb_mode_idx = DEFAULT_MODE;
201 return;
202 }
203
204 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
205 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
206 if(!quiet) {
207 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
208 }
209 sisfb_mode_idx = DEFAULT_MODE;
210 return;
211 }
212 #endif
213 if(strlen(name) <= 19) {
214 strcpy(strbuf1, name);
215 for(i=0; i<strlen(strbuf1); i++) {
216 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
217 }
218
219 /* This does some fuzzy mode naming detection */
220 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
221 if((rate <= 32) || (depth > 32)) {
222 j = rate; rate = depth; depth = j;
223 }
224 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
225 nameptr = strbuf;
226 sisfb_parm_rate = rate;
227 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
228 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
229 nameptr = strbuf;
230 } else {
231 xres = 0;
232 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
233 sprintf(strbuf, "%ux%ux8", xres, yres);
234 nameptr = strbuf;
235 } else {
236 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
237 return;
238 }
239 }
240 }
241
242 i = 0; j = 0;
243 while(sisbios_mode[i].mode_no[0] != 0) {
244 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
245 if(sisfb_fstn) {
246 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
247 sisbios_mode[i-1].mode_no[1] == 0x56 ||
248 sisbios_mode[i-1].mode_no[1] == 0x53) continue;
249 } else {
250 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
251 sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
252 }
253 sisfb_mode_idx = i - 1;
254 j = 1;
255 break;
256 }
257 }
258 if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
259 }
260
261 #ifndef MODULE
262 static void __devinit
sisfb_get_vga_mode_from_kernel(void)263 sisfb_get_vga_mode_from_kernel(void)
264 {
265 #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
266 char mymode[32];
267 int mydepth = screen_info.lfb_depth;
268
269 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
270
271 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
272 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
273 (mydepth >= 8) && (mydepth <= 32) ) {
274
275 if(mydepth == 24) mydepth = 32;
276
277 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
278 screen_info.lfb_height,
279 mydepth);
280
281 printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode);
282
283 sisfb_search_mode(mymode, TRUE);
284 }
285 #endif
286 return;
287 }
288 #endif
289
290 static void __init
sisfb_search_crt2type(const char * name)291 sisfb_search_crt2type(const char *name)
292 {
293 int i = 0;
294
295 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
296
297 if(name == NULL) return;
298
299 while(sis_crt2type[i].type_no != -1) {
300 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
301 sisfb_crt2type = sis_crt2type[i].type_no;
302 sisfb_tvplug = sis_crt2type[i].tvplug_no;
303 sisfb_crt2flags = sis_crt2type[i].flags;
304 break;
305 }
306 i++;
307 }
308
309 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
310 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
311
312 if(sisfb_crt2type < 0) {
313 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
314 }
315 }
316
317 static void __init
sisfb_search_tvstd(const char * name)318 sisfb_search_tvstd(const char *name)
319 {
320 int i = 0;
321
322 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
323
324 if(name == NULL) return;
325
326 while(sis_tvtype[i].type_no != -1) {
327 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
328 sisfb_tvstd = sis_tvtype[i].type_no;
329 break;
330 }
331 i++;
332 }
333 }
334
335 static void __init
sisfb_search_specialtiming(const char * name)336 sisfb_search_specialtiming(const char *name)
337 {
338 int i = 0;
339 BOOLEAN found = FALSE;
340
341 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
342
343 if(name == NULL) return;
344
345 if(!strnicmp(name, "none", 4)) {
346 sisfb_specialtiming = CUT_FORCENONE;
347 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
348 } else {
349 while(mycustomttable[i].chipID != 0) {
350 if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {
351 sisfb_specialtiming = mycustomttable[i].SpecialID;
352 found = TRUE;
353 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
354 mycustomttable[i].vendorName, mycustomttable[i].cardName,
355 mycustomttable[i].optionName);
356 break;
357 }
358 i++;
359 }
360 if(!found) {
361 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
362 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
363 i = 0;
364 while(mycustomttable[i].chipID != 0) {
365 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
366 mycustomttable[i].optionName,
367 mycustomttable[i].vendorName,
368 mycustomttable[i].cardName);
369 i++;
370 }
371 }
372 }
373 }
374
375 static BOOLEAN __devinit
sisfb_interpret_edid(struct sisfb_monitor * monitor,u8 * buffer)376 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
377 {
378 int i, j, xres, yres, refresh, index;
379 u32 emodes;
380
381 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
382 buffer[2] != 0xff || buffer[3] != 0xff ||
383 buffer[4] != 0xff || buffer[5] != 0xff ||
384 buffer[6] != 0xff || buffer[7] != 0x00) {
385 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
386 return FALSE;
387 }
388
389 if(buffer[0x12] != 0x01) {
390 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
391 buffer[0x12]);
392 return FALSE;
393 }
394
395 monitor->feature = buffer[0x18];
396
397 if(!buffer[0x14] & 0x80) {
398 if(!(buffer[0x14] & 0x08)) {
399 printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n");
400 }
401 }
402
403 if(buffer[0x13] >= 0x01) {
404 /* EDID V1 rev 1 and 2: Search for monitor descriptor
405 * to extract ranges
406 */
407 j = 0x36;
408 for(i=0; i<4; i++) {
409 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
410 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
411 buffer[j + 4] == 0x00) {
412 monitor->hmin = buffer[j + 7];
413 monitor->hmax = buffer[j + 8];
414 monitor->vmin = buffer[j + 5];
415 monitor->vmax = buffer[j + 6];
416 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
417 monitor->datavalid = TRUE;
418 break;
419 }
420 j += 18;
421 }
422 }
423
424 if(!monitor->datavalid) {
425 /* Otherwise: Get a range from the list of supported
426 * Estabished Timings. This is not entirely accurate,
427 * because fixed frequency monitors are not supported
428 * that way.
429 */
430 monitor->hmin = 65535; monitor->hmax = 0;
431 monitor->vmin = 65535; monitor->vmax = 0;
432 monitor->dclockmax = 0;
433 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
434 for(i = 0; i < 13; i++) {
435 if(emodes & sisfb_ddcsmodes[i].mask) {
436 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
437 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
438 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
439 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
440 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
441 }
442 }
443 index = 0x26;
444 for(i = 0; i < 8; i++) {
445 xres = (buffer[index] + 31) * 8;
446 switch(buffer[index + 1] & 0xc0) {
447 case 0xc0: yres = (xres * 9) / 16; break;
448 case 0x80: yres = (xres * 4) / 5; break;
449 case 0x40: yres = (xres * 3) / 4; break;
450 default: yres = xres; break;
451 }
452 refresh = (buffer[index + 1] & 0x3f) + 60;
453 if((xres >= 640) && (yres >= 480)) {
454 for(j = 0; j < 8; j++) {
455 if((xres == sisfb_ddcfmodes[j].x) &&
456 (yres == sisfb_ddcfmodes[j].y) &&
457 (refresh == sisfb_ddcfmodes[j].v)) {
458 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
459 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
460 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
461 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
462 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
463 }
464 }
465 }
466 index += 2;
467 }
468 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
469 monitor->datavalid = TRUE;
470 }
471 }
472
473 return(monitor->datavalid);
474 }
475
476 static void __devinit
sisfb_handle_ddc(struct sis_video_info * ivideo,struct sisfb_monitor * monitor,int crtno)477 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
478 {
479 USHORT temp, i, realcrtno = crtno;
480 u8 buffer[256];
481
482 monitor->datavalid = FALSE;
483
484 if(crtno) {
485 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
486 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
487 else return;
488 }
489
490 if((ivideo->sisfb_crt1off) && (!crtno)) return;
491
492 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
493 realcrtno, 0, &buffer[0]);
494 if((!temp) || (temp == 0xffff)) {
495 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
496 return;
497 } else {
498 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
499 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
500 crtno + 1,
501 (temp & 0x1a) ? "" : "[none of the supported]",
502 (temp & 0x02) ? "2 " : "",
503 (temp & 0x08) ? "D&P" : "",
504 (temp & 0x10) ? "FPDI-2" : "");
505 if(temp & 0x02) {
506 i = 3; /* Number of retrys */
507 do {
508 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
509 realcrtno, 1, &buffer[0]);
510 } while((temp) && i--);
511 if(!temp) {
512 if(sisfb_interpret_edid(monitor, &buffer[0])) {
513 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
514 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
515 monitor->dclockmax / 1000);
516 } else {
517 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
518 }
519 } else {
520 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
521 }
522 } else {
523 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
524 }
525 }
526 }
527
528 static BOOLEAN
sisfb_verify_rate(struct sis_video_info * ivideo,struct sisfb_monitor * monitor,int mode_idx,int rate_idx,int rate)529 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
530 int mode_idx, int rate_idx, int rate)
531 {
532 int htotal, vtotal;
533 unsigned int dclock, hsync;
534
535 if(!monitor->datavalid) return TRUE;
536
537 if(mode_idx < 0) return FALSE;
538
539 if(rate < (monitor->vmin - 1)) return FALSE;
540 if(rate > (monitor->vmax + 1)) return FALSE;
541
542 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, &ivideo->sishw_ext,
543 sisbios_mode[mode_idx].mode_no[ivideo->mni],
544 &htotal, &vtotal, rate_idx)) {
545 dclock = (htotal * vtotal * rate) / 1000;
546 if(dclock > (monitor->dclockmax + 1000)) return FALSE;
547 hsync = dclock / htotal;
548 if(hsync < (monitor->hmin - 1)) return FALSE;
549 if(hsync > (monitor->hmax + 1)) return FALSE;
550 } else {
551 return FALSE;
552 }
553 return TRUE;
554 }
555
556 static int
sisfb_validate_mode(struct sis_video_info * ivideo,int myindex,u32 vbflags)557 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
558 {
559 u16 xres=0, yres, myres;
560
561 #ifdef CONFIG_FB_SIS_300
562 if(ivideo->sisvga_engine == SIS_300_VGA) {
563 if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1);
564 }
565 #endif
566 #ifdef CONFIG_FB_SIS_315
567 if(ivideo->sisvga_engine == SIS_315_VGA) {
568 if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1);
569 }
570 #endif
571
572 myres = sisbios_mode[myindex].yres;
573
574 switch(vbflags & VB_DISPTYPE_DISP2) {
575
576 case CRT2_LCD:
577
578 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
579
580 if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) {
581 if(sisbios_mode[myindex].xres > xres) return(-1);
582 if(myres > yres) return(-1);
583 }
584
585 if(vbflags & (VB_LVDS | VB_30xBDH)) {
586 if(sisbios_mode[myindex].xres == 320) {
587 if((myres == 240) || (myres == 480)) {
588 if(!ivideo->sisfb_fstn) {
589 if(sisbios_mode[myindex].mode_no[1] == 0x5a ||
590 sisbios_mode[myindex].mode_no[1] == 0x5b)
591 return(-1);
592 } else {
593 if(sisbios_mode[myindex].mode_no[1] == 0x50 ||
594 sisbios_mode[myindex].mode_no[1] == 0x56 ||
595 sisbios_mode[myindex].mode_no[1] == 0x53)
596 return(-1);
597 }
598 }
599 }
600 }
601
602 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
603 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
604 ivideo->SiS_Pr.SiS_CustomT, xres, yres) < 0x14) {
605 return(-1);
606 }
607 break;
608
609 case CRT2_TV:
610 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
611 sisbios_mode[myindex].yres, 0) < 0x14) {
612 return(-1);
613 }
614 break;
615
616 case CRT2_VGA:
617 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
618 sisbios_mode[myindex].yres, 0) < 0x14) {
619 return(-1);
620 }
621 break;
622 }
623
624 return(myindex);
625 }
626
627 static u8
sisfb_search_refresh_rate(struct sis_video_info * ivideo,unsigned int rate,int mode_idx)628 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
629 {
630 u16 xres, yres;
631 int i = 0;
632
633 xres = sisbios_mode[mode_idx].xres;
634 yres = sisbios_mode[mode_idx].yres;
635
636 ivideo->rate_idx = 0;
637 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
638 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
639 if(sisfb_vrate[i].refresh == rate) {
640 ivideo->rate_idx = sisfb_vrate[i].idx;
641 break;
642 } else if(sisfb_vrate[i].refresh > rate) {
643 if((sisfb_vrate[i].refresh - rate) <= 3) {
644 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
645 rate, sisfb_vrate[i].refresh);
646 ivideo->rate_idx = sisfb_vrate[i].idx;
647 ivideo->refresh_rate = sisfb_vrate[i].refresh;
648 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
649 && (sisfb_vrate[i].idx != 1)) {
650 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
651 rate, sisfb_vrate[i-1].refresh);
652 ivideo->rate_idx = sisfb_vrate[i-1].idx;
653 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
654 }
655 break;
656 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
657 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
658 rate, sisfb_vrate[i].refresh);
659 ivideo->rate_idx = sisfb_vrate[i].idx;
660 break;
661 }
662 }
663 i++;
664 }
665 if(ivideo->rate_idx > 0) {
666 return ivideo->rate_idx;
667 } else {
668 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
669 rate, xres, yres);
670 return 0;
671 }
672 }
673
674 static BOOLEAN
sisfb_bridgeisslave(struct sis_video_info * ivideo)675 sisfb_bridgeisslave(struct sis_video_info *ivideo)
676 {
677 unsigned char P1_00;
678
679 if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE;
680
681 inSISIDXREG(SISPART1,0x00,P1_00);
682 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
683 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
684 return TRUE;
685 } else {
686 return FALSE;
687 }
688 }
689
690 static BOOLEAN
sisfballowretracecrt1(struct sis_video_info * ivideo)691 sisfballowretracecrt1(struct sis_video_info *ivideo)
692 {
693 u8 temp;
694
695 inSISIDXREG(SISCR,0x17,temp);
696 if(!(temp & 0x80)) return FALSE;
697
698 inSISIDXREG(SISSR,0x1f,temp);
699 if(temp & 0xc0) return FALSE;
700
701 return TRUE;
702 }
703
704 static BOOLEAN
sisfbcheckvretracecrt1(struct sis_video_info * ivideo)705 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
706 {
707 if(!sisfballowretracecrt1(ivideo)) return FALSE;
708
709 if(inSISREG(SISINPSTAT) & 0x08) return TRUE;
710 else return FALSE;
711 }
712
713 static void
sisfbwaitretracecrt1(struct sis_video_info * ivideo)714 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
715 {
716 int watchdog;
717
718 if(!sisfballowretracecrt1(ivideo)) return;
719
720 watchdog = 65536;
721 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
722 watchdog = 65536;
723 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
724 }
725
726 static BOOLEAN
sisfbcheckvretracecrt2(struct sis_video_info * ivideo)727 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
728 {
729 unsigned char temp, reg;
730
731 switch(ivideo->sisvga_engine) {
732 case SIS_300_VGA: reg = 0x25; break;
733 case SIS_315_VGA: reg = 0x30; break;
734 default: return FALSE;
735 }
736
737 inSISIDXREG(SISPART1, reg, temp);
738 if(temp & 0x02) return FALSE;
739 else return TRUE;
740 }
741
742 static BOOLEAN
sisfb_CheckVBRetrace(struct sis_video_info * ivideo)743 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
744 {
745 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
746 if(sisfb_bridgeisslave(ivideo)) {
747 return(sisfbcheckvretracecrt1(ivideo));
748 } else {
749 return(sisfbcheckvretracecrt2(ivideo));
750 }
751 }
752 return(sisfbcheckvretracecrt1(ivideo));
753 }
754
755 static u32
sisfb_setupvbblankflags(struct sis_video_info * ivideo,u32 * vcount,u32 * hcount)756 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
757 {
758 u8 idx, reg1, reg2, reg3, reg4;
759 u32 ret = 0;
760
761 (*vcount) = (*hcount) = 0;
762
763 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
764 ret |= (FB_VBLANK_HAVE_VSYNC |
765 FB_VBLANK_HAVE_HBLANK |
766 FB_VBLANK_HAVE_VBLANK |
767 FB_VBLANK_HAVE_VCOUNT |
768 FB_VBLANK_HAVE_HCOUNT);
769 switch(ivideo->sisvga_engine) {
770 case SIS_300_VGA: idx = 0x25; break;
771 default:
772 case SIS_315_VGA: idx = 0x30; break;
773 }
774 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
775 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
776 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
777 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
778 if(!(reg1 & 0x01)) ret |= FB_VBLANK_VBLANKING;
779 if(!(reg1 & 0x02)) ret |= FB_VBLANK_VSYNCING;
780 if(!(reg4 & 0x80)) ret |= FB_VBLANK_HBLANKING;
781 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
782 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
783 } else if(sisfballowretracecrt1(ivideo)) {
784 ret |= (FB_VBLANK_HAVE_VSYNC |
785 FB_VBLANK_HAVE_VBLANK |
786 FB_VBLANK_HAVE_VCOUNT |
787 FB_VBLANK_HAVE_HCOUNT);
788 reg1 = inSISREG(SISINPSTAT);
789 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
790 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
791 inSISIDXREG(SISCR,0x20,reg1);
792 inSISIDXREG(SISCR,0x1b,reg1);
793 inSISIDXREG(SISCR,0x1c,reg2);
794 inSISIDXREG(SISCR,0x1d,reg3);
795 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
796 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
797 }
798 return ret;
799 }
800
801 static int
sisfb_myblank(struct sis_video_info * ivideo,int blank)802 sisfb_myblank(struct sis_video_info *ivideo, int blank)
803 {
804 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
805 BOOLEAN backlight = TRUE;
806
807 switch(blank) {
808 case 0: /* on */
809 sr01 = 0x00;
810 sr11 = 0x00;
811 sr1f = 0x00;
812 cr63 = 0x00;
813 p2_0 = 0x20;
814 p1_13 = 0x00;
815 backlight = TRUE;
816 break;
817 case 1: /* blank */
818 sr01 = 0x20;
819 sr11 = 0x00;
820 sr1f = 0x00;
821 cr63 = 0x00;
822 p2_0 = 0x20;
823 p1_13 = 0x00;
824 backlight = TRUE;
825 break;
826 case 2: /* no vsync */
827 sr01 = 0x20;
828 sr11 = 0x08;
829 sr1f = 0x80;
830 cr63 = 0x40;
831 p2_0 = 0x40;
832 p1_13 = 0x80;
833 backlight = FALSE;
834 break;
835 case 3: /* no hsync */
836 sr01 = 0x20;
837 sr11 = 0x08;
838 sr1f = 0x40;
839 cr63 = 0x40;
840 p2_0 = 0x80;
841 p1_13 = 0x40;
842 backlight = FALSE;
843 break;
844 case 4: /* off */
845 sr01 = 0x20;
846 sr11 = 0x08;
847 sr1f = 0xc0;
848 cr63 = 0x40;
849 p2_0 = 0xc0;
850 p1_13 = 0xc0;
851 backlight = FALSE;
852 break;
853 default:
854 return 1;
855 }
856
857 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
858
859 if( (!ivideo->sisfb_thismonitor.datavalid) ||
860 ((ivideo->sisfb_thismonitor.datavalid) &&
861 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
862
863 if(ivideo->sisvga_engine == SIS_315_VGA) {
864 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
865 }
866
867 if(!(sisfb_bridgeisslave(ivideo))) {
868 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
869 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
870 }
871 }
872
873 }
874
875 if(ivideo->currentvbflags & CRT2_LCD) {
876
877 if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
878 if(backlight) {
879 SiS_SiS30xBLOn(&ivideo->SiS_Pr, &ivideo->sishw_ext);
880 } else {
881 SiS_SiS30xBLOff(&ivideo->SiS_Pr, &ivideo->sishw_ext);
882 }
883 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
884 if(ivideo->vbflags & VB_CHRONTEL) {
885 if(backlight) {
886 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr,&ivideo->sishw_ext);
887 } else {
888 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
889 }
890 }
891 }
892
893 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
894 (ivideo->vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
895 ((ivideo->sisvga_engine == SIS_315_VGA) &&
896 ((ivideo->vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
897 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
898 }
899
900 if(ivideo->sisvga_engine == SIS_300_VGA) {
901 if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
902 (!(ivideo->vbflags & VB_30xBDH))) {
903 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
904 }
905 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
906 if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
907 (!(ivideo->vbflags & VB_30xBDH))) {
908 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
909 }
910 }
911
912 } else if(ivideo->currentvbflags & CRT2_VGA) {
913
914 if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) {
915 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
916 }
917
918 }
919
920 return(0);
921 }
922
923 /* ----------- FBDev related routines for all series ----------- */
924
925 static int
sisfb_get_cmap_len(const struct fb_var_screeninfo * var)926 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
927 {
928 return (var->bits_per_pixel == 8) ? 256 : 16;
929 }
930
931 static void
sisfb_set_vparms(struct sis_video_info * ivideo)932 sisfb_set_vparms(struct sis_video_info *ivideo)
933 {
934 switch(ivideo->video_bpp) {
935 case 8:
936 ivideo->DstColor = 0x0000;
937 ivideo->SiS310_AccelDepth = 0x00000000;
938 ivideo->video_cmap_len = 256;
939 break;
940 case 16:
941 ivideo->DstColor = 0x8000;
942 ivideo->SiS310_AccelDepth = 0x00010000;
943 ivideo->video_cmap_len = 16;
944 break;
945 case 32:
946 ivideo->DstColor = 0xC000;
947 ivideo->SiS310_AccelDepth = 0x00020000;
948 ivideo->video_cmap_len = 16;
949 break;
950 default:
951 ivideo->video_cmap_len = 16;
952 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
953 ivideo->accel = 0;
954 break;
955 }
956 }
957
958 static void
sisfb_bpp_to_var(struct sis_video_info * ivideo,struct fb_var_screeninfo * var)959 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
960 {
961 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
962
963 switch(var->bits_per_pixel) {
964 case 8:
965 var->red.offset = var->green.offset = var->blue.offset = 0;
966 var->red.length = var->green.length = var->blue.length = 6;
967 break;
968 case 16:
969 var->red.offset = 11;
970 var->red.length = 5;
971 var->green.offset = 5;
972 var->green.length = 6;
973 var->blue.offset = 0;
974 var->blue.length = 5;
975 var->transp.offset = 0;
976 var->transp.length = 0;
977 break;
978 case 32:
979 var->red.offset = 16;
980 var->red.length = 8;
981 var->green.offset = 8;
982 var->green.length = 8;
983 var->blue.offset = 0;
984 var->blue.length = 8;
985 var->transp.offset = 24;
986 var->transp.length = 8;
987 break;
988 }
989 }
990
991 static int
sisfb_do_set_var(struct fb_var_screeninfo * var,int isactive,struct fb_info * info)992 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
993 struct fb_info *info)
994 {
995 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
996 unsigned int htotal = 0, vtotal = 0;
997 unsigned int drate = 0, hrate = 0;
998 int found_mode = 0;
999 int old_mode;
1000 u32 pixclock;
1001
1002 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1003
1004 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1005
1006 pixclock = var->pixclock;
1007
1008 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1009 vtotal += var->yres;
1010 vtotal <<= 1;
1011 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1012 vtotal += var->yres;
1013 vtotal <<= 2;
1014 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1015 vtotal += var->yres;
1016 vtotal <<= 1;
1017 } else vtotal += var->yres;
1018
1019 if(!(htotal) || !(vtotal)) {
1020 DPRINTK("sisfb: Invalid 'var' information\n");
1021 return -EINVAL;
1022 }
1023
1024 if(pixclock && htotal && vtotal) {
1025 drate = 1000000000 / pixclock;
1026 hrate = (drate * 1000) / htotal;
1027 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1028 } else {
1029 ivideo->refresh_rate = 60;
1030 }
1031
1032 old_mode = ivideo->sisfb_mode_idx;
1033 ivideo->sisfb_mode_idx = 0;
1034
1035 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1036 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1037 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1038 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1039 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1040 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1041 found_mode = 1;
1042 break;
1043 }
1044 ivideo->sisfb_mode_idx++;
1045 }
1046
1047 if(found_mode) {
1048 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1049 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1050 } else {
1051 ivideo->sisfb_mode_idx = -1;
1052 }
1053
1054 if(ivideo->sisfb_mode_idx < 0) {
1055 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1056 var->yres, var->bits_per_pixel);
1057 ivideo->sisfb_mode_idx = old_mode;
1058 return -EINVAL;
1059 }
1060
1061 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1062 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1063 ivideo->refresh_rate = 60;
1064 }
1065
1066 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1067 if(ivideo->sisfb_thismonitor.datavalid) {
1068 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
1069 ivideo->rate_idx, ivideo->refresh_rate)) {
1070 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1071 }
1072 }
1073 #endif
1074
1075 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1076 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1077 #else
1078 if(isactive) {
1079 #endif
1080 sisfb_pre_setmode(ivideo);
1081
1082 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
1083 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1084 return -EINVAL;
1085 }
1086
1087 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1088
1089 sisfb_post_setmode(ivideo);
1090
1091 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1092 ivideo->video_vwidth = ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1093 ivideo->video_vheight = ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1094 ivideo->video_linelength = ivideo->video_width * (ivideo->video_bpp >> 3);
1095 ivideo->org_x = ivideo->org_y = 0;
1096 ivideo->accel = 0;
1097 if(ivideo->sisfb_accel) {
1098 ivideo->accel = (var->accel_flags & FB_ACCELF_TEXT) ? -1 : 0;
1099 }
1100
1101 sisfb_set_vparms(ivideo);
1102
1103 ivideo->current_width = ivideo->video_width;
1104 ivideo->current_height = ivideo->video_height;
1105 ivideo->current_bpp = ivideo->video_bpp;
1106 ivideo->current_htotal = htotal;
1107 ivideo->current_vtotal = vtotal;
1108 ivideo->current_pixclock = var->pixclock;
1109 ivideo->current_refresh_rate = ivideo->refresh_rate;
1110 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1111 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1112 #endif
1113
1114 }
1115
1116 return 0;
1117 }
1118
1119 static int
1120 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1121 {
1122 unsigned int base;
1123
1124 if(var->xoffset > (var->xres_virtual - var->xres)) {
1125 return -EINVAL;
1126 }
1127 if(var->yoffset > (var->yres_virtual - var->yres)) {
1128 return -EINVAL;
1129 }
1130
1131 base = var->yoffset * var->xres_virtual + var->xoffset;
1132
1133 /* calculate base bpp dep. */
1134 switch(var->bits_per_pixel) {
1135 case 32:
1136 break;
1137 case 16:
1138 base >>= 1;
1139 break;
1140 case 8:
1141 default:
1142 base >>= 2;
1143 break;
1144 }
1145
1146 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1147
1148 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1149 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1150 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1151 if(ivideo->sisvga_engine == SIS_315_VGA) {
1152 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1153 }
1154 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1155 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1156 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1157 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1158 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1159 if(ivideo->sisvga_engine == SIS_315_VGA) {
1160 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1161 }
1162 }
1163 return 0;
1164 }
1165
1166 /* ------------ FBDev related routines for 2.4 series ----------- */
1167
1168 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1169
1170 static void
1171 sisfb_crtc_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1172 {
1173 u16 VRE, VBE, VRS, VBS, VDE, VT;
1174 u16 HRE, HBE, HRS, HBS, HDE, HT;
1175 u8 sr_data, cr_data, cr_data2, cr_data3, mr_data;
1176 int A, B, C, D, E, F, temp;
1177 unsigned int hrate, drate, maxyres;
1178
1179 inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
1180
1181 if(sr_data & SIS_INTERLACED_MODE)
1182 var->vmode = FB_VMODE_INTERLACED;
1183 else
1184 var->vmode = FB_VMODE_NONINTERLACED;
1185
1186 switch((sr_data & 0x1C) >> 2) {
1187 case SIS_8BPP_COLOR_MODE:
1188 var->bits_per_pixel = 8;
1189 break;
1190 case SIS_16BPP_COLOR_MODE:
1191 var->bits_per_pixel = 16;
1192 break;
1193 case SIS_32BPP_COLOR_MODE:
1194 var->bits_per_pixel = 32;
1195 break;
1196 }
1197
1198 sisfb_bpp_to_var(ivideo, var);
1199
1200 inSISIDXREG(SISSR, 0x0A, sr_data);
1201 inSISIDXREG(SISCR, 0x06, cr_data);
1202 inSISIDXREG(SISCR, 0x07, cr_data2);
1203
1204 VT = (cr_data & 0xFF) |
1205 ((u16) (cr_data2 & 0x01) << 8) |
1206 ((u16) (cr_data2 & 0x20) << 4) |
1207 ((u16) (sr_data & 0x01) << 10);
1208 A = VT + 2;
1209
1210 inSISIDXREG(SISCR, 0x12, cr_data);
1211
1212 VDE = (cr_data & 0xff) |
1213 ((u16) (cr_data2 & 0x02) << 7) |
1214 ((u16) (cr_data2 & 0x40) << 3) |
1215 ((u16) (sr_data & 0x02) << 9);
1216 E = VDE + 1;
1217
1218 inSISIDXREG(SISCR, 0x10, cr_data);
1219
1220 VRS = (cr_data & 0xff) |
1221 ((u16) (cr_data2 & 0x04) << 6) |
1222 ((u16) (cr_data2 & 0x80) << 2) |
1223 ((u16) (sr_data & 0x08) << 7);
1224 F = VRS + 1 - E;
1225
1226 inSISIDXREG(SISCR, 0x15, cr_data);
1227 inSISIDXREG(SISCR, 0x09, cr_data3);
1228
1229 if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE;
1230
1231 VBS = (cr_data & 0xff) |
1232 ((u16) (cr_data2 & 0x08) << 5) |
1233 ((u16) (cr_data3 & 0x20) << 4) |
1234 ((u16) (sr_data & 0x04) << 8);
1235
1236 inSISIDXREG(SISCR, 0x16, cr_data);
1237
1238 VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
1239 temp = VBE - ((E - 1) & 511);
1240 B = (temp > 0) ? temp : (temp + 512);
1241
1242 inSISIDXREG(SISCR, 0x11, cr_data);
1243
1244 VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
1245 temp = VRE - ((E + F - 1) & 31);
1246 C = (temp > 0) ? temp : (temp + 32);
1247
1248 D = B - F - C;
1249
1250 var->yres = E;
1251 var->upper_margin = D;
1252 var->lower_margin = F;
1253 var->vsync_len = C;
1254
1255 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1256 var->yres <<= 1;
1257 var->upper_margin <<= 1;
1258 var->lower_margin <<= 1;
1259 var->vsync_len <<= 1;
1260 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1261 var->yres >>= 1;
1262 var->upper_margin >>= 1;
1263 var->lower_margin >>= 1;
1264 var->vsync_len >>= 1;
1265 }
1266
1267 inSISIDXREG(SISSR, 0x0b, sr_data);
1268 inSISIDXREG(SISCR, 0x00, cr_data);
1269
1270 HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
1271 A = HT + 5;
1272
1273 inSISIDXREG(SISCR, 0x01, cr_data);
1274
1275 HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
1276 E = HDE + 1;
1277
1278 inSISIDXREG(SISCR, 0x04, cr_data);
1279
1280 HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
1281 F = HRS - E - 3;
1282
1283 inSISIDXREG(SISCR, 0x02, cr_data);
1284
1285 HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
1286
1287 inSISIDXREG(SISSR, 0x0c, sr_data);
1288 inSISIDXREG(SISCR, 0x03, cr_data);
1289 inSISIDXREG(SISCR, 0x05, cr_data2);
1290
1291 HBE = (cr_data & 0x1f) |
1292 ((u16) (cr_data2 & 0x80) >> 2) |
1293 ((u16) (sr_data & 0x03) << 6);
1294 HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
1295
1296 temp = HBE - ((E - 1) & 255);
1297 B = (temp > 0) ? temp : (temp + 256);
1298
1299 temp = HRE - ((E + F + 3) & 63);
1300 C = (temp > 0) ? temp : (temp + 64);
1301
1302 D = B - F - C;
1303
1304 var->xres = var->xres_virtual = E * 8;
1305
1306 if((var->xres == 320) &&
1307 (var->yres == 200 || var->yres == 240)) {
1308 /* Terrible hack, but the correct CRTC data for
1309 * these modes only produces a black screen...
1310 */
1311 var->left_margin = (400 - 376);
1312 var->right_margin = (328 - 320);
1313 var->hsync_len = (376 - 328);
1314 } else {
1315 var->left_margin = D * 8;
1316 var->right_margin = F * 8;
1317 var->hsync_len = C * 8;
1318 }
1319 var->activate = FB_ACTIVATE_NOW;
1320
1321 var->sync = 0;
1322
1323 mr_data = inSISREG(SISMISCR);
1324 if(mr_data & 0x80)
1325 var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
1326 else
1327 var->sync |= FB_SYNC_VERT_HIGH_ACT;
1328
1329 if(mr_data & 0x40)
1330 var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
1331 else
1332 var->sync |= FB_SYNC_HOR_HIGH_ACT;
1333
1334 VT += 2;
1335 VT <<= 1;
1336 HT = (HT + 5) * 8;
1337
1338 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1339 VT <<= 1;
1340 }
1341 hrate = ivideo->refresh_rate * VT / 2;
1342 drate = (hrate * HT) / 1000;
1343 var->pixclock = (u32) (1000000000 / drate);
1344
1345 if(ivideo->sisfb_ypan) {
1346 maxyres = ivideo->heapstart / (var->xres * (var->bits_per_pixel >> 3));
1347 if(maxyres > 32767) maxyres = 32767;
1348 if(ivideo->sisfb_max) {
1349 var->yres_virtual = maxyres;
1350 } else {
1351 if(var->yres_virtual > maxyres) {
1352 var->yres_virtual = maxyres;
1353 }
1354 }
1355 if(var->yres_virtual <= var->yres) {
1356 var->yres_virtual = var->yres;
1357 }
1358 } else {
1359 var->yres_virtual = var->yres;
1360 }
1361
1362 }
1363
1364 static int
1365 sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
1366 unsigned *transp, struct fb_info *info)
1367 {
1368 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1369
1370 if(regno >= ivideo->video_cmap_len) return 1;
1371
1372 *red = ivideo->sis_palette[regno].red;
1373 *green = ivideo->sis_palette[regno].green;
1374 *blue = ivideo->sis_palette[regno].blue;
1375 *transp = 0;
1376
1377 return 0;
1378 }
1379
1380 static int
1381 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1382 unsigned transp, struct fb_info *info)
1383 {
1384 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1385
1386 if(regno >= ivideo->video_cmap_len) return 1;
1387
1388 ivideo->sis_palette[regno].red = red;
1389 ivideo->sis_palette[regno].green = green;
1390 ivideo->sis_palette[regno].blue = blue;
1391
1392 switch(ivideo->video_bpp) {
1393 #ifdef FBCON_HAS_CFB8
1394 case 8:
1395 outSISREG(SISDACA, regno);
1396 outSISREG(SISDACD, (red >> 10));
1397 outSISREG(SISDACD, (green >> 10));
1398 outSISREG(SISDACD, (blue >> 10));
1399 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1400 outSISREG(SISDAC2A, regno);
1401 outSISREG(SISDAC2D, (red >> 8));
1402 outSISREG(SISDAC2D, (green >> 8));
1403 outSISREG(SISDAC2D, (blue >> 8));
1404 }
1405 break;
1406 #endif
1407 #ifdef FBCON_HAS_CFB16
1408 case 16:
1409 ivideo->sis_fbcon_cmap.cfb16[regno] =
1410 ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1411 break;
1412 #endif
1413 #ifdef FBCON_HAS_CFB32
1414 case 32:
1415 red >>= 8;
1416 green >>= 8;
1417 blue >>= 8;
1418 ivideo->sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
1419 break;
1420 #endif
1421 }
1422
1423 return 0;
1424 }
1425
1426 static void
1427 sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info)
1428 {
1429 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1430 struct display *display;
1431 struct display_switch *sw;
1432 struct fb_fix_screeninfo fix;
1433 long flags;
1434
1435 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1436
1437 sisfb_get_fix(&fix, con, info);
1438
1439 display->var = *var;
1440 display->screen_base = (char *)ivideo->video_vbase;
1441 display->visual = fix.visual;
1442 display->type = fix.type;
1443 display->type_aux = fix.type_aux;
1444 display->ypanstep = fix.ypanstep;
1445 display->ywrapstep = fix.ywrapstep;
1446 display->line_length = fix.line_length;
1447 display->can_soft_blank = 1;
1448 display->inverse = ivideo->sisfb_inverse;
1449 display->next_line = fix.line_length;
1450
1451 save_flags(flags);
1452
1453 switch(ivideo->video_bpp) {
1454 #ifdef FBCON_HAS_CFB8
1455 case 8:
1456 sw = ivideo->accel ? &fbcon_sis8 : &fbcon_cfb8;
1457 break;
1458 #endif
1459 #ifdef FBCON_HAS_CFB16
1460 case 16:
1461 sw = ivideo->accel ? &fbcon_sis16 : &fbcon_cfb16;
1462 display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb16;
1463 break;
1464 #endif
1465 #ifdef FBCON_HAS_CFB32
1466 case 32:
1467 sw = ivideo->accel ? &fbcon_sis32 : &fbcon_cfb32;
1468 display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb32;
1469 break;
1470 #endif
1471 default:
1472 sw = &fbcon_dummy;
1473 break;
1474 }
1475 memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw));
1476 display->dispsw = &ivideo->sisfb_sw;
1477
1478 restore_flags(flags);
1479
1480 if(ivideo->sisfb_ypan) {
1481 /* display->scrollmode = 0; */
1482 } else {
1483 display->scrollmode = SCROLL_YREDRAW;
1484 ivideo->sisfb_sw.bmove = fbcon_redraw_bmove;
1485 }
1486 }
1487
1488 static void
1489 sisfb_do_install_cmap(int con, struct fb_info *info)
1490 {
1491 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1492
1493 if(con != ivideo->currcon) return;
1494
1495 if(fb_display[con].cmap.len) {
1496 fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
1497 } else {
1498 int size = sisfb_get_cmap_len(&fb_display[con].var);
1499 fb_set_cmap(fb_default_cmap(size), 1, sisfb_setcolreg, info);
1500 }
1501 }
1502
1503 static int
1504 sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1505 {
1506 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1507
1508 if(con == -1) {
1509 memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo));
1510 } else {
1511 *var = fb_display[con].var;
1512 }
1513
1514 if(ivideo->sisfb_fstn) {
1515 if(var->xres == 320 && var->yres == 480) var->yres = 240;
1516 }
1517
1518 return 0;
1519 }
1520
1521 static int
1522 sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1523 {
1524 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1525 unsigned int cols, rows;
1526 int err;
1527
1528 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1529
1530 if(sisfb_do_set_var(var, con == ivideo->currcon, info)) {
1531 sisfb_crtc_to_var(ivideo, var);
1532 return -EINVAL;
1533 }
1534
1535 sisfb_crtc_to_var(ivideo, var);
1536
1537 sisfb_set_disp(con, var, info);
1538
1539 if(info->changevar) {
1540 (*info->changevar)(con);
1541 }
1542
1543 if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) {
1544 return err;
1545 }
1546
1547 sisfb_do_install_cmap(con, info);
1548
1549 cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
1550 rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
1551
1552 #if 0 /* Why was this called here? */
1553 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1554 #endif
1555 return 0;
1556 }
1557
1558 static int
1559 sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1560 {
1561 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1562 struct display *display;
1563
1564 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1565
1566 if(con == ivideo->currcon) {
1567
1568 return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
1569
1570 } else if(display->cmap.len) {
1571
1572 fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2);
1573
1574 } else {
1575
1576 int size = sisfb_get_cmap_len(&display->var);
1577 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
1578
1579 }
1580
1581 return 0;
1582 }
1583
1584 static int
1585 sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1586 {
1587 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1588 struct display *display;
1589 int err, size;
1590
1591 display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1592
1593 size = sisfb_get_cmap_len(&display->var);
1594 if(display->cmap.len != size) {
1595 err = fb_alloc_cmap(&display->cmap, size, 0);
1596 if(err) return err;
1597 }
1598
1599 if(con == ivideo->currcon) {
1600 return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
1601 } else {
1602 fb_copy_cmap(cmap, &display->cmap, kspc ? 0 : 1);
1603 }
1604
1605 return 0;
1606 }
1607
1608 static int
1609 sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info)
1610 {
1611 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1612 int err;
1613
1614 if(var->vmode & FB_VMODE_YWRAP) {
1615 if((var->yoffset < 0) ||
1616 (var->yoffset >= fb_display[con].var.yres_virtual) ||
1617 (var->xoffset)) {
1618 return -EINVAL;
1619 }
1620 } else {
1621 if((var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual) ||
1622 (var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)) {
1623 return -EINVAL;
1624 }
1625 }
1626
1627 if(con == ivideo->currcon) {
1628 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
1629 }
1630
1631 fb_display[con].var.xoffset = var->xoffset;
1632 fb_display[con].var.yoffset = var->yoffset;
1633 if(var->vmode & FB_VMODE_YWRAP) {
1634 fb_display[con].var.vmode |= FB_VMODE_YWRAP;
1635 } else {
1636 fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
1637 }
1638
1639 return 0;
1640 }
1641
1642 static int
1643 sisfb_update_var(int con, struct fb_info *info)
1644 {
1645 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1646
1647 return(sisfb_pan_var(ivideo, &fb_display[con].var));
1648 }
1649
1650 static int
1651 sisfb_switch(int con, struct fb_info *info)
1652 {
1653 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1654 int cols, rows;
1655
1656 if(fb_display[ivideo->currcon].cmap.len) {
1657 fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info);
1658 }
1659
1660 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1661
1662 if(!memcmp(&fb_display[con].var, &fb_display[ivideo->currcon].var,
1663 sizeof(struct fb_var_screeninfo))) {
1664 ivideo->currcon = con;
1665 return 1;
1666 }
1667
1668 ivideo->currcon = con;
1669
1670 sisfb_do_set_var(&fb_display[con].var, 1, info);
1671
1672 sisfb_set_disp(con, &fb_display[con].var, info);
1673
1674 sisfb_do_install_cmap(con, info);
1675
1676 cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
1677 rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
1678 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1679
1680 sisfb_update_var(con, info);
1681
1682 return 1;
1683 }
1684
1685 static void
1686 sisfb_blank(int blank, struct fb_info *info)
1687 {
1688 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1689
1690 sisfb_myblank(ivideo, blank);
1691 }
1692 #endif
1693
1694 /* ------------ FBDev related routines for 2.6 series ----------- */
1695
1696 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1697
1698 static int
1699 sisfb_open(struct fb_info *info, int user)
1700 {
1701 return 0;
1702 }
1703
1704 static int
1705 sisfb_release(struct fb_info *info, int user)
1706 {
1707 return 0;
1708 }
1709
1710 static int
1711 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1712 unsigned transp, struct fb_info *info)
1713 {
1714 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1715
1716 if(regno >= sisfb_get_cmap_len(&info->var)) return 1;
1717
1718 switch(info->var.bits_per_pixel) {
1719 case 8:
1720 outSISREG(SISDACA, regno);
1721 outSISREG(SISDACD, (red >> 10));
1722 outSISREG(SISDACD, (green >> 10));
1723 outSISREG(SISDACD, (blue >> 10));
1724 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1725 outSISREG(SISDAC2A, regno);
1726 outSISREG(SISDAC2D, (red >> 8));
1727 outSISREG(SISDAC2D, (green >> 8));
1728 outSISREG(SISDAC2D, (blue >> 8));
1729 }
1730 break;
1731 case 16:
1732 ((u32 *)(info->pseudo_palette))[regno] =
1733 ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1734 break;
1735 case 32:
1736 red >>= 8;
1737 green >>= 8;
1738 blue >>= 8;
1739 ((u32 *)(info->pseudo_palette))[regno] =
1740 (red << 16) | (green << 8) | (blue);
1741 break;
1742 }
1743 return 0;
1744 }
1745
1746 static int
1747 sisfb_set_par(struct fb_info *info)
1748 {
1749 int err;
1750
1751 if((err = sisfb_do_set_var(&info->var, 1, info))) {
1752 return err;
1753 }
1754
1755 sisfb_get_fix(&info->fix, info->currcon, info);
1756
1757 return 0;
1758 }
1759
1760 static int
1761 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1762 {
1763 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1764 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1765 unsigned int drate = 0, hrate = 0, maxyres;
1766 int found_mode = 0;
1767 int refresh_rate, search_idx;
1768 BOOLEAN recalc_clock = FALSE;
1769 u32 pixclock;
1770
1771 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1772
1773 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1774
1775 pixclock = var->pixclock;
1776
1777 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1778 vtotal += var->yres;
1779 vtotal <<= 1;
1780 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1781 vtotal += var->yres;
1782 vtotal <<= 2;
1783 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1784 vtotal += var->yres;
1785 vtotal <<= 1;
1786 } else vtotal += var->yres;
1787
1788 if(!(htotal) || !(vtotal)) {
1789 SISFAIL("sisfb: no valid timing data");
1790 }
1791
1792 search_idx = 0;
1793 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1794 (sisbios_mode[search_idx].xres <= var->xres) ) {
1795 if( (sisbios_mode[search_idx].xres == var->xres) &&
1796 (sisbios_mode[search_idx].yres == var->yres) &&
1797 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1798 if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) {
1799 found_mode = 1;
1800 break;
1801 }
1802 }
1803 search_idx++;
1804 }
1805
1806 if(!found_mode) {
1807 search_idx = 0;
1808 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1809 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1810 (var->yres <= sisbios_mode[search_idx].yres) &&
1811 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1812 if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) {
1813 found_mode = 1;
1814 break;
1815 }
1816 }
1817 search_idx++;
1818 }
1819 if(found_mode) {
1820 printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1821 var->xres, var->yres, var->bits_per_pixel,
1822 sisbios_mode[search_idx].xres,
1823 sisbios_mode[search_idx].yres,
1824 var->bits_per_pixel);
1825 var->xres = sisbios_mode[search_idx].xres;
1826 var->yres = sisbios_mode[search_idx].yres;
1827
1828
1829 } else {
1830 printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n",
1831 var->xres, var->yres, var->bits_per_pixel);
1832 return -EINVAL;
1833 }
1834 }
1835
1836 if( ((ivideo->vbflags & VB_LVDS) || /* Slave modes on LVDS and 301B-DH */
1837 ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1838 (var->bits_per_pixel == 8) ) {
1839 refresh_rate = 60;
1840 recalc_clock = TRUE;
1841 } else if( (ivideo->current_htotal == htotal) && /* x=x & y=y & c=c -> assume depth change */
1842 (ivideo->current_vtotal == vtotal) &&
1843 (ivideo->current_pixclock == pixclock) ) {
1844 drate = 1000000000 / pixclock;
1845 hrate = (drate * 1000) / htotal;
1846 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1847 } else if( ( (ivideo->current_htotal != htotal) || /* x!=x | y!=y & c=c -> invalid pixclock */
1848 (ivideo->current_vtotal != vtotal) ) &&
1849 (ivideo->current_pixclock == var->pixclock) ) {
1850 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1851 refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1852 } else if(ivideo->sisfb_parm_rate != -1) {
1853 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1854 refresh_rate = ivideo->sisfb_parm_rate;
1855 } else {
1856 refresh_rate = 60;
1857 }
1858 recalc_clock = TRUE;
1859 } else if((pixclock) && (htotal) && (vtotal)) {
1860 drate = 1000000000 / pixclock;
1861 hrate = (drate * 1000) / htotal;
1862 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1863 } else if(ivideo->current_refresh_rate) {
1864 refresh_rate = ivideo->current_refresh_rate;
1865 recalc_clock = TRUE;
1866 } else {
1867 refresh_rate = 60;
1868 recalc_clock = TRUE;
1869 }
1870
1871 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1872
1873 /* Eventually recalculate timing and clock */
1874 if(recalc_clock) {
1875 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1876 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1877 &ivideo->sishw_ext,
1878 sisbios_mode[search_idx].mode_no[ivideo->mni],
1879 myrateindex));
1880 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
1881 sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex, var);
1882 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1883 var->pixclock <<= 1;
1884 }
1885 }
1886
1887 if(ivideo->sisfb_thismonitor.datavalid) {
1888 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1889 myrateindex, refresh_rate)) {
1890 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1891 }
1892 }
1893
1894 /* Adapt RGB settings */
1895 sisfb_bpp_to_var(ivideo, var);
1896
1897 /* Sanity check for offsets */
1898 if(var->xoffset < 0) var->xoffset = 0;
1899 if(var->yoffset < 0) var->yoffset = 0;
1900
1901 /* Horiz-panning not supported */
1902 if(var->xres != var->xres_virtual) {
1903 var->xres_virtual = var->xres;
1904 }
1905
1906 if(ivideo->sisfb_ypan) {
1907 maxyres = ivideo->heapstart / (var->xres * (var->bits_per_pixel >> 3));
1908 if(maxyres > 32767) maxyres = 32767;
1909 if(ivideo->sisfb_max) {
1910 var->yres_virtual = maxyres;
1911 } else {
1912 if(var->yres_virtual > maxyres) {
1913 var->yres_virtual = maxyres;
1914 }
1915 }
1916 if(var->yres_virtual <= var->yres) {
1917 var->yres_virtual = var->yres;
1918 }
1919 } else {
1920 if(var->yres != var->yres_virtual) {
1921 var->yres_virtual = var->yres;
1922 }
1923 var->xoffset = 0;
1924 var->yoffset = 0;
1925 }
1926
1927 /* Truncate offsets to maximum if too high */
1928 if(var->xoffset > var->xres_virtual - var->xres) {
1929 var->xoffset = var->xres_virtual - var->xres - 1;
1930 }
1931
1932 if(var->yoffset > var->yres_virtual - var->yres) {
1933 var->yoffset = var->yres_virtual - var->yres - 1;
1934 }
1935
1936 /* Set everything else to 0 */
1937 var->red.msb_right =
1938 var->green.msb_right =
1939 var->blue.msb_right =
1940 var->transp.offset =
1941 var->transp.length =
1942 var->transp.msb_right = 0;
1943
1944 return 0;
1945 }
1946
1947 static int
1948 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1949 {
1950 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1951 int err;
1952
1953 if(var->xoffset > (var->xres_virtual - var->xres)) {
1954 return -EINVAL;
1955 }
1956 if(var->yoffset > (var->yres_virtual - var->yres)) {
1957 return -EINVAL;
1958 }
1959
1960 if(var->vmode & FB_VMODE_YWRAP) {
1961 if((var->yoffset < 0) ||
1962 (var->yoffset >= info->var.yres_virtual) ||
1963 (var->xoffset)) {
1964 return -EINVAL;
1965 }
1966 } else {
1967 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
1968 var->yoffset + info->var.yres > info->var.yres_virtual) {
1969 return -EINVAL;
1970 }
1971 }
1972
1973 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
1974
1975 info->var.xoffset = var->xoffset;
1976 info->var.yoffset = var->yoffset;
1977 if(var->vmode & FB_VMODE_YWRAP) {
1978 info->var.vmode |= FB_VMODE_YWRAP;
1979 } else {
1980 info->var.vmode &= ~FB_VMODE_YWRAP;
1981 }
1982
1983 return 0;
1984 }
1985
1986 static int
1987 sisfb_blank(int blank, struct fb_info *info)
1988 {
1989 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1990
1991 return(sisfb_myblank(ivideo, blank));
1992 }
1993
1994 #endif
1995
1996 /* ----------- FBDev related routines for all series ---------- */
1997
1998 static int
1999 sisfb_ioctl(struct inode *inode, struct file *file,
2000 unsigned int cmd, unsigned long arg,
2001 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2002 int con,
2003 #endif
2004 struct fb_info *info)
2005 {
2006 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2007 struct sis_memreq sismemreq;
2008 struct fb_vblank sisvbblank;
2009 sisfb_info x;
2010 u32 gpu32 = 0;
2011 static int count = 0;
2012
2013 switch (cmd) {
2014 case FBIO_ALLOC:
2015 if(!capable(CAP_SYS_RAWIO)) {
2016 return -EPERM;
2017 }
2018 if(copy_from_user(&sismemreq, (void *)arg, sizeof(sismemreq))) {
2019 return -EFAULT;
2020 }
2021 sis_malloc(&sismemreq);
2022 if(copy_to_user((void *)arg, &sismemreq, sizeof(sismemreq))) {
2023 sis_free((u32)sismemreq.offset);
2024 return -EFAULT;
2025 }
2026 break;
2027
2028 case FBIO_FREE:
2029 if(!capable(CAP_SYS_RAWIO)) {
2030 return -EPERM;
2031 }
2032 if(get_user(gpu32, (u32 *)arg)) {
2033 return -EFAULT;
2034 }
2035 sis_free(gpu32);
2036 break;
2037
2038 case FBIOGET_VBLANK:
2039 sisvbblank.count = 0;
2040 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
2041 if(copy_to_user((void *)arg, &sisvbblank, sizeof(sisvbblank))) {
2042 return -EFAULT;
2043 }
2044 break;
2045
2046 case SISFB_GET_INFO_SIZE:
2047 return put_user(sizeof(sisfb_info), (u32 *)arg);
2048
2049 case SISFB_GET_INFO_OLD:
2050 if(++count < 50) {
2051 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2052 }
2053 case SISFB_GET_INFO: /* For communication with X driver */
2054 x.sisfb_id = SISFB_ID;
2055 x.sisfb_version = VER_MAJOR;
2056 x.sisfb_revision = VER_MINOR;
2057 x.sisfb_patchlevel = VER_LEVEL;
2058 x.chip_id = ivideo->chip_id;
2059 x.memory = ivideo->video_size / 1024;
2060 x.heapstart = ivideo->heapstart / 1024;
2061 if(ivideo->modechanged) {
2062 x.fbvidmode = ivideo->mode_no;
2063 } else {
2064 x.fbvidmode = ivideo->modeprechange;
2065 }
2066 x.sisfb_caps = ivideo->caps;
2067 x.sisfb_tqlen = 512; /* yet fixed */
2068 x.sisfb_pcibus = ivideo->pcibus;
2069 x.sisfb_pcislot = ivideo->pcislot;
2070 x.sisfb_pcifunc = ivideo->pcifunc;
2071 x.sisfb_lcdpdc = ivideo->detectedpdc;
2072 x.sisfb_lcdpdca = ivideo->detectedpdca;
2073 x.sisfb_lcda = ivideo->detectedlcda;
2074 x.sisfb_vbflags = ivideo->vbflags;
2075 x.sisfb_currentvbflags = ivideo->currentvbflags;
2076 x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
2077 x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
2078 x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
2079 x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
2080 x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
2081 x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
2082 x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
2083 x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
2084 x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
2085 x.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
2086
2087 if(copy_to_user((void *)arg, &x, sizeof(x))) {
2088 return -EFAULT;
2089 }
2090 break;
2091
2092 case SISFB_GET_VBRSTATUS_OLD:
2093 if(++count < 50) {
2094 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2095 }
2096 case SISFB_GET_VBRSTATUS:
2097 if(sisfb_CheckVBRetrace(ivideo)) {
2098 return put_user((u32)1, (u32 *) arg);
2099 } else {
2100 return put_user((u32)0, (u32 *) arg);
2101 }
2102
2103 case SISFB_GET_AUTOMAXIMIZE_OLD:
2104 if(++count < 50) {
2105 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2106 }
2107 case SISFB_GET_AUTOMAXIMIZE:
2108 if(ivideo->sisfb_max) return put_user((u32)1, (u32 *)arg);
2109 else return put_user((u32)0, (u32 *)arg);
2110
2111 case SISFB_SET_AUTOMAXIMIZE_OLD:
2112 if(++count < 50) {
2113 printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2114 }
2115 case SISFB_SET_AUTOMAXIMIZE:
2116 if(copy_from_user(&gpu32, (u32 *)arg, sizeof(gpu32))) {
2117 return -EFAULT;
2118 }
2119 ivideo->sisfb_max = (gpu32) ? 1 : 0;
2120 break;
2121
2122 case SISFB_SET_TVPOSOFFSET:
2123 if(copy_from_user(&gpu32, (u32 *)arg, sizeof(gpu32))) {
2124 return -EFAULT;
2125 }
2126 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
2127 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
2128 break;
2129
2130 case SISFB_GET_TVPOSOFFSET:
2131 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)), (u32 *)arg);
2132
2133 case SISFB_SET_LOCK:
2134 if(copy_from_user(&gpu32, (u32 *)arg, sizeof(gpu32))) {
2135 return -EFAULT;
2136 }
2137 ivideo->sisfblocked = (gpu32) ? 1 : 0;
2138 break;
2139
2140 default:
2141 return -EINVAL;
2142 }
2143 return 0;
2144 }
2145
2146 static int
2147 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
2148 {
2149 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2150
2151 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2152
2153 strcpy(fix->id, ivideo->myid);
2154
2155 fix->smem_start = ivideo->video_base;
2156 fix->smem_len = ivideo->sisfb_mem;
2157 fix->type = FB_TYPE_PACKED_PIXELS;
2158 fix->type_aux = 0;
2159 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
2160 fix->xpanstep = 0;
2161 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
2162 fix->ywrapstep = 0;
2163 fix->line_length = ivideo->video_linelength;
2164 fix->mmio_start = ivideo->mmio_base;
2165 fix->mmio_len = ivideo->mmio_size;
2166 if(ivideo->sisvga_engine == SIS_300_VGA) {
2167 fix->accel = FB_ACCEL_SIS_GLAMOUR;
2168 } else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) {
2169 fix->accel = FB_ACCEL_SIS_XABRE;
2170 } else {
2171 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
2172 }
2173
2174 return 0;
2175 }
2176
2177 /* ---------------- fb_ops structures ----------------- */
2178
2179 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2180 static struct fb_ops sisfb_ops = {
2181 .owner = THIS_MODULE,
2182 .fb_get_fix = sisfb_get_fix,
2183 .fb_get_var = sisfb_get_var,
2184 .fb_set_var = sisfb_set_var,
2185 .fb_get_cmap = sisfb_get_cmap,
2186 .fb_set_cmap = sisfb_set_cmap,
2187 .fb_pan_display = sisfb_pan_display,
2188 .fb_ioctl = sisfb_ioctl
2189 };
2190 #endif
2191
2192 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
2193 static struct fb_ops sisfb_ops = {
2194 .owner = THIS_MODULE,
2195 .fb_open = sisfb_open,
2196 .fb_release = sisfb_release,
2197 .fb_check_var = sisfb_check_var,
2198 .fb_set_par = sisfb_set_par,
2199 .fb_setcolreg = sisfb_setcolreg,
2200 .fb_pan_display = sisfb_pan_display,
2201 .fb_blank = sisfb_blank,
2202 .fb_fillrect = fbcon_sis_fillrect,
2203 .fb_copyarea = fbcon_sis_copyarea,
2204 .fb_imageblit = cfb_imageblit,
2205 .fb_cursor = soft_cursor,
2206 .fb_sync = fbcon_sis_sync,
2207 .fb_ioctl = sisfb_ioctl
2208 };
2209 #endif
2210
2211 /* ---------------- Chip generation dependent routines ---------------- */
2212
2213 static struct pci_dev * sisfb_get_northbridge(int basechipid)
2214 {
2215 struct pci_dev *pdev = NULL;
2216 int nbridgenum, nbridgeidx, i;
2217 const unsigned short nbridgeids[] = {
2218 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2219 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2220 PCI_DEVICE_ID_SI_730,
2221 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2222 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2223 PCI_DEVICE_ID_SI_651,
2224 PCI_DEVICE_ID_SI_740,
2225 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760 VGA */
2226 PCI_DEVICE_ID_SI_741,
2227 PCI_DEVICE_ID_SI_660,
2228 PCI_DEVICE_ID_SI_760
2229 };
2230
2231 switch(basechipid) {
2232 #ifdef CONFIG_FB_SIS_300
2233 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2234 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2235 #endif
2236 #ifdef CONFIG_FB_SIS_315
2237 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2238 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
2239 case SIS_660: nbridgeidx = 7; nbridgenum = 4; break;
2240 #endif
2241 default: return NULL;
2242 }
2243 for(i = 0; i < nbridgenum; i++) {
2244 if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break;
2245 }
2246 return pdev;
2247 }
2248
2249 static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
2250 {
2251 u8 reg;
2252
2253 ivideo->video_size = 0;
2254
2255 switch(ivideo->chip) {
2256 #ifdef CONFIG_FB_SIS_300
2257 case SIS_300:
2258 inSISIDXREG(SISSR, 0x14, reg);
2259 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2260 break;
2261 case SIS_540:
2262 case SIS_630:
2263 case SIS_730:
2264 if(!ivideo->nbridge) return -1;
2265 pci_read_config_byte(ivideo->nbridge, 0x63, ®);
2266 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2267 break;
2268 #endif
2269 #ifdef CONFIG_FB_SIS_315
2270 case SIS_315H:
2271 case SIS_315PRO:
2272 case SIS_315:
2273 inSISIDXREG(SISSR, 0x14, reg);
2274 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2275 switch((reg >> 2) & 0x03) {
2276 case 0x01:
2277 case 0x03:
2278 ivideo->video_size <<= 1;
2279 break;
2280 case 0x02:
2281 ivideo->video_size += (ivideo->video_size/2);
2282 }
2283 break;
2284 case SIS_330:
2285 inSISIDXREG(SISSR, 0x14, reg);
2286 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2287 if(reg & 0x0c) ivideo->video_size <<= 1;
2288 break;
2289 case SIS_550:
2290 case SIS_650:
2291 case SIS_740:
2292 inSISIDXREG(SISSR, 0x14, reg);
2293 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2294 break;
2295 case SIS_661:
2296 case SIS_741:
2297 inSISIDXREG(SISCR, 0x79, reg);
2298 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2299 break;
2300 case SIS_660:
2301 case SIS_760:
2302 inSISIDXREG(SISCR, 0x79, reg);
2303 reg = (reg & 0xf0) >> 4;
2304 if(reg) ivideo->video_size = (1 << reg) << 20;
2305 inSISIDXREG(SISCR, 0x78, reg);
2306 reg &= 0x30;
2307 if(reg) {
2308 if(reg == 0x10) ivideo->video_size += (32 << 20);
2309 else ivideo->video_size += (64 << 20);
2310 }
2311 break;
2312 #endif
2313 default:
2314 return -1;
2315 }
2316 return 0;
2317 }
2318
2319 /* -------------- video bridge device detection --------------- */
2320
2321 static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2322 {
2323 u8 cr32, temp;
2324
2325 #ifdef CONFIG_FB_SIS_300
2326 if(ivideo->sisvga_engine == SIS_300_VGA) {
2327 inSISIDXREG(SISSR, 0x17, temp);
2328 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2329 /* PAL/NTSC is stored on SR16 on such machines */
2330 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2331 inSISIDXREG(SISSR, 0x16, temp);
2332 if(temp & 0x20)
2333 ivideo->vbflags |= TV_PAL;
2334 else
2335 ivideo->vbflags |= TV_NTSC;
2336 }
2337 }
2338 }
2339 #endif
2340
2341 inSISIDXREG(SISCR, 0x32, cr32);
2342
2343 if(cr32 & SIS_CRT1) {
2344 ivideo->sisfb_crt1off = 0;
2345 } else {
2346 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2347 }
2348
2349 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2350
2351 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2352 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2353 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2354
2355 /* Check given parms for hardware compatibility.
2356 * (Cannot do this in the search_xx routines since we don't
2357 * know what hardware we are running on then)
2358 */
2359
2360 if(ivideo->chip != SIS_550) {
2361 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2362 }
2363
2364 if(ivideo->sisfb_tvplug != -1) {
2365 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2366 (!(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) ) {
2367 if(ivideo->sisfb_tvplug & TV_YPBPR) {
2368 ivideo->sisfb_tvplug = -1;
2369 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2370 }
2371 }
2372 }
2373 if(ivideo->sisfb_tvplug != -1) {
2374 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2375 (!(ivideo->vbflags & (VB_301|VB_301B|VB_302B))) ) {
2376 if(ivideo->sisfb_tvplug & TV_HIVISION) {
2377 ivideo->sisfb_tvplug = -1;
2378 printk(KERN_ERR "sisfb: HiVision not supported\n");
2379 }
2380 }
2381 }
2382 if(ivideo->sisfb_tvstd != -1) {
2383 if( (!(ivideo->vbflags & VB_SISBRIDGE)) &&
2384 (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags & VB_CHRONTEL))) ) {
2385 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2386 ivideo->sisfb_tvstd = -1;
2387 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2388 }
2389 }
2390 }
2391
2392 /* Detect/set TV plug & type */
2393 if(ivideo->sisfb_tvplug != -1) {
2394 ivideo->vbflags |= ivideo->sisfb_tvplug;
2395 } else {
2396 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2397 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2398 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2399 else {
2400 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2401 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2402 }
2403 }
2404
2405 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2406 if(ivideo->sisfb_tvstd != -1) {
2407 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2408 ivideo->vbflags |= ivideo->sisfb_tvstd;
2409 }
2410 if(ivideo->vbflags & TV_SCART) {
2411 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2412 ivideo->vbflags |= TV_PAL;
2413 }
2414 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2415 if(ivideo->sisvga_engine == SIS_300_VGA) {
2416 inSISIDXREG(SISSR, 0x38, temp);
2417 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2418 else ivideo->vbflags |= TV_NTSC;
2419 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2420 inSISIDXREG(SISSR, 0x38, temp);
2421 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2422 else ivideo->vbflags |= TV_NTSC;
2423 } else {
2424 inSISIDXREG(SISCR, 0x79, temp);
2425 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2426 else ivideo->vbflags |= TV_NTSC;
2427 }
2428 }
2429 }
2430
2431 /* Copy forceCRT1 option to CRT1off if option is given */
2432 if(ivideo->sisfb_forcecrt1 != -1) {
2433 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2434 }
2435 }
2436
2437 static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo)
2438 {
2439 char stdstr[] = "sisfb: Detected";
2440 char bridgestr[] = "video bridge";
2441 u8 vb_chipid;
2442 u8 reg;
2443
2444 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2445 switch(vb_chipid) {
2446 case 0x01:
2447 inSISIDXREG(SISPART4, 0x01, reg);
2448 if(reg < 0xb0) {
2449 ivideo->vbflags |= VB_301;
2450 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2451 } else if(reg < 0xc0) {
2452 ivideo->vbflags |= VB_301B;
2453 inSISIDXREG(SISPART4,0x23,reg);
2454 if(!(reg & 0x02)) {
2455 ivideo->vbflags |= VB_30xBDH;
2456 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2457 } else {
2458 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2459 }
2460 } else if(reg < 0xd0) {
2461 ivideo->vbflags |= VB_301C;
2462 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2463 } else if(reg < 0xe0) {
2464 ivideo->vbflags |= VB_301LV;
2465 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2466 } else if(reg <= 0xe1) {
2467 inSISIDXREG(SISPART4,0x39,reg);
2468 if(reg == 0xff) {
2469 ivideo->vbflags |= VB_302LV;
2470 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2471 } else {
2472 ivideo->vbflags |= VB_301C;
2473 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2474 #if 0
2475 ivideo->vbflags |= VB_302ELV;
2476 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2477 #endif
2478 }
2479 }
2480 break;
2481 case 0x02:
2482 ivideo->vbflags |= VB_302B;
2483 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2484 break;
2485 }
2486
2487 if((!(ivideo->vbflags & VB_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2488 inSISIDXREG(SISCR, 0x37, reg);
2489 reg &= SIS_EXTERNAL_CHIP_MASK;
2490 reg >>= 1;
2491 if(ivideo->sisvga_engine == SIS_300_VGA) {
2492 #ifdef CONFIG_FB_SIS_300
2493 switch(reg) {
2494 case SIS_EXTERNAL_CHIP_LVDS:
2495 ivideo->vbflags |= VB_LVDS;
2496 break;
2497 case SIS_EXTERNAL_CHIP_TRUMPION:
2498 ivideo->vbflags |= VB_TRUMPION;
2499 break;
2500 case SIS_EXTERNAL_CHIP_CHRONTEL:
2501 ivideo->vbflags |= VB_CHRONTEL;
2502 break;
2503 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2504 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2505 break;
2506 }
2507 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 1;
2508 #endif
2509 } else if(ivideo->chip < SIS_661) {
2510 #ifdef CONFIG_FB_SIS_315
2511 switch (reg) {
2512 case SIS310_EXTERNAL_CHIP_LVDS:
2513 ivideo->vbflags |= VB_LVDS;
2514 break;
2515 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2516 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2517 break;
2518 }
2519 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2520 #endif
2521 } else if(ivideo->chip >= SIS_661) {
2522 #ifdef CONFIG_FB_SIS_315
2523 inSISIDXREG(SISCR, 0x38, reg);
2524 reg >>= 5;
2525 switch(reg) {
2526 case 0x02:
2527 ivideo->vbflags |= VB_LVDS;
2528 break;
2529 case 0x03:
2530 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2531 break;
2532 case 0x04:
2533 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);
2534 break;
2535 }
2536 if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2537 #endif
2538 }
2539 if(ivideo->vbflags & VB_LVDS) {
2540 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2541 }
2542 if(ivideo->vbflags & VB_TRUMPION) {
2543 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2544 }
2545 if(ivideo->vbflags & VB_CHRONTEL) {
2546 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2547 }
2548 if(ivideo->vbflags & VB_CONEXANT) {
2549 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2550 }
2551 }
2552
2553 if(ivideo->vbflags & VB_SISBRIDGE) {
2554 SiS_Sense30x(ivideo);
2555 } else if(ivideo->vbflags & VB_CHRONTEL) {
2556 SiS_SenseCh(ivideo);
2557 }
2558 }
2559
2560 /* ------------------ Sensing routines ------------------ */
2561
2562 static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo)
2563 {
2564 unsigned short old;
2565 int count = 48;
2566
2567 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2568 do {
2569 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2570 } while(count--);
2571 return (count == -1) ? FALSE : TRUE;
2572 }
2573
2574 static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
2575 {
2576 BOOLEAN mustwait = FALSE;
2577 u8 SR1F, CR17;
2578 #ifdef CONFIG_FB_SIS_315
2579 u8 CR63=0;
2580 #endif
2581 u16 temp = 0xffff;
2582 int i;
2583
2584 inSISIDXREG(SISSR,0x1F,SR1F);
2585 orSISIDXREG(SISSR,0x1F,0x04);
2586 andSISIDXREG(SISSR,0x1F,0x3F);
2587 if(SR1F & 0xc0) mustwait = TRUE;
2588
2589 #ifdef CONFIG_FB_SIS_315
2590 if(ivideo->sisvga_engine == SIS_315_VGA) {
2591 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,CR63);
2592 CR63 &= 0x40;
2593 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2594 }
2595 #endif
2596
2597 inSISIDXREG(SISCR,0x17,CR17);
2598 CR17 &= 0x80;
2599 if(!CR17) {
2600 orSISIDXREG(SISCR,0x17,0x80);
2601 mustwait = TRUE;
2602 outSISIDXREG(SISSR, 0x00, 0x01);
2603 outSISIDXREG(SISSR, 0x00, 0x03);
2604 }
2605
2606 if(mustwait) {
2607 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2608 }
2609
2610 #ifdef CONFIG_FB_SIS_315
2611 if(ivideo->chip >= SIS_330) {
2612 andSISIDXREG(SISCR,0x32,~0x20);
2613 if(ivideo->chip >= SIS_340) {
2614 outSISIDXREG(SISCR, 0x57, 0x4a);
2615 } else {
2616 outSISIDXREG(SISCR, 0x57, 0x5f);
2617 }
2618 orSISIDXREG(SISCR, 0x53, 0x02);
2619 while((inSISREG(SISINPSTAT)) & 0x01) break;
2620 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2621 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2622 andSISIDXREG(SISCR, 0x53, 0xfd);
2623 andSISIDXREG(SISCR, 0x57, 0x00);
2624 }
2625 #endif
2626
2627 if(temp == 0xffff) {
2628 i = 3;
2629 do {
2630 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, 0, 0, NULL);
2631 } while(((temp == 0) || (temp == 0xffff)) && i--);
2632
2633 if((temp == 0) || (temp == 0xffff)) {
2634 if(sisfb_test_DDC1(ivideo)) temp = 1;
2635 }
2636 }
2637
2638 if((temp) && (temp != 0xffff)) {
2639 orSISIDXREG(SISCR,0x32,0x20);
2640 }
2641
2642 #ifdef CONFIG_FB_SIS_315
2643 if(ivideo->sisvga_engine == SIS_315_VGA) {
2644 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,CR63);
2645 }
2646 #endif
2647
2648 setSISIDXREG(SISCR,0x17,0x7F,CR17);
2649
2650 outSISIDXREG(SISSR,0x1F,SR1F);
2651 }
2652
2653 /* Determine and detect attached devices on SiS30x */
2654 static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2655 {
2656 int temp, mytest, result, i, j;
2657
2658 for(j = 0; j < 10; j++) {
2659 result = 0;
2660 for(i = 0; i < 3; i++) {
2661 mytest = test;
2662 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2663 temp = (type >> 8) | (mytest & 0x00ff);
2664 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2665 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2666 mytest >>= 8;
2667 mytest &= 0x7f;
2668 inSISIDXREG(SISPART4,0x03,temp);
2669 temp ^= 0x0e;
2670 temp &= mytest;
2671 if(temp == mytest) result++;
2672 #if 1
2673 outSISIDXREG(SISPART4,0x11,0x00);
2674 andSISIDXREG(SISPART4,0x10,0xe0);
2675 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2676 #endif
2677 }
2678 if((result == 0) || (result >= 2)) break;
2679 }
2680 return(result);
2681 }
2682
2683 static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
2684 {
2685 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2686 u16 svhs=0, svhs_c=0;
2687 u16 cvbs=0, cvbs_c=0;
2688 u16 vga2=0, vga2_c=0;
2689 int myflag, result;
2690 char stdstr[] = "sisfb: Detected";
2691 char tvstr[] = "TV connected to";
2692
2693 if(ivideo->vbflags & VB_301) {
2694 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2695 inSISIDXREG(SISPART4,0x01,myflag);
2696 if(myflag & 0x04) {
2697 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2698 }
2699 } else if(ivideo->vbflags & (VB_301B | VB_302B)) {
2700 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2701 } else if(ivideo->vbflags & (VB_301LV | VB_302LV)) {
2702 svhs = 0x0200; cvbs = 0x0100;
2703 } else if(ivideo->vbflags & (VB_301C | VB_302ELV)) {
2704 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2705 } else return;
2706
2707 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2708 if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
2709 svhs_c = 0x0408; cvbs_c = 0x0808;
2710 }
2711 biosflag = 2;
2712
2713 if(ivideo->chip == SIS_300) {
2714 inSISIDXREG(SISSR,0x3b,myflag);
2715 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2716 }
2717
2718 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2719 orSISIDXREG(SISSR,0x1e,0x20);
2720
2721 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2722 if(ivideo->vbflags & VB_301C) {
2723 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2724 } else {
2725 orSISIDXREG(SISPART4,0x0d,0x04);
2726 }
2727 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2728
2729 inSISIDXREG(SISPART2,0x00,backupP2_00);
2730 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2731
2732 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2733 if(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV)) {
2734 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2735 }
2736
2737 if(!(ivideo->vbflags & VB_301C)) {
2738 SISDoSense(ivideo, 0, 0);
2739 }
2740
2741 andSISIDXREG(SISCR, 0x32, ~0x14);
2742
2743 if(vga2_c || vga2) {
2744 if(SISDoSense(ivideo, vga2, vga2_c)) {
2745 if(biosflag & 0x01) {
2746 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2747 orSISIDXREG(SISCR, 0x32, 0x04);
2748 } else {
2749 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2750 orSISIDXREG(SISCR, 0x32, 0x10);
2751 }
2752 }
2753 }
2754
2755 andSISIDXREG(SISCR, 0x32, 0x3f);
2756
2757 if(ivideo->vbflags & VB_301C) {
2758 orSISIDXREG(SISPART4,0x0d,0x04);
2759 }
2760
2761 if((ivideo->sisvga_engine == SIS_315_VGA) &&
2762 (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV))) {
2763 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2764 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2765 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2766 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2767 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2768 orSISIDXREG(SISCR,0x32,0x80);
2769 }
2770 }
2771 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2772 }
2773
2774 andSISIDXREG(SISCR, 0x32, ~0x03);
2775
2776 if(!(ivideo->vbflags & TV_YPBPR)) {
2777 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2778 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2779 orSISIDXREG(SISCR, 0x32, 0x02);
2780 }
2781 if((biosflag & 0x02) || (!result)) {
2782 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2783 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2784 orSISIDXREG(SISCR, 0x32, 0x01);
2785 }
2786 }
2787 }
2788
2789 SISDoSense(ivideo, 0, 0);
2790
2791 outSISIDXREG(SISPART2,0x00,backupP2_00);
2792 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2793 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2794
2795 if(ivideo->vbflags & VB_301C) {
2796 inSISIDXREG(SISPART2,0x00,biosflag);
2797 if(biosflag & 0x20) {
2798 for(myflag = 2; myflag > 0; myflag--) {
2799 biosflag ^= 0x20;
2800 outSISIDXREG(SISPART2,0x00,biosflag);
2801 }
2802 }
2803 }
2804
2805 outSISIDXREG(SISPART2,0x00,backupP2_00);
2806 }
2807
2808 /* Determine and detect attached TV's on Chrontel */
2809 static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
2810 {
2811 u8 temp1, temp2;
2812 #ifdef CONFIG_FB_SIS_300
2813 unsigned char test[3];
2814 int i;
2815 #endif
2816 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2817
2818 if(ivideo->chip < SIS_315H) {
2819
2820 #ifdef CONFIG_FB_SIS_300
2821 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2822 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2823 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2824 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2825 /* See Chrontel TB31 for explanation */
2826 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2827 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2828 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b0e);
2829 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2830 }
2831 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2832 if(temp2 != temp1) temp1 = temp2;
2833
2834 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2835 /* Read power status */
2836 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2837 if((temp1 & 0x03) != 0x03) {
2838 /* Power all outputs */
2839 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0B0E);
2840 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2841 }
2842 /* Sense connected TV devices */
2843 for(i = 0; i < 3; i++) {
2844 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0110);
2845 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2846 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0010);
2847 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2848 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2849 if(!(temp1 & 0x08)) test[i] = 0x02;
2850 else if(!(temp1 & 0x02)) test[i] = 0x01;
2851 else test[i] = 0;
2852 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2853 }
2854
2855 if(test[0] == test[1]) temp1 = test[0];
2856 else if(test[0] == test[2]) temp1 = test[0];
2857 else if(test[1] == test[2]) temp1 = test[1];
2858 else {
2859 printk(KERN_INFO
2860 "sisfb: TV detection unreliable - test results varied\n");
2861 temp1 = test[2];
2862 }
2863 if(temp1 == 0x02) {
2864 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2865 ivideo->vbflags |= TV_SVIDEO;
2866 orSISIDXREG(SISCR, 0x32, 0x02);
2867 andSISIDXREG(SISCR, 0x32, ~0x05);
2868 } else if (temp1 == 0x01) {
2869 printk(KERN_INFO "%s CVBS output\n", stdstr);
2870 ivideo->vbflags |= TV_AVIDEO;
2871 orSISIDXREG(SISCR, 0x32, 0x01);
2872 andSISIDXREG(SISCR, 0x32, ~0x06);
2873 } else {
2874 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2875 andSISIDXREG(SISCR, 0x32, ~0x07);
2876 }
2877 } else if(temp1 == 0) {
2878 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2879 andSISIDXREG(SISCR, 0x32, ~0x07);
2880 }
2881 /* Set general purpose IO for Chrontel communication */
2882 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2883 #endif
2884
2885 } else {
2886
2887 #ifdef CONFIG_FB_SIS_315
2888 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2889 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2890 SiS_SetCH701x(&ivideo->SiS_Pr, 0x2049);
2891 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2892 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2893 temp2 |= 0x01;
2894 SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2895 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2896 temp2 ^= 0x01;
2897 SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2898 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2899 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2900 SiS_SetCH701x(&ivideo->SiS_Pr, (temp1 << 8) | 0x49);
2901 temp1 = 0;
2902 if(temp2 & 0x02) temp1 |= 0x01;
2903 if(temp2 & 0x10) temp1 |= 0x01;
2904 if(temp2 & 0x04) temp1 |= 0x02;
2905 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2906 switch(temp1) {
2907 case 0x01:
2908 printk(KERN_INFO "%s CVBS output\n", stdstr);
2909 ivideo->vbflags |= TV_AVIDEO;
2910 orSISIDXREG(SISCR, 0x32, 0x01);
2911 andSISIDXREG(SISCR, 0x32, ~0x06);
2912 break;
2913 case 0x02:
2914 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2915 ivideo->vbflags |= TV_SVIDEO;
2916 orSISIDXREG(SISCR, 0x32, 0x02);
2917 andSISIDXREG(SISCR, 0x32, ~0x05);
2918 break;
2919 case 0x04:
2920 printk(KERN_INFO "%s SCART output\n", stdstr);
2921 orSISIDXREG(SISCR, 0x32, 0x04);
2922 andSISIDXREG(SISCR, 0x32, ~0x03);
2923 break;
2924 default:
2925 andSISIDXREG(SISCR, 0x32, ~0x07);
2926 }
2927 #endif
2928 }
2929 }
2930
2931 /* ------------------------ Heap routines -------------------------- */
2932
2933 static u32 __devinit
2934 sisfb_getheapstart(struct sis_video_info *ivideo)
2935 {
2936 u32 ret = ivideo->sisfb_parm_mem * 1024;
2937 u32 max = ivideo->video_size - ivideo->hwcursor_size;
2938 u32 def;
2939
2940 /* Calculate heap start = end of memory for console
2941 *
2942 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
2943 * C = console, D = heap, H = HWCursor, Q = cmd-queue
2944 *
2945 * Basically given by "mem" parameter
2946 *
2947 * maximum = videosize - cmd_queue - hwcursor
2948 * (results in a heap of size 0)
2949 * default = SiS 300: depends on videosize
2950 * SiS 315/330: 32k below max
2951 */
2952
2953 if(ivideo->sisvga_engine == SIS_300_VGA) {
2954 max -= TURBO_QUEUE_AREA_SIZE;
2955 if(ivideo->video_size > 0x1000000) {
2956 def = 0xc00000;
2957 } else if(ivideo->video_size > 0x800000) {
2958 def = 0x800000;
2959 } else {
2960 def = 0x400000;
2961 }
2962 } else {
2963 max -= COMMAND_QUEUE_AREA_SIZE;
2964 def = max - 0x8000;
2965 }
2966
2967 if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) {
2968 ret = def;
2969 }
2970
2971 return ret;
2972 }
2973
2974 static int __devinit
2975 sisfb_heap_init(struct sis_video_info *ivideo)
2976 {
2977 SIS_OH *poh;
2978
2979 ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo);
2980
2981 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
2982 ivideo->sisfb_heap_end = ivideo->video_vbase + ivideo->video_size;
2983
2984 /* Initialize command queue (We use MMIO only) */
2985
2986 #ifdef CONFIG_FB_SIS_315
2987 if(ivideo->sisvga_engine == SIS_315_VGA) {
2988 u32 tempq = 0;
2989 u8 temp = 0;
2990
2991 ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
2992
2993 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2994 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2995
2996 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2997 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2998
2999 temp = SIS_CMD_QUEUE_SIZE_512k;
3000 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3001 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3002
3003 tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE);
3004 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3005
3006 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3007 }
3008 #endif
3009
3010 #ifdef CONFIG_FB_SIS_300
3011 if(ivideo->sisvga_engine == SIS_300_VGA) {
3012 unsigned long tqueue_pos;
3013 u8 tq_state;
3014
3015 ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
3016
3017 tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
3018
3019 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3020 tq_state |= 0xf0;
3021 tq_state &= 0xfc;
3022 tq_state |= (u8)(tqueue_pos >> 8);
3023 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3024
3025 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
3026
3027 ivideo->caps |= TURBO_QUEUE_CAP;
3028 }
3029 #endif
3030
3031 /* Reserve memory for the HWCursor */
3032 ivideo->sisfb_heap_end -= ivideo->hwcursor_size;
3033 ivideo->hwcursor_vbase = ivideo->sisfb_heap_end;
3034 ivideo->caps |= HW_CURSOR_CAP;
3035
3036 ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start;
3037
3038 if(ivideo->cardnumber == 0) {
3039
3040 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3041 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3042
3043 sisfb_heap.vinfo = ivideo;
3044
3045 sisfb_heap.poha_chain = NULL;
3046 sisfb_heap.poh_freelist = NULL;
3047
3048 poh = sisfb_poh_new_node();
3049 if(poh == NULL) return 1;
3050
3051 poh->poh_next = &sisfb_heap.oh_free;
3052 poh->poh_prev = &sisfb_heap.oh_free;
3053 poh->size = ivideo->sisfb_heap_size;
3054 poh->offset = ivideo->heapstart;
3055
3056 sisfb_heap.oh_free.poh_next = poh;
3057 sisfb_heap.oh_free.poh_prev = poh;
3058 sisfb_heap.oh_free.size = 0;
3059 sisfb_heap.max_freesize = poh->size;
3060
3061 sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
3062 sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
3063 sisfb_heap.oh_used.size = SENTINEL;
3064
3065 } else {
3066
3067 printk(KERN_INFO "Skipped heap initialization for secondary cards\n");
3068
3069 }
3070
3071 return 0;
3072 }
3073
3074 static SIS_OH *
3075 sisfb_poh_new_node(void)
3076 {
3077 int i;
3078 unsigned long cOhs;
3079 SIS_OHALLOC *poha;
3080 SIS_OH *poh;
3081
3082 if(sisfb_heap.poh_freelist == NULL) {
3083 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3084 if(!poha) return NULL;
3085
3086 poha->poha_next = sisfb_heap.poha_chain;
3087 sisfb_heap.poha_chain = poha;
3088
3089 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
3090
3091 poh = &poha->aoh[0];
3092 for(i = cOhs - 1; i != 0; i--) {
3093 poh->poh_next = poh + 1;
3094 poh = poh + 1;
3095 }
3096
3097 poh->poh_next = NULL;
3098 sisfb_heap.poh_freelist = &poha->aoh[0];
3099 }
3100
3101 poh = sisfb_heap.poh_freelist;
3102 sisfb_heap.poh_freelist = poh->poh_next;
3103
3104 return (poh);
3105 }
3106
3107 static SIS_OH *
3108 sisfb_poh_allocate(u32 size)
3109 {
3110 SIS_OH *pohThis;
3111 SIS_OH *pohRoot;
3112 int bAllocated = 0;
3113
3114 if(size > sisfb_heap.max_freesize) {
3115 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3116 (unsigned int) size / 1024);
3117 return (NULL);
3118 }
3119
3120 pohThis = sisfb_heap.oh_free.poh_next;
3121
3122 while(pohThis != &sisfb_heap.oh_free) {
3123 if (size <= pohThis->size) {
3124 bAllocated = 1;
3125 break;
3126 }
3127 pohThis = pohThis->poh_next;
3128 }
3129
3130 if(!bAllocated) {
3131 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3132 (unsigned int) size / 1024);
3133 return (NULL);
3134 }
3135
3136 if(size == pohThis->size) {
3137 pohRoot = pohThis;
3138 sisfb_delete_node(pohThis);
3139 } else {
3140 pohRoot = sisfb_poh_new_node();
3141
3142 if(pohRoot == NULL) {
3143 return (NULL);
3144 }
3145
3146 pohRoot->offset = pohThis->offset;
3147 pohRoot->size = size;
3148
3149 pohThis->offset += size;
3150 pohThis->size -= size;
3151 }
3152
3153 sisfb_heap.max_freesize -= size;
3154
3155 pohThis = &sisfb_heap.oh_used;
3156 sisfb_insert_node(pohThis, pohRoot);
3157
3158 return (pohRoot);
3159 }
3160
3161 static void
3162 sisfb_delete_node(SIS_OH *poh)
3163 {
3164 SIS_OH *poh_prev;
3165 SIS_OH *poh_next;
3166
3167 poh_prev = poh->poh_prev;
3168 poh_next = poh->poh_next;
3169
3170 poh_prev->poh_next = poh_next;
3171 poh_next->poh_prev = poh_prev;
3172 }
3173
3174 static void
3175 sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
3176 {
3177 SIS_OH *pohTemp;
3178
3179 pohTemp = pohList->poh_next;
3180
3181 pohList->poh_next = poh;
3182 pohTemp->poh_prev = poh;
3183
3184 poh->poh_prev = pohList;
3185 poh->poh_next = pohTemp;
3186 }
3187
3188 static SIS_OH *
3189 sisfb_poh_free(u32 base)
3190 {
3191 SIS_OH *pohThis;
3192 SIS_OH *poh_freed;
3193 SIS_OH *poh_prev;
3194 SIS_OH *poh_next;
3195 u32 ulUpper;
3196 u32 ulLower;
3197 int foundNode = 0;
3198
3199 poh_freed = sisfb_heap.oh_used.poh_next;
3200
3201 while(poh_freed != &sisfb_heap.oh_used) {
3202 if(poh_freed->offset == base) {
3203 foundNode = 1;
3204 break;
3205 }
3206
3207 poh_freed = poh_freed->poh_next;
3208 }
3209
3210 if(!foundNode) return(NULL);
3211
3212 sisfb_heap.max_freesize += poh_freed->size;
3213
3214 poh_prev = poh_next = NULL;
3215 ulUpper = poh_freed->offset + poh_freed->size;
3216 ulLower = poh_freed->offset;
3217
3218 pohThis = sisfb_heap.oh_free.poh_next;
3219
3220 while(pohThis != &sisfb_heap.oh_free) {
3221 if(pohThis->offset == ulUpper) {
3222 poh_next = pohThis;
3223 } else if((pohThis->offset + pohThis->size) == ulLower) {
3224 poh_prev = pohThis;
3225 }
3226 pohThis = pohThis->poh_next;
3227 }
3228
3229 sisfb_delete_node(poh_freed);
3230
3231 if(poh_prev && poh_next) {
3232 poh_prev->size += (poh_freed->size + poh_next->size);
3233 sisfb_delete_node(poh_next);
3234 sisfb_free_node(poh_freed);
3235 sisfb_free_node(poh_next);
3236 return(poh_prev);
3237 }
3238
3239 if(poh_prev) {
3240 poh_prev->size += poh_freed->size;
3241 sisfb_free_node(poh_freed);
3242 return(poh_prev);
3243 }
3244
3245 if(poh_next) {
3246 poh_next->size += poh_freed->size;
3247 poh_next->offset = poh_freed->offset;
3248 sisfb_free_node(poh_freed);
3249 return(poh_next);
3250 }
3251
3252 sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
3253
3254 return(poh_freed);
3255 }
3256
3257 static void
3258 sisfb_free_node(SIS_OH *poh)
3259 {
3260 if(poh == NULL) return;
3261
3262 poh->poh_next = sisfb_heap.poh_freelist;
3263 sisfb_heap.poh_freelist = poh;
3264 }
3265
3266 void
3267 sis_malloc(struct sis_memreq *req)
3268 {
3269 struct sis_video_info *ivideo = sisfb_heap.vinfo;
3270 SIS_OH *poh = NULL;
3271
3272 if((ivideo) && (!ivideo->havenoheap)) {
3273 poh = sisfb_poh_allocate((u32)req->size);
3274 }
3275
3276 if(poh == NULL) {
3277 req->offset = req->size = 0;
3278 DPRINTK("sisfb: Video RAM allocation failed\n");
3279 } else {
3280 req->offset = poh->offset;
3281 req->size = poh->size;
3282 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3283 (poh->offset + ivideo->video_vbase));
3284 }
3285 }
3286
3287 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3288
3289 void
3290 sis_free(u32 base)
3291 {
3292 struct sis_video_info *ivideo = sisfb_heap.vinfo;
3293 SIS_OH *poh;
3294
3295 if((!ivideo) || (ivideo->havenoheap)) return;
3296
3297 poh = sisfb_poh_free((u32)base);
3298
3299 if(poh == NULL) {
3300 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3301 (unsigned int) base);
3302 }
3303 }
3304
3305 /* --------------------- SetMode routines ------------------------- */
3306
3307 static void
3308 sisfb_pre_setmode(struct sis_video_info *ivideo)
3309 {
3310 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3311 int tvregnum = 0;
3312
3313 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3314
3315 inSISIDXREG(SISCR, 0x31, cr31);
3316 cr31 &= ~0x60;
3317 cr31 |= 0x04;
3318
3319 cr33 = ivideo->rate_idx & 0x0F;
3320
3321 #ifdef CONFIG_FB_SIS_315
3322 if(ivideo->sisvga_engine == SIS_315_VGA) {
3323 if(ivideo->chip >= SIS_661) {
3324 inSISIDXREG(SISCR, 0x38, cr38);
3325 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3326 } else {
3327 tvregnum = 0x38;
3328 inSISIDXREG(SISCR, tvregnum, cr38);
3329 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3330 }
3331 }
3332 #endif
3333 #ifdef CONFIG_FB_SIS_300
3334 if(ivideo->sisvga_engine == SIS_300_VGA) {
3335 tvregnum = 0x35;
3336 inSISIDXREG(SISCR, tvregnum, cr38);
3337 }
3338 #endif
3339
3340 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3341 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3342
3343 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3344
3345 case CRT2_TV:
3346 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3347 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) {
3348 #ifdef CONFIG_FB_SIS_315
3349 if(ivideo->chip >= SIS_661) {
3350 cr38 |= 0x04;
3351 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3352 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3353 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3354 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3355 cr35 &= ~0x01;
3356 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3357 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3358 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3359 cr38 |= 0x08;
3360 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3361 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3362 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3363 cr31 &= ~0x01;
3364 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3365 }
3366 #endif
3367 } else if((ivideo->vbflags & TV_HIVISION) && (ivideo->vbflags & (VB_301|VB_301B|VB_302B))) {
3368 if(ivideo->chip >= SIS_661) {
3369 cr38 |= 0x04;
3370 cr35 |= 0x60;
3371 } else {
3372 cr30 |= 0x80;
3373 }
3374 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3375 cr31 |= 0x01;
3376 cr35 |= 0x01;
3377 ivideo->currentvbflags |= TV_HIVISION;
3378 } else if(ivideo->vbflags & TV_SCART) {
3379 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3380 cr31 |= 0x01;
3381 cr35 |= 0x01;
3382 ivideo->currentvbflags |= TV_SCART;
3383 } else {
3384 if(ivideo->vbflags & TV_SVIDEO) {
3385 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3386 ivideo->currentvbflags |= TV_SVIDEO;
3387 }
3388 if(ivideo->vbflags & TV_AVIDEO) {
3389 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3390 ivideo->currentvbflags |= TV_AVIDEO;
3391 }
3392 }
3393 cr31 |= SIS_DRIVER_MODE;
3394
3395 if(ivideo->vbflags & (TV_AVIDEO|TV_SVIDEO)) {
3396 if(ivideo->vbflags & TV_PAL) {
3397 cr31 |= 0x01; cr35 |= 0x01;
3398 ivideo->currentvbflags |= TV_PAL;
3399 if(ivideo->vbflags & TV_PALM) {
3400 cr38 |= 0x40; cr35 |= 0x04;
3401 ivideo->currentvbflags |= TV_PALM;
3402 } else if(ivideo->vbflags & TV_PALN) {
3403 cr38 |= 0x80; cr35 |= 0x08;
3404 ivideo->currentvbflags |= TV_PALN;
3405 }
3406 } else {
3407 cr31 &= ~0x01; cr35 &= ~0x01;
3408 ivideo->currentvbflags |= TV_NTSC;
3409 if(ivideo->vbflags & TV_NTSCJ) {
3410 cr38 |= 0x40; cr35 |= 0x02;
3411 ivideo->currentvbflags |= TV_NTSCJ;
3412 }
3413 }
3414 }
3415 break;
3416
3417 case CRT2_LCD:
3418 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3419 cr31 |= SIS_DRIVER_MODE;
3420 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3421 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3422 break;
3423
3424 case CRT2_VGA:
3425 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3426 cr31 |= SIS_DRIVER_MODE;
3427 if(ivideo->sisfb_nocrt2rate) {
3428 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3429 } else {
3430 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3431 }
3432 break;
3433
3434 default: /* disable CRT2 */
3435 cr30 = 0x00;
3436 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3437 }
3438
3439 outSISIDXREG(SISCR, 0x30, cr30);
3440 outSISIDXREG(SISCR, 0x33, cr33);
3441
3442 if(ivideo->chip >= SIS_661) {
3443 #ifdef CONFIG_FB_SIS_315
3444 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3445 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3446 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3447 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3448 #endif
3449 } else if(ivideo->chip != SIS_300) {
3450 outSISIDXREG(SISCR, tvregnum, cr38);
3451 }
3452 outSISIDXREG(SISCR, 0x31, cr31);
3453
3454 if(ivideo->accel) sisfb_syncaccel(ivideo);
3455
3456 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3457 }
3458
3459 /* Fix SR11 for 661 and later */
3460 #ifdef CONFIG_FB_SIS_315
3461 static void
3462 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3463 {
3464 u8 tmpreg;
3465
3466 if(ivideo->chip >= SIS_661) {
3467 inSISIDXREG(SISSR,0x11,tmpreg);
3468 if(tmpreg & 0x20) {
3469 inSISIDXREG(SISSR,0x3e,tmpreg);
3470 tmpreg = (tmpreg + 1) & 0xff;
3471 outSISIDXREG(SISSR,0x3e,tmpreg);
3472 inSISIDXREG(SISSR,0x11,tmpreg);
3473 }
3474 if(tmpreg & 0xf0) {
3475 andSISIDXREG(SISSR,0x11,0x0f);
3476 }
3477 }
3478 }
3479 #endif
3480
3481 static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3482 {
3483 if(val > 32) val = 32;
3484 if(val < -32) val = -32;
3485 ivideo->tvxpos = val;
3486
3487 if(ivideo->sisfblocked) return;
3488 if(!ivideo->modechanged) return;
3489
3490 if(ivideo->currentvbflags & CRT2_TV) {
3491
3492 if(ivideo->vbflags & VB_CHRONTEL) {
3493
3494 int x = ivideo->tvx;
3495
3496 switch(ivideo->chronteltype) {
3497 case 1:
3498 x += val;
3499 if(x < 0) x = 0;
3500 outSISIDXREG(SISSR,0x05,0x86);
3501 SiS_SetCH700x(&ivideo->SiS_Pr, (((x & 0xff) << 8) | 0x0a));
3502 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD);
3503 break;
3504 case 2:
3505 /* Not supported by hardware */
3506 break;
3507 }
3508
3509 } else if(ivideo->vbflags & VB_SISBRIDGE) {
3510
3511 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3512 unsigned short temp;
3513
3514 p2_1f = ivideo->p2_1f;
3515 p2_20 = ivideo->p2_20;
3516 p2_2b = ivideo->p2_2b;
3517 p2_42 = ivideo->p2_42;
3518 p2_43 = ivideo->p2_43;
3519
3520 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3521 temp += (val * 2);
3522 p2_1f = temp & 0xff;
3523 p2_20 = (temp & 0xf00) >> 4;
3524 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3525 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3526 temp += (val * 2);
3527 p2_43 = temp & 0xff;
3528 p2_42 = (temp & 0xf00) >> 4;
3529 outSISIDXREG(SISPART2,0x1f,p2_1f);
3530 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3531 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3532 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3533 outSISIDXREG(SISPART2,0x43,p2_43);
3534 }
3535 }
3536 }
3537
3538 static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3539 {
3540 if(val > 32) val = 32;
3541 if(val < -32) val = -32;
3542 ivideo->tvypos = val;
3543
3544 if(ivideo->sisfblocked) return;
3545 if(!ivideo->modechanged) return;
3546
3547 if(ivideo->currentvbflags & CRT2_TV) {
3548
3549 if(ivideo->vbflags & VB_CHRONTEL) {
3550
3551 int y = ivideo->tvy;
3552
3553 switch(ivideo->chronteltype) {
3554 case 1:
3555 y -= val;
3556 if(y < 0) y = 0;
3557 outSISIDXREG(SISSR,0x05,0x86);
3558 SiS_SetCH700x(&ivideo->SiS_Pr, (((y & 0xff) << 8) | 0x0b));
3559 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, ((y & 0x0100) | 0x08),0xFE);
3560 break;
3561 case 2:
3562 /* Not supported by hardware */
3563 break;
3564 }
3565
3566 } else if(ivideo->vbflags & VB_SISBRIDGE) {
3567
3568 char p2_01, p2_02;
3569 val /= 2;
3570 p2_01 = ivideo->p2_01;
3571 p2_02 = ivideo->p2_02;
3572
3573 p2_01 += val;
3574 p2_02 += val;
3575 while((p2_01 <= 0) || (p2_02 <= 0)) {
3576 p2_01 += 2;
3577 p2_02 += 2;
3578 }
3579 outSISIDXREG(SISPART2,0x01,p2_01);
3580 outSISIDXREG(SISPART2,0x02,p2_02);
3581 }
3582 }
3583 }
3584
3585 static void
3586 sisfb_post_setmode(struct sis_video_info *ivideo)
3587 {
3588 u8 reg;
3589 BOOLEAN crt1isoff = FALSE;
3590 BOOLEAN doit = TRUE;
3591 #ifdef CONFIG_FB_SIS_315
3592 u8 reg1;
3593 #endif
3594
3595 outSISIDXREG(SISSR,0x05,0x86);
3596
3597 #ifdef CONFIG_FB_SIS_315
3598 sisfb_fixup_SR11(ivideo);
3599 #endif
3600
3601 /* Now we actually HAVE changed the display mode */
3602 ivideo->modechanged = 1;
3603
3604 /* We can't switch off CRT1 if bridge is in slave mode */
3605 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
3606 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3607 } else ivideo->sisfb_crt1off = 0;
3608
3609 #ifdef CONFIG_FB_SIS_300
3610 if(ivideo->sisvga_engine == SIS_300_VGA) {
3611 if((ivideo->sisfb_crt1off) && (doit)) {
3612 crt1isoff = TRUE;
3613 reg = 0x00;
3614 } else {
3615 crt1isoff = FALSE;
3616 reg = 0x80;
3617 }
3618 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3619 }
3620 #endif
3621 #ifdef CONFIG_FB_SIS_315
3622 if(ivideo->sisvga_engine == SIS_315_VGA) {
3623 if((ivideo->sisfb_crt1off) && (doit)) {
3624 crt1isoff = TRUE;
3625 reg = 0x40;
3626 reg1 = 0xc0;
3627 } else {
3628 crt1isoff = FALSE;
3629 reg = 0x00;
3630 reg1 = 0x00;
3631
3632 }
3633 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3634 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3635 }
3636 #endif
3637
3638 if(crt1isoff) {
3639 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3640 ivideo->currentvbflags |= VB_SINGLE_MODE;
3641 } else {
3642 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3643 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3644 ivideo->currentvbflags |= VB_MIRROR_MODE;
3645 } else {
3646 ivideo->currentvbflags |= VB_SINGLE_MODE;
3647 }
3648 }
3649
3650 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3651
3652 if(ivideo->currentvbflags & CRT2_TV) {
3653 if(ivideo->vbflags & VB_SISBRIDGE) {
3654 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3655 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3656 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3657 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3658 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3659 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3660 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3661 } else if(ivideo->vbflags & VB_CHRONTEL) {
3662 if(ivideo->chronteltype == 1) {
3663 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3664 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3665 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3666 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3667 }
3668 }
3669 }
3670
3671 if(ivideo->tvxpos) {
3672 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3673 }
3674 if(ivideo->tvypos) {
3675 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3676 }
3677
3678 if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) { /* Set filter for SiS301 */
3679
3680 unsigned char filter_tb = 0;
3681
3682 switch (ivideo->video_width) {
3683 case 320:
3684 filter_tb = (ivideo->vbflags & TV_NTSC) ? 4 : 12;
3685 break;
3686 case 640:
3687 filter_tb = (ivideo->vbflags & TV_NTSC) ? 5 : 13;
3688 break;
3689 case 720:
3690 filter_tb = (ivideo->vbflags & TV_NTSC) ? 6 : 14;
3691 break;
3692 case 400:
3693 case 800:
3694 filter_tb = (ivideo->vbflags & TV_NTSC) ? 7 : 15;
3695 break;
3696 default:
3697 ivideo->sisfb_filter = -1;
3698 break;
3699 }
3700
3701 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
3702
3703 if(ivideo->vbflags & TV_NTSC) {
3704
3705 andSISIDXREG(SISPART2, 0x3a, 0x1f);
3706
3707 if (ivideo->vbflags & TV_SVIDEO) {
3708
3709 andSISIDXREG(SISPART2, 0x30, 0xdf);
3710
3711 } else if (ivideo->vbflags & TV_AVIDEO) {
3712
3713 orSISIDXREG(SISPART2, 0x30, 0x20);
3714
3715 switch (ivideo->video_width) {
3716 case 640:
3717 outSISIDXREG(SISPART2, 0x35, 0xEB);
3718 outSISIDXREG(SISPART2, 0x36, 0x04);
3719 outSISIDXREG(SISPART2, 0x37, 0x25);
3720 outSISIDXREG(SISPART2, 0x38, 0x18);
3721 break;
3722 case 720:
3723 outSISIDXREG(SISPART2, 0x35, 0xEE);
3724 outSISIDXREG(SISPART2, 0x36, 0x0C);
3725 outSISIDXREG(SISPART2, 0x37, 0x22);
3726 outSISIDXREG(SISPART2, 0x38, 0x08);
3727 break;
3728 case 400:
3729 case 800:
3730 outSISIDXREG(SISPART2, 0x35, 0xEB);
3731 outSISIDXREG(SISPART2, 0x36, 0x15);
3732 outSISIDXREG(SISPART2, 0x37, 0x25);
3733 outSISIDXREG(SISPART2, 0x38, 0xF6);
3734 break;
3735 }
3736 }
3737
3738 } else if(ivideo->vbflags & TV_PAL) {
3739
3740 andSISIDXREG(SISPART2, 0x3A, 0x1F);
3741
3742 if (ivideo->vbflags & TV_SVIDEO) {
3743
3744 andSISIDXREG(SISPART2, 0x30, 0xDF);
3745
3746 } else if (ivideo->vbflags & TV_AVIDEO) {
3747
3748 orSISIDXREG(SISPART2, 0x30, 0x20);
3749
3750 switch (ivideo->video_width) {
3751 case 640:
3752 outSISIDXREG(SISPART2, 0x35, 0xF1);
3753 outSISIDXREG(SISPART2, 0x36, 0xF7);
3754 outSISIDXREG(SISPART2, 0x37, 0x1F);
3755 outSISIDXREG(SISPART2, 0x38, 0x32);
3756 break;
3757 case 720:
3758 outSISIDXREG(SISPART2, 0x35, 0xF3);
3759 outSISIDXREG(SISPART2, 0x36, 0x00);
3760 outSISIDXREG(SISPART2, 0x37, 0x1D);
3761 outSISIDXREG(SISPART2, 0x38, 0x20);
3762 break;
3763 case 400:
3764 case 800:
3765 outSISIDXREG(SISPART2, 0x35, 0xFC);
3766 outSISIDXREG(SISPART2, 0x36, 0xFB);
3767 outSISIDXREG(SISPART2, 0x37, 0x14);
3768 outSISIDXREG(SISPART2, 0x38, 0x2A);
3769 break;
3770 }
3771 }
3772 }
3773
3774 if((ivideo->sisfb_filter >= 0) && (ivideo->sisfb_filter <= 7)) {
3775 outSISIDXREG(SISPART2,0x35,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][0]));
3776 outSISIDXREG(SISPART2,0x36,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][1]));
3777 outSISIDXREG(SISPART2,0x37,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][2]));
3778 outSISIDXREG(SISPART2,0x38,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][3]));
3779 }
3780
3781 }
3782 }
3783
3784 #ifndef MODULE
3785 int __init sisfb_setup(char *options)
3786 {
3787 char *this_opt;
3788
3789 sisfb_setdefaultparms();
3790
3791 printk(KERN_DEBUG "sisfb: Options %s\n", options);
3792
3793 if(!options || !(*options)) {
3794 return 0;
3795 }
3796
3797 while((this_opt = strsep(&options, ",")) != NULL) {
3798
3799 if(!(*this_opt)) continue;
3800
3801 if(!strnicmp(this_opt, "off", 3)) {
3802 sisfb_off = 1;
3803 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3804 /* Need to check crt2 type first for fstn/dstn */
3805 sisfb_search_crt2type(this_opt + 14);
3806 } else if(!strnicmp(this_opt, "tvmode:",7)) {
3807 sisfb_search_tvstd(this_opt + 7);
3808 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3809 sisfb_search_tvstd(this_opt + 7);
3810 } else if(!strnicmp(this_opt, "mode:", 5)) {
3811 sisfb_search_mode(this_opt + 5, FALSE);
3812 } else if(!strnicmp(this_opt, "vesa:", 5)) {
3813 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
3814 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
3815 } else if(!strnicmp(this_opt, "inverse", 7)) {
3816 sisfb_inverse = 1;
3817 /* fb_invert_cmaps(); */
3818 } else if(!strnicmp(this_opt, "font:", 5)) {
3819 if(strlen(this_opt + 5) < 40) {
3820 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
3821 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
3822 }
3823 #endif
3824 } else if(!strnicmp(this_opt, "rate:", 5)) {
3825 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
3826 } else if(!strnicmp(this_opt, "filter:", 7)) {
3827 sisfb_filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
3828 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3829 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
3830 } else if(!strnicmp(this_opt, "mem:",4)) {
3831 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
3832 } else if(!strnicmp(this_opt, "pdc:", 4)) {
3833 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
3834 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
3835 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
3836 } else if(!strnicmp(this_opt, "noaccel", 7)) {
3837 sisfb_accel = 0;
3838 } else if(!strnicmp(this_opt, "accel", 5)) {
3839 sisfb_accel = -1;
3840 } else if(!strnicmp(this_opt, "noypan", 6)) {
3841 sisfb_ypan = 0;
3842 } else if(!strnicmp(this_opt, "ypan", 4)) {
3843 sisfb_ypan = -1;
3844 } else if(!strnicmp(this_opt, "nomax", 5)) {
3845 sisfb_max = 0;
3846 } else if(!strnicmp(this_opt, "max", 3)) {
3847 sisfb_max = -1;
3848 } else if(!strnicmp(this_opt, "userom:", 7)) {
3849 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
3850 } else if(!strnicmp(this_opt, "useoem:", 7)) {
3851 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
3852 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
3853 sisfb_nocrt2rate = 1;
3854 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
3855 unsigned long temp = 2;
3856 temp = simple_strtoul(this_opt + 9, NULL, 0);
3857 if((temp == 0) || (temp == 1)) {
3858 sisfb_scalelcd = temp ^ 1;
3859 }
3860 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
3861 int temp = 0;
3862 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3863 if((temp >= -32) && (temp <= 32)) {
3864 sisfb_tvxposoffset = temp;
3865 }
3866 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
3867 int temp = 0;
3868 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3869 if((temp >= -32) && (temp <= 32)) {
3870 sisfb_tvyposoffset = temp;
3871 }
3872 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
3873 sisfb_search_specialtiming(this_opt + 14);
3874 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
3875 int temp = 4;
3876 temp = simple_strtoul(this_opt + 7, NULL, 0);
3877 if((temp >= 0) && (temp <= 3)) {
3878 sisfb_lvdshl = temp;
3879 }
3880 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
3881 sisfb_search_mode(this_opt, TRUE);
3882 #if !defined(__i386__) && !defined(__x86_64__)
3883 } else if(!strnicmp(this_opt, "resetcard", 9)) {
3884 sisfb_resetcard = 1;
3885 } else if(!strnicmp(this_opt, "videoram:", 9)) {
3886 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
3887 #endif
3888 } else {
3889 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
3890 }
3891
3892 }
3893
3894
3895
3896 return 0;
3897 }
3898 #endif
3899
3900 static char * __devinit sis_find_rom(struct pci_dev *pdev)
3901 {
3902 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3903
3904 #if defined(__i386__) || defined(__x86_64__)
3905 u32 segstart;
3906 unsigned char *rom_base, *rom;
3907 int romptr;
3908 unsigned short pciid;
3909
3910 for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
3911
3912 rom_base = (unsigned char *)ioremap(segstart, 0x10000);
3913 if(!rom_base) continue;
3914
3915 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) {
3916 iounmap(rom_base);
3917 continue;
3918 }
3919
3920 romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
3921 if(romptr > (0x10000 - 8)) {
3922 iounmap(rom_base);
3923 continue;
3924 }
3925
3926 rom = rom_base + romptr;
3927
3928 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
3929 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) {
3930 iounmap(rom_base);
3931 continue;
3932 }
3933
3934 pciid = readb(rom + 4) | (readb(rom + 5) << 8);
3935 if(pciid != 0x1039) {
3936 iounmap(rom_base);
3937 continue;
3938 }
3939
3940 pciid = readb(rom + 6) | (readb(rom + 7) << 8);
3941 if(pciid == ivideo->chip_id) return rom_base;
3942
3943 iounmap(rom_base);
3944 }
3945 #else
3946 unsigned char *rom_base, *rom, *myrombase = NULL;
3947 int romptr;
3948 unsigned short pciid;
3949 u32 backup;
3950
3951 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &backup);
3952 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
3953 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
3954
3955 rom_base = ioremap(ivideo->video_base, 65536);
3956 if(rom_base) {
3957 if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) {
3958 romptr = (u16)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
3959 if(romptr <= (0x10000 - 8)) {
3960 rom = rom_base + romptr;
3961 if((readb(rom) == 'P') && (readb(rom + 1) == 'C') &&
3962 (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) {
3963 pciid = readb(rom + 4) | (readb(rom + 5) << 8);
3964 if(pciid == 0x1039) {
3965 pciid = readb(rom + 6) | (readb(rom + 7) << 8);
3966 if(pciid == ivideo->chip_id) {
3967 if((myrombase = vmalloc(65536))) {
3968 memcpy_fromio(myrombase, rom_base, 65536);
3969 }
3970 }
3971 }
3972 }
3973 }
3974 }
3975 iounmap(rom_base);
3976 }
3977 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, backup);
3978 if(myrombase) return myrombase;
3979 #endif
3980 return NULL;
3981 }
3982
3983 #ifdef SIS300
3984 static int __devinit
3985 sisfb_chkbuswidth300(struct pci_dev *pdev, ULONG FBAddress)
3986 {
3987 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3988 int i, j;
3989 USHORT temp;
3990 UCHAR reg;
3991
3992 andSISIDXREG(SISSR,0x15,0xFB);
3993 orSISIDXREG(SISSR,0x15,0x04);
3994 outSISIDXREG(SISSR,0x13,0x00);
3995 outSISIDXREG(SISSR,0x14,0xBF);
3996
3997 for(i=0; i<2; i++) {
3998 temp = 0x1234;
3999 for(j=0; j<4; j++) {
4000 writew(temp, FBAddress);
4001 if(readw(FBAddress) == temp) break;
4002 orSISIDXREG(SISSR,0x3c,0x01);
4003 inSISIDXREG(SISSR,0x05,reg);
4004 inSISIDXREG(SISSR,0x05,reg);
4005 andSISIDXREG(SISSR,0x3c,0xfe);
4006 inSISIDXREG(SISSR,0x05,reg);
4007 inSISIDXREG(SISSR,0x05,reg);
4008 temp++;
4009 }
4010 }
4011
4012 writel(0x01234567L, FBAddress);
4013 writel(0x456789ABL, (FBAddress+4));
4014 writel(0x89ABCDEFL, (FBAddress+8));
4015 writel(0xCDEF0123L, (FBAddress+12));
4016 inSISIDXREG(SISSR,0x3b,reg);
4017 if(reg & 0x01) {
4018 if(readl((FBAddress+12)) == 0xCDEF0123L) return(4); /* Channel A 128bit */
4019 }
4020 if(readl((FBAddress+4)) == 0x456789ABL) return(2); /* Channel B 64bit */
4021 return(1); /* 32bit */
4022 }
4023
4024 static void __devinit
4025 sisfb_setramsize300(struct pci_dev *pdev)
4026 {
4027 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4028 ULONG FBAddr = (ULONG)ivideo->sishw_ext.pjVideoMemoryAddress, Addr;
4029 USHORT SR13, SR14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0;
4030 int PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
4031 int RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
4032 int PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k;
4033 const USHORT SiS_DRAMType[17][5] = {
4034 {0x0C,0x0A,0x02,0x40,0x39},
4035 {0x0D,0x0A,0x01,0x40,0x48},
4036 {0x0C,0x09,0x02,0x20,0x35},
4037 {0x0D,0x09,0x01,0x20,0x44},
4038 {0x0C,0x08,0x02,0x10,0x31},
4039 {0x0D,0x08,0x01,0x10,0x40},
4040 {0x0C,0x0A,0x01,0x20,0x34},
4041 {0x0C,0x09,0x01,0x08,0x32},
4042 {0x0B,0x08,0x02,0x08,0x21},
4043 {0x0C,0x08,0x01,0x08,0x30},
4044 {0x0A,0x08,0x02,0x04,0x11},
4045 {0x0B,0x0A,0x01,0x10,0x28},
4046 {0x09,0x08,0x02,0x02,0x01},
4047 {0x0B,0x09,0x01,0x08,0x24},
4048 {0x0B,0x08,0x01,0x04,0x20},
4049 {0x0A,0x08,0x01,0x02,0x10},
4050 {0x09,0x08,0x01,0x01,0x00}
4051 };
4052
4053 buswidth = sisfb_chkbuswidth300(pdev, FBAddr);
4054
4055 MB2Bank = 16;
4056 Done = 0;
4057 for(i = 6; i >= 0; i--) {
4058 if(Done) break;
4059 PseudoRankCapacity = 1 << i;
4060 for(j = 4; j >= 1; j--) {
4061 if(Done) break;
4062 PseudoTotalCapacity = PseudoRankCapacity * j;
4063 PseudoAdrPinCount = 15 - j;
4064 if(PseudoTotalCapacity <= 64) {
4065 for(k = 0; k <= 16; k++) {
4066 if(Done) break;
4067 RankCapacity = buswidth * SiS_DRAMType[k][3];
4068 AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
4069 if(RankCapacity == PseudoRankCapacity)
4070 if(AdrPinCount <= PseudoAdrPinCount) {
4071 if(j == 3) { /* Rank No */
4072 BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
4073 BankNumMid = RankCapacity * MB2Bank * 1 - 1;
4074 } else {
4075 BankNumHigh = RankCapacity * MB2Bank * j - 1;
4076 BankNumMid = RankCapacity * MB2Bank * j / 2 - 1;
4077 }
4078 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4079 PhysicalAdrHigh = BankNumHigh;
4080 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4081 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4082 /* Write data */
4083 andSISIDXREG(SISSR,0x15,0xFB); /* Test */
4084 orSISIDXREG(SISSR,0x15,0x04); /* Test */
4085 TotalCapacity = SiS_DRAMType[k][3] * buswidth;
4086 SR13 = SiS_DRAMType[k][4];
4087 if(buswidth == 4) SR14 = (TotalCapacity - 1) | 0x80;
4088 if(buswidth == 2) SR14 = (TotalCapacity - 1) | 0x40;
4089 if(buswidth == 1) SR14 = (TotalCapacity - 1) | 0x00;
4090 outSISIDXREG(SISSR,0x13,SR13);
4091 outSISIDXREG(SISSR,0x14,SR14);
4092 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4093 /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */
4094 writew(((USHORT)PhysicalAdrHigh), Addr);
4095 Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh;
4096 /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */
4097 writew(((USHORT)BankNumMid), Addr);
4098 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage;
4099 /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */
4100 writew(((USHORT)PhysicalAdrHalfPage), Addr);
4101 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage;
4102 /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */
4103 writew(((USHORT)PhysicalAdrOtherPage), Addr);
4104 /* Read data */
4105 Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4106 data = readw(Addr); /* *((USHORT *)(Addr)); */
4107 if(data == PhysicalAdrHigh) Done = 1;
4108 } /* if */
4109 } /* for k */
4110 } /* if */
4111 } /* for j */
4112 } /* for i */
4113 }
4114
4115 static void __devinit sisfb_post_sis300(struct pci_dev *pdev)
4116 {
4117 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4118 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4119 u16 index, rindex, memtype = 0;
4120
4121 outSISIDXREG(SISSR,0x05,0x86);
4122
4123 if(ivideo->sishw_ext.UseROM) {
4124 if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80) {
4125 memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4126 } else {
4127 inSISIDXREG(SISSR,0x3a,memtype);
4128 }
4129 memtype &= 0x07;
4130 }
4131
4132 if(ivideo->revision_id <= 0x13) {
4133 v1 = 0x44; v2 = 0x42; v3 = 0x80;
4134 v4 = 0x44; v5 = 0x42; v6 = 0x80;
4135 } else {
4136 v1 = 0x68; v2 = 0x43; v3 = 0x80; /* Assume 125Mhz MCLK */
4137 v4 = 0x68; v5 = 0x43; v6 = 0x80; /* Assume 125Mhz ECLK */
4138 if(ivideo->sishw_ext.UseROM) {
4139 index = memtype * 5;
4140 rindex = index + 0x54;
4141 v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4142 v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4143 v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4144 rindex = index + 0x7c;
4145 v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4146 v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4147 v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4148 }
4149 }
4150 outSISIDXREG(SISSR,0x28,v1);
4151 outSISIDXREG(SISSR,0x29,v2);
4152 outSISIDXREG(SISSR,0x2a,v3);
4153 outSISIDXREG(SISSR,0x2e,v4);
4154 outSISIDXREG(SISSR,0x2f,v5);
4155 outSISIDXREG(SISSR,0x30,v6);
4156 v1 = 0x10;
4157 if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0xa4];
4158 outSISIDXREG(SISSR,0x07,v1); /* DAC speed */
4159 outSISIDXREG(SISSR,0x11,0x0f); /* DDC, power save */
4160 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4161 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4162 if(ivideo->sishw_ext.UseROM) {
4163 memtype += 0xa5;
4164 v1 = ivideo->sishw_ext.pjVirtualRomBase[memtype];
4165 v2 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 8];
4166 v3 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 16];
4167 v4 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 24];
4168 v5 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 32];
4169 v6 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 40];
4170 v7 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 48];
4171 v8 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 56];
4172 }
4173 if(ivideo->revision_id >= 0x80) v3 &= 0xfd;
4174 outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4175 outSISIDXREG(SISSR,0x16,v2);
4176 outSISIDXREG(SISSR,0x17,v3);
4177 outSISIDXREG(SISSR,0x18,v4);
4178 outSISIDXREG(SISSR,0x19,v5);
4179 outSISIDXREG(SISSR,0x1a,v6);
4180 outSISIDXREG(SISSR,0x1b,v7);
4181 outSISIDXREG(SISSR,0x1c,v8); /* ---- */
4182 andSISIDXREG(SISSR,0x15,0xfb);
4183 orSISIDXREG(SISSR,0x15,0x04);
4184 if(ivideo->sishw_ext.UseROM) {
4185 if(ivideo->sishw_ext.pjVirtualRomBase[0x53] & 0x02) {
4186 orSISIDXREG(SISSR,0x19,0x20);
4187 }
4188 }
4189 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4190 if(ivideo->revision_id >= 0x80) v1 |= 0x01;
4191 outSISIDXREG(SISSR,0x1f,v1);
4192 outSISIDXREG(SISSR,0x20,0xa0); /* linear & relocated io */
4193 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4194 if(ivideo->sishw_ext.UseROM) {
4195 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe8];
4196 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe9];
4197 v3 = ivideo->sishw_ext.pjVirtualRomBase[0xea];
4198 }
4199 outSISIDXREG(SISSR,0x23,v1);
4200 outSISIDXREG(SISSR,0x24,v2);
4201 outSISIDXREG(SISSR,0x25,v3);
4202 outSISIDXREG(SISSR,0x21,0x84);
4203 outSISIDXREG(SISSR,0x22,0x00);
4204 outSISIDXREG(SISCR,0x37,0x00);
4205 orSISIDXREG(SISPART1,0x24,0x01); /* unlock crt2 */
4206 outSISIDXREG(SISPART1,0x00,0x00);
4207 v1 = 0x40; v2 = 0x11;
4208 if(ivideo->sishw_ext.UseROM) {
4209 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xec];
4210 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xeb];
4211 }
4212 outSISIDXREG(SISPART1,0x02,v1);
4213 if(ivideo->revision_id >= 0x80) v2 &= ~0x01;
4214 inSISIDXREG(SISPART4,0x00,reg);
4215 if((reg == 1) || (reg == 2)) {
4216 outSISIDXREG(SISCR,0x37,0x02);
4217 outSISIDXREG(SISPART2,0x00,0x1c);
4218 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4219 if(ivideo->sishw_ext.UseROM) {
4220 v4 = ivideo->sishw_ext.pjVirtualRomBase[0xf5];
4221 v5 = ivideo->sishw_ext.pjVirtualRomBase[0xf6];
4222 v6 = ivideo->sishw_ext.pjVirtualRomBase[0xf7];
4223 }
4224 outSISIDXREG(SISPART4,0x0d,v4);
4225 outSISIDXREG(SISPART4,0x0e,v5);
4226 outSISIDXREG(SISPART4,0x10,v6);
4227 outSISIDXREG(SISPART4,0x0f,0x3f);
4228 inSISIDXREG(SISPART4,0x01,reg);
4229 if(reg >= 0xb0) {
4230 inSISIDXREG(SISPART4,0x23,reg);
4231 reg &= 0x20;
4232 reg <<= 1;
4233 outSISIDXREG(SISPART4,0x23,reg);
4234 }
4235 } else {
4236 v2 &= ~0x10;
4237 }
4238 outSISIDXREG(SISSR,0x32,v2);
4239 andSISIDXREG(SISPART1,0x24,0xfe); /* Lock CRT2 */
4240 inSISIDXREG(SISSR,0x16,reg);
4241 reg &= 0xc3;
4242 outSISIDXREG(SISCR,0x35,reg);
4243 outSISIDXREG(SISCR,0x83,0x00);
4244 #if !defined(__i386__) && !defined(__x86_64__)
4245 if(sisfb_videoram) {
4246 outSISIDXREG(SISSR,0x13,0x28); /* ? */
4247 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4248 outSISIDXREG(SISSR,0x14,reg);
4249 } else {
4250 #endif
4251 /* Need to map max FB size for finding out about RAM size */
4252 ivideo->sishw_ext.pjVideoMemoryAddress = ioremap(ivideo->video_base, 0x4000000);
4253 if(ivideo->sishw_ext.pjVideoMemoryAddress) {
4254 sisfb_setramsize300(pdev);
4255 iounmap(ivideo->sishw_ext.pjVideoMemoryAddress);
4256 } else {
4257 printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4258 outSISIDXREG(SISSR,0x13,0x28); /* ? */
4259 outSISIDXREG(SISSR,0x14,0x47); /* 8MB, 64bit default */
4260 }
4261 #if !defined(__i386__) && !defined(__x86_64__)
4262 }
4263 #endif
4264 if(ivideo->sishw_ext.UseROM) {
4265 v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe6];
4266 v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe7];
4267 } else {
4268 inSISIDXREG(SISSR,0x3a,reg);
4269 if((reg & 0x30) == 0x30) {
4270 v1 = 0x04; /* PCI */
4271 v2 = 0x92;
4272 } else {
4273 v1 = 0x14; /* AGP */
4274 v2 = 0xb2;
4275 }
4276 }
4277 outSISIDXREG(SISSR,0x21,v1);
4278 outSISIDXREG(SISSR,0x22,v2);
4279 }
4280 #endif
4281
4282 int __devinit sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
4283 {
4284 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
4285 struct sis_video_info *ivideo = NULL;
4286 struct fb_info *sis_fb_info = NULL;
4287 u16 reg16;
4288 u8 reg;
4289 int sisvga_enabled = 0, i;
4290
4291 if(sisfb_off) return -ENXIO;
4292
4293 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
4294 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
4295 if(!sis_fb_info) return -ENOMEM;
4296 #else
4297 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
4298 if(!sis_fb_info) return -ENOMEM;
4299 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
4300 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
4301 #endif
4302
4303 ivideo = (struct sis_video_info *)sis_fb_info->par;
4304 ivideo->memyselfandi = sis_fb_info;
4305
4306 if(card_list == NULL) {
4307 ivideo->cardnumber = 0;
4308 } else {
4309 struct sis_video_info *countvideo = card_list;
4310 ivideo->cardnumber = 1;
4311 while((countvideo = countvideo->next)) ivideo->cardnumber++;
4312 }
4313
4314 strncpy(ivideo->myid, chipinfo->chip_name, 30);
4315
4316 ivideo->chip_id = pdev->device;
4317 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
4318 ivideo->sishw_ext.jChipRevision = ivideo->revision_id;
4319 pci_read_config_word(pdev, PCI_COMMAND, ®16);
4320 sisvga_enabled = reg16 & 0x01;
4321 ivideo->pcibus = pdev->bus->number;
4322 ivideo->pcislot = PCI_SLOT(pdev->devfn);
4323 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
4324 ivideo->subsysvendor = pdev->subsystem_vendor;
4325 ivideo->subsysdevice = pdev->subsystem_device;
4326 #ifdef SIS_CONFIG_COMPAT
4327 ivideo->ioctl32registered = 0;
4328 ivideo->ioctl32vblankregistered = 0;
4329 #endif
4330
4331 #ifndef MODULE
4332 if(sisfb_mode_idx == -1) {
4333 sisfb_get_vga_mode_from_kernel();
4334 }
4335 #endif
4336
4337 ivideo->chip = chipinfo->chip;
4338 ivideo->sisvga_engine = chipinfo->vgaengine;
4339 ivideo->hwcursor_size = chipinfo->hwcursor_size;
4340 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
4341 ivideo->mni = chipinfo->mni;
4342
4343 ivideo->detectedpdc = 0xff;
4344 ivideo->detectedpdca = 0xff;
4345 ivideo->detectedlcda = 0xff;
4346
4347 ivideo->sisfb_thismonitor.datavalid = FALSE;
4348
4349 ivideo->sisfb_parm_mem = sisfb_parm_mem;
4350 ivideo->sisfb_accel = sisfb_accel;
4351 ivideo->sisfb_ypan = sisfb_ypan;
4352 ivideo->sisfb_max = sisfb_max;
4353 ivideo->sisfb_userom = sisfb_userom;
4354 ivideo->sisfb_useoem = sisfb_useoem;
4355 ivideo->sisfb_mode_idx = sisfb_mode_idx;
4356 ivideo->sisfb_parm_rate = sisfb_parm_rate;
4357 ivideo->sisfb_crt1off = sisfb_crt1off;
4358 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
4359 ivideo->sisfb_crt2type = sisfb_crt2type;
4360 ivideo->sisfb_crt2flags = sisfb_crt2flags;
4361 /* pdc(a), scalelcd, special timing, lvdshl handled below */
4362 ivideo->sisfb_dstn = sisfb_dstn;
4363 ivideo->sisfb_fstn = sisfb_fstn;
4364 ivideo->sisfb_tvplug = sisfb_tvplug;
4365 ivideo->sisfb_tvstd = sisfb_tvstd;
4366 ivideo->tvxpos = sisfb_tvxposoffset;
4367 ivideo->tvypos = sisfb_tvyposoffset;
4368 ivideo->sisfb_filter = sisfb_filter;
4369 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
4370 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4371 ivideo->sisfb_inverse = sisfb_inverse;
4372 #endif
4373
4374 ivideo->refresh_rate = 0;
4375 if(ivideo->sisfb_parm_rate != -1) {
4376 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
4377 }
4378
4379 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
4380 ivideo->SiS_Pr.CenterScreen = -1;
4381 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
4382 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
4383
4384 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
4385 ivideo->SiS_Pr.SiS_CHOverScan = -1;
4386 ivideo->SiS_Pr.SiS_ChSW = FALSE;
4387 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
4388 ivideo->SiS_Pr.HaveEMI = FALSE;
4389 ivideo->SiS_Pr.HaveEMILCD = FALSE;
4390 ivideo->SiS_Pr.OverruleEMI = FALSE;
4391 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
4392 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
4393 ivideo->SiS_Pr.PDC = -1;
4394 ivideo->SiS_Pr.PDCA = -1;
4395 #ifdef CONFIG_FB_SIS_315
4396 if(ivideo->chip >= SIS_330) {
4397 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
4398 if(ivideo->chip >= SIS_661) {
4399 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
4400 }
4401 }
4402 #endif
4403
4404 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
4405
4406 pci_set_drvdata(pdev, ivideo);
4407
4408 /* Patch special cases */
4409 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
4410 switch(ivideo->nbridge->device) {
4411 #ifdef CONFIG_FB_SIS_300
4412 case PCI_DEVICE_ID_SI_730:
4413 ivideo->chip = SIS_730;
4414 strcpy(ivideo->myid, "SiS 730");
4415 break;
4416 #endif
4417 #ifdef CONFIG_FB_SIS_315
4418 case PCI_DEVICE_ID_SI_651:
4419 /* ivideo->chip is ok */
4420 strcpy(ivideo->myid, "SiS 651");
4421 break;
4422 case PCI_DEVICE_ID_SI_740:
4423 ivideo->chip = SIS_740;
4424 strcpy(ivideo->myid, "SiS 740");
4425 break;
4426 case PCI_DEVICE_ID_SI_661:
4427 ivideo->chip = SIS_661;
4428 strcpy(ivideo->myid, "SiS 661");
4429 break;
4430 case PCI_DEVICE_ID_SI_741:
4431 ivideo->chip = SIS_741;
4432 strcpy(ivideo->myid, "SiS 741");
4433 break;
4434 case PCI_DEVICE_ID_SI_760:
4435 ivideo->chip = SIS_760;
4436 strcpy(ivideo->myid, "SiS 760");
4437 break;
4438 #endif
4439 }
4440 }
4441
4442 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4443 strcpy(sis_fb_info->modename, ivideo->myid);
4444 #endif
4445
4446 ivideo->sishw_ext.jChipType = ivideo->chip;
4447
4448 #ifdef CONFIG_FB_SIS_315
4449 if((ivideo->sishw_ext.jChipType == SIS_315PRO) ||
4450 (ivideo->sishw_ext.jChipType == SIS_315)) {
4451 ivideo->sishw_ext.jChipType = SIS_315H;
4452 }
4453 #endif
4454
4455 ivideo->video_base = pci_resource_start(pdev, 0);
4456 ivideo->mmio_base = pci_resource_start(pdev, 1);
4457 ivideo->mmio_size = pci_resource_len(pdev, 1);
4458 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
4459 ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
4460
4461 if(!sisvga_enabled) {
4462 if(pci_enable_device(pdev)) {
4463 pci_set_drvdata(pdev, NULL);
4464 kfree(sis_fb_info);
4465 return -EIO;
4466 }
4467 }
4468
4469 SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress);
4470
4471 #ifdef CONFIG_FB_SIS_300
4472 /* Find PCI systems for Chrontel/GPIO communication setup */
4473 if(ivideo->chip == SIS_630) {
4474 i=0;
4475 do {
4476 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
4477 mychswtable[i].subsysCard == ivideo->subsysdevice) {
4478 ivideo->SiS_Pr.SiS_ChSW = TRUE;
4479 printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
4480 mychswtable[i].vendorName, mychswtable[i].cardName);
4481 break;
4482 }
4483 i++;
4484 } while(mychswtable[i].subsysVendor != 0);
4485 }
4486 #endif
4487
4488 outSISIDXREG(SISSR, 0x05, 0x86);
4489
4490 if( (!sisvga_enabled)
4491 #if !defined(__i386__) && !defined(__x86_64__)
4492 || (sisfb_resetcard)
4493 #endif
4494 ) {
4495 for(i = 0x30; i <= 0x3f; i++) {
4496 outSISIDXREG(SISCR,i,0x00);
4497 }
4498 }
4499
4500 inSISIDXREG(SISCR,0x34,reg);
4501 ivideo->modeprechange = ((reg & 0x7f)) ? (reg & 0x7f) : 0x03;
4502 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4503 #ifdef MODULE
4504 if((reg & 0x80) && (reg != 0xff)) {
4505 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) {
4506 printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
4507 pci_set_drvdata(pdev, NULL);
4508 kfree(sis_fb_info);
4509 return -EBUSY;
4510 }
4511 }
4512 #endif
4513 #endif
4514
4515 ivideo->sishw_ext.bIntegratedMMEnabled = TRUE;
4516 #ifdef CONFIG_FB_SIS_300
4517 if(ivideo->sisvga_engine == SIS_300_VGA) {
4518 if(ivideo->chip != SIS_300) {
4519 inSISIDXREG(SISSR, 0x1a, reg);
4520 if(!(reg & 0x10)) {
4521 ivideo->sishw_ext.bIntegratedMMEnabled = FALSE;
4522 }
4523 }
4524 }
4525 #endif
4526
4527 ivideo->bios_vbase = ivideo->bios_abase = NULL;
4528 if(ivideo->sisfb_userom) {
4529 ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
4530 #if defined(__i386__) || defined(__x86_64__)
4531 ivideo->bios_vbase = ivideo->sishw_ext.pjVirtualRomBase; /* mapped */
4532 #else
4533 ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase; /* allocated */
4534 #endif
4535 if(ivideo->sishw_ext.pjVirtualRomBase) {
4536 printk(KERN_INFO "sisfb: Video ROM found and %s to 0x%p\n",
4537 ivideo->bios_vbase ? "mapped" : "copied",
4538 ivideo->sishw_ext.pjVirtualRomBase);
4539 ivideo->sishw_ext.UseROM = TRUE;
4540 } else {
4541 ivideo->sishw_ext.UseROM = FALSE;
4542 printk(KERN_INFO "sisfb: Video ROM not found\n");
4543 }
4544 } else {
4545 ivideo->sishw_ext.pjVirtualRomBase = NULL;
4546 ivideo->sishw_ext.UseROM = FALSE;
4547 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
4548 }
4549
4550 /* Find systems for special custom timing */
4551 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
4552 int j;
4553 unsigned char *biosver = NULL;
4554 unsigned char *biosdate = NULL;
4555 BOOLEAN footprint;
4556 u32 chksum = 0;
4557
4558 if(ivideo->sishw_ext.UseROM) {
4559 biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
4560 biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
4561 for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
4562 }
4563
4564 i=0;
4565 do {
4566 if( (mycustomttable[i].chipID == ivideo->chip) &&
4567 ((!strlen(mycustomttable[i].biosversion)) ||
4568 (ivideo->sishw_ext.UseROM &&
4569 (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
4570 ((!strlen(mycustomttable[i].biosdate)) ||
4571 (ivideo->sishw_ext.UseROM &&
4572 (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
4573 ((!mycustomttable[i].bioschksum) ||
4574 (ivideo->sishw_ext.UseROM &&
4575 (mycustomttable[i].bioschksum == chksum))) &&
4576 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
4577 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
4578 footprint = TRUE;
4579 for(j = 0; j < 5; j++) {
4580 if(mycustomttable[i].biosFootprintAddr[j]) {
4581 if(ivideo->sishw_ext.UseROM) {
4582 if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
4583 mycustomttable[i].biosFootprintData[j]) {
4584 footprint = FALSE;
4585 }
4586 } else footprint = FALSE;
4587 }
4588 }
4589 if(footprint) {
4590 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
4591 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
4592 mycustomttable[i].vendorName,
4593 mycustomttable[i].cardName);
4594 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
4595 mycustomttable[i].optionName);
4596 break;
4597 }
4598 }
4599 i++;
4600 } while(mycustomttable[i].chipID);
4601 }
4602
4603 #ifdef CONFIG_FB_SIS_300
4604 if(ivideo->sisvga_engine == SIS_300_VGA) {
4605 if( (!sisvga_enabled)
4606 #if !defined(__i386__) && !defined(__x86_64__)
4607 || (sisfb_resetcard)
4608 #endif
4609 ) {
4610 if(ivideo->chip == SIS_300) sisfb_post_sis300(pdev);
4611 }
4612 }
4613 #endif
4614
4615 #ifdef CONFIG_FB_SIS_315
4616 if(ivideo->sisvga_engine == SIS_315_VGA) {
4617 if( (!sisvga_enabled)
4618 #if !defined(__i386__) && !defined(__x86_64__)
4619 || (sisfb_resetcard)
4620 #endif
4621 ) {
4622 if((ivideo->sisfb_mode_idx < 0) ||
4623 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
4624 /* TODO: POSTing 315/330 not supported yet */
4625 }
4626 }
4627 }
4628 #endif
4629
4630 if(sisfb_get_dram_size(ivideo)) {
4631 printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
4632 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
4633 pci_set_drvdata(pdev, NULL);
4634 kfree(sis_fb_info);
4635 return -ENODEV;
4636 }
4637
4638 if((ivideo->sisfb_mode_idx < 0) ||
4639 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
4640 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
4641 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
4642 /* Enable 2D accelerator engine */
4643 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
4644 }
4645
4646
4647
4648 if(sisfb_pdc != 0xff) {
4649 if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
4650 else sisfb_pdc &= 0x1f;
4651 ivideo->SiS_Pr.PDC = sisfb_pdc;
4652 }
4653 #ifdef CONFIG_FB_SIS_315
4654 if(ivideo->sisvga_engine == SIS_315_VGA) {
4655 if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
4656 }
4657 #endif
4658
4659 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
4660 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
4661 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
4662 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
4663 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
4664 pci_set_drvdata(pdev, NULL);
4665 kfree(sis_fb_info);
4666 return -ENODEV;
4667 }
4668
4669 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
4670 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
4671 release_mem_region(ivideo->video_base, ivideo->video_size);
4672 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
4673 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
4674 pci_set_drvdata(pdev, NULL);
4675 kfree(sis_fb_info);
4676 return -ENODEV;
4677 }
4678
4679 ivideo->video_vbase = (unsigned long)ioremap(ivideo->video_base, ivideo->video_size);
4680 ivideo->sishw_ext.pjVideoMemoryAddress = (unsigned char *)ivideo->video_vbase;
4681 if(!ivideo->video_vbase) {
4682 printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
4683 release_mem_region(ivideo->video_base, ivideo->video_size);
4684 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
4685 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
4686 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
4687 pci_set_drvdata(pdev, NULL);
4688 kfree(sis_fb_info);
4689 return -ENODEV;
4690 }
4691
4692 ivideo->mmio_vbase = (unsigned long)ioremap(ivideo->mmio_base, ivideo->mmio_size);
4693 if(!ivideo->mmio_vbase) {
4694 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
4695 iounmap((void *)ivideo->video_vbase);
4696 release_mem_region(ivideo->video_base, ivideo->video_size);
4697 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
4698 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
4699 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
4700 pci_set_drvdata(pdev, NULL);
4701 kfree(sis_fb_info);
4702 return -ENODEV;
4703 }
4704
4705 printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n",
4706 ivideo->video_base, ivideo->video_vbase, ivideo->video_size / 1024);
4707
4708 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
4709 ivideo->mmio_base, ivideo->mmio_vbase, ivideo->mmio_size / 1024);
4710
4711 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
4712 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
4713 }
4714
4715 /* Used for clearing the screen only, therefore respect our mem limit */
4716 ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
4717
4718 ivideo->mtrr = 0;
4719
4720 ivideo->vbflags = 0;
4721 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
4722 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
4723 ivideo->defmodeidx = DEFAULT_MODE;
4724
4725 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
4726
4727 if((ivideo->sisfb_mode_idx < 0) ||
4728 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
4729
4730 sisfb_sense_crt1(ivideo);
4731
4732 sisfb_get_VB_type(ivideo);
4733
4734 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
4735 sisfb_detect_VB_connect(ivideo);
4736 }
4737
4738 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
4739
4740 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
4741 if(ivideo->sisfb_crt2type != -1) {
4742 if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
4743 ivideo->currentvbflags |= CRT2_LCD;
4744 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
4745 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
4746 }
4747 } else {
4748 /* Chrontel 700x TV detection often unreliable, therefore use a
4749 * different default order on such machines
4750 */
4751 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
4752 if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
4753 else if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
4754 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
4755 } else {
4756 if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV;
4757 else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
4758 else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
4759 }
4760 }
4761 }
4762
4763 if(ivideo->vbflags & CRT2_LCD) {
4764 inSISIDXREG(SISCR, 0x36, reg);
4765 reg &= 0x0f;
4766 if(ivideo->sisvga_engine == SIS_300_VGA) {
4767 ivideo->sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
4768 } else if(ivideo->chip >= SIS_661) {
4769 ivideo->sishw_ext.ulCRT2LCDType = sis661paneltype[reg];
4770 } else {
4771 ivideo->sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
4772 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
4773 if((ivideo->sishw_ext.ulCRT2LCDType != LCD_640x480_2) &&
4774 (ivideo->sishw_ext.ulCRT2LCDType != LCD_640x480_3)) {
4775 ivideo->sishw_ext.ulCRT2LCDType = LCD_320x480;
4776 }
4777 }
4778 }
4779 if(ivideo->sishw_ext.ulCRT2LCDType == LCD_UNKNOWN) {
4780 ivideo->sishw_ext.ulCRT2LCDType = LCD_1024x768;
4781 printk(KERN_DEBUG "sisfb: Illegal panel ID (%02x), assuming 1024x768\n", reg);
4782 }
4783 for(i = 0; i < SIS_LCD_NUMBER; i++) {
4784 if(ivideo->sishw_ext.ulCRT2LCDType == sis_lcd_data[i].lcdtype) {
4785 ivideo->lcdxres = sis_lcd_data[i].xres;
4786 ivideo->lcdyres = sis_lcd_data[i].yres;
4787 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
4788 break;
4789 }
4790 }
4791 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
4792 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
4793 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
4794 ivideo->lcdxres = 848; ivideo->lcdyres = 480; ivideo->lcddefmodeidx = 47;
4795 }
4796 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
4797 ivideo->lcdxres, ivideo->lcdyres);
4798 }
4799
4800 #ifdef CONFIG_FB_SIS_300
4801 /* Save the current PanelDelayCompensation if the LCD is currently used */
4802 if(ivideo->sisvga_engine == SIS_300_VGA) {
4803 if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
4804 int tmp;
4805 inSISIDXREG(SISCR,0x30,tmp);
4806 if(tmp & 0x20) {
4807 /* Currently on LCD? If yes, read current pdc */
4808 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
4809 ivideo->detectedpdc &= 0x3c;
4810 if(ivideo->SiS_Pr.PDC == -1) {
4811 /* Let option override detection */
4812 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
4813 }
4814 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
4815 ivideo->detectedpdc);
4816 }
4817 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
4818 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
4819 ivideo->SiS_Pr.PDC);
4820 }
4821 }
4822 }
4823 #endif
4824
4825 #ifdef CONFIG_FB_SIS_315
4826 if(ivideo->sisvga_engine == SIS_315_VGA) {
4827
4828 /* Try to find about LCDA */
4829 if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
4830 int tmp;
4831 inSISIDXREG(SISPART1,0x13,tmp);
4832 if(tmp & 0x04) {
4833 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
4834 ivideo->detectedlcda = 0x03;
4835 printk(KERN_DEBUG
4836 "sisfb: BIOS uses LCDA for low resolution and text modes\n");
4837 }
4838 }
4839
4840 /* Save PDC */
4841 if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
4842 int tmp;
4843 inSISIDXREG(SISCR,0x30,tmp);
4844 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
4845 /* Currently on LCD? If yes, read current pdc */
4846 u8 pdc;
4847 inSISIDXREG(SISPART1,0x2D,pdc);
4848 ivideo->detectedpdc = (pdc & 0x0f) << 1;
4849 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
4850 inSISIDXREG(SISPART1,0x35,pdc);
4851 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
4852 inSISIDXREG(SISPART1,0x20,pdc);
4853 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
4854 if(ivideo->newrom) {
4855 /* New ROM invalidates other PDC resp. */
4856 if(ivideo->detectedlcda != 0xff) {
4857 ivideo->detectedpdc = 0xff;
4858 } else {
4859 ivideo->detectedpdca = 0xff;
4860 }
4861 }
4862 if(ivideo->SiS_Pr.PDC == -1) {
4863 if(ivideo->detectedpdc != 0xff) {
4864 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
4865 }
4866 }
4867 if(ivideo->SiS_Pr.PDCA == -1) {
4868 if(ivideo->detectedpdca != 0xff) {
4869 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
4870 }
4871 }
4872 if(ivideo->detectedpdc != 0xff) {
4873 printk(KERN_INFO
4874 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
4875 ivideo->detectedpdc);
4876 }
4877 if(ivideo->detectedpdca != 0xff) {
4878 printk(KERN_INFO
4879 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
4880 ivideo->detectedpdca);
4881 }
4882 }
4883
4884 /* Save EMI */
4885 if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
4886 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
4887 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
4888 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
4889 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
4890 ivideo->SiS_Pr.HaveEMI = TRUE;
4891 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
4892 ivideo->SiS_Pr.HaveEMILCD = TRUE;
4893 }
4894 }
4895 }
4896
4897 /* Let user override detected PDCs (all bridges) */
4898 if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
4899 if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
4900 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
4901 ivideo->SiS_Pr.PDC);
4902 }
4903 if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
4904 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
4905 ivideo->SiS_Pr.PDCA);
4906 }
4907 }
4908
4909 }
4910 #endif
4911
4912 if(!ivideo->sisfb_crt1off) {
4913 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
4914 } else {
4915 if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
4916 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
4917 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
4918 }
4919 }
4920
4921 if(ivideo->sisfb_mode_idx >= 0) {
4922 int bu = ivideo->sisfb_mode_idx;
4923 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
4924 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
4925 if(bu != ivideo->sisfb_mode_idx) {
4926 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
4927 sisbios_mode[bu].xres,
4928 sisbios_mode[bu].yres,
4929 sisbios_mode[bu].bpp);
4930 }
4931 }
4932
4933 if(ivideo->sisfb_mode_idx < 0) {
4934 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
4935 case CRT2_LCD:
4936 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
4937 break;
4938 case CRT2_TV:
4939 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
4940 break;
4941 default:
4942 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
4943 break;
4944 }
4945 }
4946
4947 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
4948
4949 if(ivideo->refresh_rate != 0) {
4950 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
4951 }
4952
4953 if(ivideo->rate_idx == 0) {
4954 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
4955 ivideo->refresh_rate = 60;
4956 }
4957
4958 if(ivideo->sisfb_thismonitor.datavalid) {
4959 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
4960 ivideo->rate_idx, ivideo->refresh_rate)) {
4961 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
4962 }
4963 }
4964
4965 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
4966 ivideo->video_vwidth = ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
4967 ivideo->video_vheight = ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
4968 ivideo->org_x = ivideo->org_y = 0;
4969 ivideo->video_linelength = ivideo->video_width * (ivideo->video_bpp >> 3);
4970
4971 sisfb_set_vparms(ivideo);
4972
4973 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4974
4975 /* ---------------- For 2.4: Now switch the mode ------------------ */
4976
4977 printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
4978 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
4979 ivideo->refresh_rate);
4980
4981 sisfb_pre_setmode(ivideo);
4982
4983 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
4984 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
4985 ivideo->mode_no);
4986 iounmap((void *)ivideo->video_vbase);
4987 iounmap((void *)ivideo->mmio_vbase);
4988 release_mem_region(ivideo->video_base, ivideo->video_size);
4989 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
4990 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
4991 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
4992 pci_set_drvdata(pdev, NULL);
4993 kfree(sis_fb_info);
4994 return -EINVAL;
4995 }
4996
4997 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
4998
4999 sisfb_post_setmode(ivideo);
5000
5001 ivideo->accel = 0;
5002 if(ivideo->sisfb_accel) {
5003 ivideo->accel = -1;
5004 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5005 sisfb_initaccel(ivideo);
5006 }
5007
5008 /* Maximize regardless of sisfb_max at startup */
5009 ivideo->default_var.yres_virtual = 32767;
5010 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
5011
5012 sis_fb_info->node = -1;
5013 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5014 sis_fb_info->fbops = &sisfb_ops;
5015 sis_fb_info->disp = &ivideo->sis_disp;
5016 sis_fb_info->blank = &sisfb_blank;
5017 sis_fb_info->switch_con = &sisfb_switch;
5018 sis_fb_info->updatevar = &sisfb_update_var;
5019 sis_fb_info->changevar = NULL;
5020 strcpy(sis_fb_info->fontname, sisfb_fontname);
5021
5022 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
5023
5024 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
5025
5026 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
5027 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5028 ivideo->refresh_rate);
5029
5030 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
5031 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
5032 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
5033
5034 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
5035
5036 ivideo->default_var.pixclock = (u32) (1000000000 /
5037 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5038 ivideo->mode_no, ivideo->rate_idx));
5039
5040 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5041 ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
5042 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
5043 ivideo->default_var.pixclock <<= 1;
5044 }
5045 }
5046
5047 ivideo->accel = 0;
5048 if(ivideo->sisfb_accel) {
5049 ivideo->accel = -1;
5050 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5051 sisfb_initaccel(ivideo);
5052 }
5053
5054 if(ivideo->sisfb_ypan) {
5055 /* Maximize regardless of sisfb_max at startup */
5056 ivideo->default_var.yres_virtual =
5057 ivideo->heapstart /
5058 (ivideo->default_var.xres * (ivideo->default_var.bits_per_pixel >> 3));
5059 if(ivideo->default_var.yres_virtual > 32767) ivideo->default_var.yres_virtual = 32767;
5060 if(ivideo->default_var.yres_virtual <= ivideo->default_var.yres) {
5061 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
5062 }
5063 }
5064
5065 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5066 sis_fb_info->var = ivideo->default_var;
5067 sis_fb_info->fix = ivideo->sisfb_fix;
5068 sis_fb_info->screen_base = (char *)ivideo->video_vbase;
5069 sis_fb_info->fbops = &sisfb_ops;
5070
5071 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
5072 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
5073
5074 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
5075 #endif /* 2.6 */
5076
5077 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
5078
5079 #ifdef CONFIG_MTRR
5080 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
5081 MTRR_TYPE_WRCOMB, 1);
5082 if(!ivideo->mtrr) {
5083 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
5084 }
5085 #endif
5086
5087 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5088 vc_resize_con(1, 1, 0);
5089 #endif
5090
5091 if(register_framebuffer(sis_fb_info) < 0) {
5092 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
5093 iounmap((void *)ivideo->video_vbase);
5094 iounmap((void *)ivideo->mmio_vbase);
5095 release_mem_region(ivideo->video_base, ivideo->video_size);
5096 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5097 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5098 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5099 pci_set_drvdata(pdev, NULL);
5100 kfree(sis_fb_info);
5101 return -EINVAL;
5102 }
5103
5104 ivideo->registered = 1;
5105
5106 /* Enlist us */
5107 ivideo->next = card_list;
5108 card_list = ivideo;
5109
5110 #ifdef SIS_CONFIG_COMPAT
5111 {
5112 int ret;
5113 /* Our ioctls are all "32/64bit compatible" */
5114 if(register_ioctl32_conversion(FBIOGET_VBLANK, NULL)) {
5115 printk(KERN_ERR "sisfb: Error registering FBIOGET_VBLANK ioctl32 translation\n");
5116 } else {
5117 ivideo->ioctl32vblankregistered = 1;
5118 }
5119 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
5120 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
5121 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
5122 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
5123 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
5124 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
5125 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
5126 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
5127 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
5128 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
5129 if(ret) printk(KERN_ERR "sisfb: Error registering ioctl32 translations\n");
5130 else ivideo->ioctl32registered = 1;
5131 }
5132 #endif
5133
5134 #if 0
5135 printk(KERN_DEBUG "sisfb: Installed SISFB_GET_INFO_SIZE ioctl (%x)\n", SISFB_GET_INFO_SIZE);
5136 printk(KERN_DEBUG "sisfb: Installed SISFB_GET_INFO ioctl (%x)\n", SISFB_GET_INFO);
5137 printk(KERN_DEBUG "sisfb: Installed SISFB_GET_VBRSTATUS ioctl (%x)\n", SISFB_GET_VBRSTATUS);
5138 printk(KERN_DEBUG "sisfb: Installed SISFB_GET_TVPOSOFFSET ioctl (%x)\n", SISFB_GET_TVPOSOFFSET);
5139 printk(KERN_DEBUG "sisfb: Installed SISFB_SET_TVPOSOFFSET ioctl (%x)\n", SISFB_SET_TVPOSOFFSET);
5140 #endif
5141
5142 printk(KERN_INFO "sisfb: 2D acceleration is %s, scroll-mode %s\n",
5143 ivideo->sisfb_accel ? "enabled" : "disabled",
5144 ivideo->sisfb_ypan ?
5145 (ivideo->sisfb_max ? "ypan (auto-max)" : "ypan (no auto-max)") : "redraw");
5146
5147
5148 printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n",
5149 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5150 GET_FB_IDX(sis_fb_info->node),
5151 #else
5152 sis_fb_info->node,
5153 #endif
5154 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
5155
5156 printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
5157
5158 } /* if mode = "none" */
5159
5160 return 0;
5161 }
5162
5163 /*****************************************************/
5164 /* PCI DEVICE HANDLING */
5165 /*****************************************************/
5166
5167 static void __devexit sisfb_remove(struct pci_dev *pdev)
5168 {
5169 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5170 struct fb_info *sis_fb_info = ivideo->memyselfandi;
5171 int registered = ivideo->registered;
5172
5173 #ifdef SIS_CONFIG_COMPAT
5174 if(ivideo->ioctl32vblankregistered) {
5175 if(unregister_ioctl32_conversion(FBIOGET_VBLANK)) {
5176 printk(KERN_ERR "sisfb: Error unregistering FBIOGET_VBLANK ioctl32 translation\n");
5177 }
5178 }
5179 if(ivideo->ioctl32registered) {
5180 int ret;
5181 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
5182 ret |= unregister_ioctl32_conversion(FBIO_FREE);
5183 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
5184 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
5185 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
5186 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
5187 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
5188 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
5189 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
5190 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
5191 if(ret) printk(KERN_ERR "sisfb: Error unregistering ioctl32 translations\n");
5192 }
5193 #endif
5194
5195 /* Unmap */
5196 iounmap((void *)ivideo->video_vbase);
5197 iounmap((void *)ivideo->mmio_vbase);
5198 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5199 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5200
5201 /* Release mem regions */
5202 release_mem_region(ivideo->video_base, ivideo->video_size);
5203 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5204
5205 #ifdef CONFIG_MTRR
5206 /* Release MTRR region */
5207 if(ivideo->mtrr) {
5208 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
5209 }
5210 #endif
5211
5212 /* Unregister the framebuffer */
5213 if(ivideo->registered) {
5214 unregister_framebuffer(sis_fb_info);
5215 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5216 framebuffer_release(sis_fb_info);
5217 #else
5218 kfree(sis_fb_info);
5219 #endif
5220 }
5221
5222 pci_set_drvdata(pdev, NULL);
5223
5224 /* TODO: Restore the initial mode
5225 * This sounds easy but is as good as impossible
5226 * on many machines with SiS chip and video bridge
5227 * since text modes are always set up differently
5228 * from machine to machine. Depends on the type
5229 * of integration between chipset and bridge.
5230 */
5231 if(registered) {
5232 printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
5233 }
5234 };
5235
5236 static struct pci_driver sisfb_driver = {
5237 .name = "sisfb",
5238 .id_table = sisfb_pci_table,
5239 .probe = sisfb_probe,
5240 .remove = __devexit_p(sisfb_remove)
5241 };
5242
5243 int __init sisfb_init(void)
5244 {
5245 return(pci_module_init(&sisfb_driver));
5246 }
5247
5248 /*****************************************************/
5249 /* MODULE */
5250 /*****************************************************/
5251
5252 #ifdef MODULE
5253
5254 static char *mode = NULL;
5255 static int vesa = -1;
5256 static unsigned int rate = 0;
5257 static unsigned int crt1off = 1;
5258 static unsigned int mem = 0;
5259 static char *forcecrt2type = NULL;
5260 static int forcecrt1 = -1;
5261 static int pdc = -1;
5262 static int pdc1 = -1;
5263 static int noaccel = -1;
5264 static int noypan = -1;
5265 static int nomax = -1;
5266 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5267 static int inverse = 0;
5268 #endif
5269 static int userom = -1;
5270 static int useoem = -1;
5271 static char *tvstandard = NULL;
5272 static int nocrt2rate = 0;
5273 static int scalelcd = -1;
5274 static char *specialtiming = NULL;
5275 static int lvdshl = -1;
5276 static int tvxposoffset = 0, tvyposoffset = 0;
5277 static int filter = -1;
5278 #if !defined(__i386__) && !defined(__x86_64__)
5279 static int resetcard = 0;
5280 static int videoram = 0;
5281 #endif
5282
5283 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
5284 MODULE_LICENSE("GPL");
5285 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
5286
5287 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5288 MODULE_PARM(mem, "i");
5289 MODULE_PARM(noaccel, "i");
5290 MODULE_PARM(noypan, "i");
5291 MODULE_PARM(nomax, "i");
5292 MODULE_PARM(userom, "i");
5293 MODULE_PARM(useoem, "i");
5294 MODULE_PARM(mode, "s");
5295 MODULE_PARM(vesa, "i");
5296 MODULE_PARM(rate, "i");
5297 MODULE_PARM(forcecrt1, "i");
5298 MODULE_PARM(forcecrt2type, "s");
5299 MODULE_PARM(scalelcd, "i");
5300 MODULE_PARM(pdc, "i");
5301 MODULE_PARM(pdc1, "i");
5302 MODULE_PARM(specialtiming, "s");
5303 MODULE_PARM(lvdshl, "i");
5304 MODULE_PARM(tvstandard, "s");
5305 MODULE_PARM(tvxposoffset, "i");
5306 MODULE_PARM(tvyposoffset, "i");
5307 MODULE_PARM(filter, "i");
5308 MODULE_PARM(nocrt2rate, "i");
5309 MODULE_PARM(inverse, "i");
5310 #if !defined(__i386__) && !defined(__x86_64__)
5311 MODULE_PARM(resetcard, "i");
5312 MODULE_PARM(videoram, "i");
5313 #endif
5314 #endif
5315
5316 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5317 module_param(mem, int, 0);
5318 module_param(noaccel, int, 0);
5319 module_param(noypan, int, 0);
5320 module_param(nomax, int, 0);
5321 module_param(userom, int, 0);
5322 module_param(useoem, int, 0);
5323 module_param(mode, charp, 0);
5324 module_param(vesa, int, 0);
5325 module_param(rate, int, 0);
5326 module_param(forcecrt1, int, 0);
5327 module_param(forcecrt2type, charp, 0);
5328 module_param(scalelcd, int, 0);
5329 module_param(pdc, int, 0);
5330 module_param(pdc1, int, 0);
5331 module_param(specialtiming, charp, 0);
5332 module_param(lvdshl, int, 0);
5333 module_param(tvstandard, charp, 0);
5334 module_param(tvxposoffset, int, 0);
5335 module_param(tvyposoffset, int, 0);
5336 module_param(filter, int, 0);
5337 module_param(nocrt2rate, int, 0);
5338 #if !defined(__i386__) && !defined(__x86_64__)
5339 module_param(resetcard, int, 0);
5340 module_param(videoram, int, 0);
5341 #endif
5342 #endif
5343
5344 MODULE_PARM_DESC(mem,
5345 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
5346 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
5347 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
5348 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
5349 "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
5350 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
5351 "for XFree86 4.x/X.org 6.7 and later.\n");
5352
5353 MODULE_PARM_DESC(noaccel,
5354 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
5355 "(default: 0)\n");
5356
5357 MODULE_PARM_DESC(noypan,
5358 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
5359 "will be performed by redrawing the screen. (default: 0)\n");
5360
5361 MODULE_PARM_DESC(nomax,
5362 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
5363 "memory for the virtual screen in order to optimize scrolling performance. If\n"
5364 "this is set to anything other than 0, sisfb will not do this and thereby \n"
5365 "enable the user to positively specify a virtual Y size of the screen using\n"
5366 "fbset. (default: 0)\n");
5367
5368 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5369 MODULE_PARM_DESC(mode,
5370 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
5371 "1024x768x16. Other formats supported include XxY-Depth and\n"
5372 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5373 "number, it will be interpreted as a VESA mode number. (default: none if\n"
5374 "sisfb is a module; this leaves the console untouched and the driver will\n"
5375 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
5376 "is in the kernel)\n");
5377 MODULE_PARM_DESC(vesa,
5378 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
5379 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
5380 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
5381 "0x0103 if sisfb is in the kernel)\n");
5382 #endif
5383
5384 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5385 MODULE_PARM_DESC(mode,
5386 "\nSelects the desired default display mode in the format XxYxDepth,\n"
5387 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
5388 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5389 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
5390
5391 MODULE_PARM_DESC(vesa,
5392 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
5393 "0x117 (default: 0x0103)\n");
5394 #endif
5395
5396 MODULE_PARM_DESC(rate,
5397 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
5398 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
5399 "will be ignored (default: 60)\n");
5400
5401 MODULE_PARM_DESC(forcecrt1,
5402 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
5403 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
5404 "0=CRT1 OFF) (default: [autodetected])\n");
5405
5406 MODULE_PARM_DESC(forcecrt2type,
5407 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
5408 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
5409 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
5410 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
5411 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
5412 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
5413 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
5414 "depends on the very hardware in use. (default: [autodetected])\n");
5415
5416 MODULE_PARM_DESC(scalelcd,
5417 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
5418 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
5419 "show black bars around the image, TMDS panels will probably do the scaling\n"
5420 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
5421
5422 MODULE_PARM_DESC(pdc,
5423 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
5424 "should detect this correctly in most cases; however, sometimes this is not\n"
5425 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
5426 "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
5427 "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
5428 "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
5429
5430 #ifdef CONFIG_FB_SIS_315
5431 MODULE_PARM_DESC(pdc1,
5432 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
5433 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
5434 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
5435 "implemented yet.\n");
5436 #endif
5437
5438 MODULE_PARM_DESC(specialtiming,
5439 "\nPlease refer to documentation for more information on this option.\n");
5440
5441 MODULE_PARM_DESC(lvdshl,
5442 "\nPlease refer to documentation for more information on this option.\n");
5443
5444 MODULE_PARM_DESC(tvstandard,
5445 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
5446 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
5447
5448 MODULE_PARM_DESC(tvxposoffset,
5449 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
5450 "Default: 0\n");
5451
5452 MODULE_PARM_DESC(tvyposoffset,
5453 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
5454 "Default: 0\n");
5455
5456 MODULE_PARM_DESC(filter,
5457 "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
5458 "(Possible values 0-7, default: [no filter])\n");
5459
5460 MODULE_PARM_DESC(nocrt2rate,
5461 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
5462 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
5463
5464 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5465 MODULE_PARM_DESC(inverse,
5466 "\nSetting this to anything but 0 should invert the display colors, but this\n"
5467 "does not seem to work. (default: 0)\n");
5468 #endif
5469
5470 #if !defined(__i386__) && !defined(__x86_64__)
5471 #ifdef CONFIG_FB_SIS_300
5472 MODULE_PARM_DESC(resetcard,
5473 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
5474 "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
5475 "Default: 0\n");
5476
5477 MODULE_PARM_DESC(videoram,
5478 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
5479 "some non-x86 architectures where the memory auto detection fails. Only\n"
5480 "relevant if resetcard is set, too. Default: [auto-detect]\n");
5481 #endif
5482 #endif
5483
5484 int __init sisfb_init_module(void)
5485 {
5486 sisfb_setdefaultparms();
5487
5488 if(rate) sisfb_parm_rate = rate;
5489
5490 if((scalelcd == 0) || (scalelcd == 1)) {
5491 sisfb_scalelcd = scalelcd ^ 1;
5492 }
5493
5494 /* Need to check crt2 type first for fstn/dstn */
5495
5496 if(forcecrt2type)
5497 sisfb_search_crt2type(forcecrt2type);
5498
5499 if(tvstandard)
5500 sisfb_search_tvstd(tvstandard);
5501
5502 if(mode)
5503 sisfb_search_mode(mode, FALSE);
5504 else if(vesa != -1)
5505 sisfb_search_vesamode(vesa, FALSE);
5506
5507 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
5508
5509 sisfb_forcecrt1 = forcecrt1;
5510 if(forcecrt1 == 1) sisfb_crt1off = 0;
5511 else if(forcecrt1 == 0) sisfb_crt1off = 1;
5512
5513 if(noaccel == 1) sisfb_accel = 0;
5514 else if(noaccel == 0) sisfb_accel = 1;
5515
5516 if(noypan == 1) sisfb_ypan = 0;
5517 else if(noypan == 0) sisfb_ypan = 1;
5518
5519 if(nomax == 1) sisfb_max = 0;
5520 else if(nomax == 0) sisfb_max = 1;
5521
5522 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5523 if(inverse) sisfb_inverse = 1;
5524 #endif
5525
5526 if(mem) sisfb_parm_mem = mem;
5527
5528 if(userom != -1) sisfb_userom = userom;
5529 if(useoem != -1) sisfb_useoem = useoem;
5530
5531 if(pdc != -1) sisfb_pdc = (pdc & 0x7f);
5532 if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
5533
5534 sisfb_nocrt2rate = nocrt2rate;
5535
5536 if(specialtiming)
5537 sisfb_search_specialtiming(specialtiming);
5538
5539 if((lvdshl >= 0) && (lvdshl <= 3)) sisfb_lvdshl = lvdshl;
5540
5541 if(filter != -1) sisfb_filter = filter;
5542
5543 sisfb_tvxposoffset = tvxposoffset;
5544 sisfb_tvyposoffset = tvyposoffset;
5545
5546 #if !defined(__i386__) && !defined(__x86_64__)
5547 sisfb_resetcard = (resetcard) ? 1 : 0;
5548 if(videoram) sisfb_videoram = videoram;
5549 #endif
5550
5551 return(sisfb_init());
5552 }
5553
5554 static void __exit sisfb_remove_module(void)
5555 {
5556 pci_unregister_driver(&sisfb_driver);
5557 printk(KERN_DEBUG "sisfb: Module unloaded\n");
5558 }
5559
5560 module_init(sisfb_init_module);
5561 module_exit(sisfb_remove_module);
5562
5563 #endif /* /MODULE */
5564
5565 EXPORT_SYMBOL(sis_malloc);
5566 EXPORT_SYMBOL(sis_free);
5567
5568
5569