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
6 * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
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.
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.
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
22 * Author: Thomas Winischhofer <thomas@winischhofer.net>
24 * Author of (practically wiped) code base:
26 * Copyright (C) 1999 Silicon Integrated Systems, Inc.
28 * See http://www.winischhofer.net/ for more information and updates
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>
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>
41 #include <linux/kernel.h>
42 #include <linux/spinlock.h>
43 #include <linux/errno.h>
44 #include <linux/string.h>
46 #include <linux/tty.h>
47 #include <linux/slab.h>
48 #include <linux/delay.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>
59 #include <linux/types.h>
60 #include <asm/uaccess.h>
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>
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"
83 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
85 extern struct display_switch fbcon_sis8
;
87 #ifdef FBCON_HAS_CFB16
88 extern struct display_switch fbcon_sis16
;
90 #ifdef FBCON_HAS_CFB32
91 extern struct display_switch fbcon_sis32
;
95 /* ------------------ Internal helper routines ----------------- */
98 sisfb_setdefaultparms(void)
108 /* Module: "None" for 2.4, default mode for 2.5+ */
109 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
112 sisfb_mode_idx
= MODE_INDEX_NONE
;
115 /* Static: Default mode */
118 sisfb_parm_rate
= -1;
120 sisfb_forcecrt1
= -1;
126 sisfb_specialtiming
= CUT_NONE
;
132 sisfb_tvxposoffset
= 0;
133 sisfb_tvyposoffset
= 0;
135 sisfb_nocrt2rate
= 0;
136 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
138 sisfb_fontname
[0] = 0;
140 #if !defined(__i386__) && !defined(__x86_64__)
147 sisfb_search_vesamode(unsigned int vesamode
, BOOLEAN quiet
)
151 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
154 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
155 sisfb_mode_idx
= MODE_INDEX_NONE
;
158 printk(KERN_ERR
"sisfb: Invalid mode. Using default.\n");
160 sisfb_mode_idx
= DEFAULT_MODE
;
165 vesamode
&= 0x1dff; /* Clean VESA mode number from other flags */
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
) ) {
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;
175 if(sisbios_mode
[i
-1].mode_no
[1] == 0x5a ||
176 sisbios_mode
[i
-1].mode_no
[1] == 0x5b) continue;
178 sisfb_mode_idx
= i
- 1;
183 if((!j
) && !quiet
) printk(KERN_ERR
"sisfb: Invalid VESA mode 0x%x'\n", vesamode
);
187 sisfb_search_mode(char *name
, BOOLEAN quiet
)
190 unsigned int j
= 0, xres
= 0, yres
= 0, depth
= 0, rate
= 0;
191 char strbuf
[16], strbuf1
[20];
192 char *nameptr
= name
;
194 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
198 printk(KERN_ERR
"sisfb: Internal error, using default mode.\n");
200 sisfb_mode_idx
= DEFAULT_MODE
;
204 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
205 if(!strnicmp(name
, sisbios_mode
[MODE_INDEX_NONE
].name
, strlen(name
))) {
207 printk(KERN_ERR
"sisfb: Mode 'none' not supported anymore. Using default.\n");
209 sisfb_mode_idx
= DEFAULT_MODE
;
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
] = ' ';
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
;
224 sprintf(strbuf
, "%ux%ux%u", xres
, yres
, depth
);
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
);
232 if((sscanf(strbuf1
, "%u %u", &xres
, &yres
) == 2) && (xres
!= 0)) {
233 sprintf(strbuf
, "%ux%ux8", xres
, yres
);
236 sisfb_search_vesamode(simple_strtoul(name
, NULL
, 0), quiet
);
243 while(sisbios_mode
[i
].mode_no
[0] != 0) {
244 if(!strnicmp(nameptr
, sisbios_mode
[i
++].name
, strlen(nameptr
))) {
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;
250 if(sisbios_mode
[i
-1].mode_no
[1] == 0x5a ||
251 sisbios_mode
[i
-1].mode_no
[1] == 0x5b) continue;
253 sisfb_mode_idx
= i
- 1;
258 if((!j
) && !quiet
) printk(KERN_ERR
"sisfb: Invalid mode '%s'\n", nameptr
);
262 static void __devinit
263 sisfb_get_vga_mode_from_kernel(void)
265 #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
267 int mydepth
= screen_info
.lfb_depth
;
269 if(screen_info
.orig_video_isVGA
!= VIDEO_TYPE_VLFB
) return;
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) ) {
275 if(mydepth
== 24) mydepth
= 32;
277 sprintf(mymode
, "%ux%ux%u", screen_info
.lfb_width
,
278 screen_info
.lfb_height
,
281 printk(KERN_DEBUG
"sisfb: Using vga mode %s pre-set by kernel as default\n", mymode
);
283 sisfb_search_mode(mymode
, TRUE
);
291 sisfb_search_crt2type(const char *name
)
295 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
297 if(name
== NULL
) return;
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
;
309 sisfb_dstn
= (sisfb_crt2flags
& FL_550_DSTN
) ? 1 : 0;
310 sisfb_fstn
= (sisfb_crt2flags
& FL_550_FSTN
) ? 1 : 0;
312 if(sisfb_crt2type
< 0) {
313 printk(KERN_ERR
"sisfb: Invalid CRT2 type: %s\n", name
);
318 sisfb_search_tvstd(const char *name
)
322 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
324 if(name
== NULL
) return;
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
;
336 sisfb_search_specialtiming(const char *name
)
339 BOOLEAN found
= FALSE
;
341 /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
343 if(name
== NULL
) return;
345 if(!strnicmp(name
, "none", 4)) {
346 sisfb_specialtiming
= CUT_FORCENONE
;
347 printk(KERN_DEBUG
"sisfb: Special timing disabled\n");
349 while(mycustomttable
[i
].chipID
!= 0) {
350 if(!strnicmp(name
,mycustomttable
[i
].optionName
, strlen(mycustomttable
[i
].optionName
))) {
351 sisfb_specialtiming
= mycustomttable
[i
].SpecialID
;
353 printk(KERN_INFO
"sisfb: Special timing for %s %s forced (\"%s\")\n",
354 mycustomttable
[i
].vendorName
, mycustomttable
[i
].cardName
,
355 mycustomttable
[i
].optionName
);
361 printk(KERN_WARNING
"sisfb: Invalid SpecialTiming parameter, valid are:");
362 printk(KERN_WARNING
"\t\"none\" (to disable special timings)\n");
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
);
375 static BOOLEAN __devinit
376 sisfb_interpret_edid(struct sisfb_monitor
*monitor
, u8
*buffer
)
378 int i
, j
, xres
, yres
, refresh
, index
;
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");
389 if(buffer
[0x12] != 0x01) {
390 printk(KERN_INFO
"sisfb: EDID version %d not supported\n",
395 monitor
->feature
= buffer
[0x18];
397 if(!buffer
[0x14] & 0x80) {
398 if(!(buffer
[0x14] & 0x08)) {
399 printk(KERN_INFO
"sisfb: WARNING: Monitor does not support separate syncs\n");
403 if(buffer
[0x13] >= 0x01) {
404 /* EDID V1 rev 1 and 2: Search for monitor descriptor
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
;
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
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
;
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;
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
;
468 if((monitor
->hmin
<= monitor
->hmax
) && (monitor
->vmin
<= monitor
->vmax
)) {
469 monitor
->datavalid
= TRUE
;
473 return(monitor
->datavalid
);
476 static void __devinit
477 sisfb_handle_ddc(struct sis_video_info
*ivideo
, struct sisfb_monitor
*monitor
, int crtno
)
479 USHORT temp
, i
, realcrtno
= crtno
;
482 monitor
->datavalid
= FALSE
;
485 if(ivideo
->vbflags
& CRT2_LCD
) realcrtno
= 1;
486 else if(ivideo
->vbflags
& CRT2_VGA
) realcrtno
= 2;
490 if((ivideo
->sisfb_crt1off
) && (!crtno
)) return;
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);
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",
501 (temp
& 0x1a) ? "" : "[none of the supported]",
502 (temp
& 0x02) ? "2 " : "",
503 (temp
& 0x08) ? "D&P" : "",
504 (temp
& 0x10) ? "FPDI-2" : "");
506 i
= 3; /* Number of retrys */
508 temp
= SiS_HandleDDC(&ivideo
->SiS_Pr
, ivideo
->vbflags
, ivideo
->sisvga_engine
,
509 realcrtno
, 1, &buffer
[0]);
510 } while((temp
) && i
--);
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);
517 printk(KERN_INFO
"sisfb: CRT%d DDC EDID corrupt\n", crtno
+ 1);
520 printk(KERN_INFO
"sisfb: CRT%d DDC reading failed\n", crtno
+ 1);
523 printk(KERN_INFO
"sisfb: VESA D&P and FPDI-2 not supported yet\n");
529 sisfb_verify_rate(struct sis_video_info
*ivideo
, struct sisfb_monitor
*monitor
,
530 int mode_idx
, int rate_idx
, int rate
)
533 unsigned int dclock
, hsync
;
535 if(!monitor
->datavalid
) return TRUE
;
537 if(mode_idx
< 0) return FALSE
;
539 /* Skip for 320x200, 320x240, 640x400 */
540 switch(sisbios_mode
[mode_idx
].mode_no
[ivideo
->mni
]) {
551 #ifdef CONFIG_FB_SIS_315
554 if(ivideo
->sisvga_engine
== SIS_315_VGA
) return TRUE
;
558 if(rate
< (monitor
->vmin
- 1)) return FALSE
;
559 if(rate
> (monitor
->vmax
+ 1)) return FALSE
;
561 if(sisfb_gettotalfrommode(&ivideo
->SiS_Pr
, &ivideo
->sishw_ext
,
562 sisbios_mode
[mode_idx
].mode_no
[ivideo
->mni
],
563 &htotal
, &vtotal
, rate_idx
)) {
564 dclock
= (htotal
* vtotal
* rate
) / 1000;
565 if(dclock
> (monitor
->dclockmax
+ 1000)) return FALSE
;
566 hsync
= dclock
/ htotal
;
567 if(hsync
< (monitor
->hmin
- 1)) return FALSE
;
568 if(hsync
> (monitor
->hmax
+ 1)) return FALSE
;
576 sisfb_validate_mode(struct sis_video_info
*ivideo
, int myindex
, u32 vbflags
)
578 u16 xres
=0, yres
, myres
;
580 #ifdef CONFIG_FB_SIS_300
581 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
582 if(!(sisbios_mode
[myindex
].chipset
& MD_SIS300
)) return(-1);
585 #ifdef CONFIG_FB_SIS_315
586 if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
587 if(!(sisbios_mode
[myindex
].chipset
& MD_SIS315
)) return(-1);
591 myres
= sisbios_mode
[myindex
].yres
;
593 switch(vbflags
& VB_DISPTYPE_DISP2
) {
597 xres
= ivideo
->lcdxres
; yres
= ivideo
->lcdyres
;
599 if(ivideo
->SiS_Pr
.SiS_CustomT
!= CUT_PANEL848
) {
600 if(sisbios_mode
[myindex
].xres
> xres
) return(-1);
601 if(myres
> yres
) return(-1);
604 if(vbflags
& (VB_LVDS
| VB_30xBDH
)) {
605 if(sisbios_mode
[myindex
].xres
== 320) {
606 if((myres
== 240) || (myres
== 480)) {
607 if(!ivideo
->sisfb_fstn
) {
608 if(sisbios_mode
[myindex
].mode_no
[1] == 0x5a ||
609 sisbios_mode
[myindex
].mode_no
[1] == 0x5b)
612 if(sisbios_mode
[myindex
].mode_no
[1] == 0x50 ||
613 sisbios_mode
[myindex
].mode_no
[1] == 0x56 ||
614 sisbios_mode
[myindex
].mode_no
[1] == 0x53)
621 if(SiS_GetModeID_LCD(ivideo
->sisvga_engine
, vbflags
, sisbios_mode
[myindex
].xres
,
622 sisbios_mode
[myindex
].yres
, 0, ivideo
->sisfb_fstn
,
623 ivideo
->SiS_Pr
.SiS_CustomT
, xres
, yres
) < 0x14) {
629 if(SiS_GetModeID_TV(ivideo
->sisvga_engine
, vbflags
, sisbios_mode
[myindex
].xres
,
630 sisbios_mode
[myindex
].yres
, 0) < 0x14) {
636 if(SiS_GetModeID_VGA2(ivideo
->sisvga_engine
, vbflags
, sisbios_mode
[myindex
].xres
,
637 sisbios_mode
[myindex
].yres
, 0) < 0x14) {
647 sisfb_search_refresh_rate(struct sis_video_info
*ivideo
, unsigned int rate
, int mode_idx
)
652 xres
= sisbios_mode
[mode_idx
].xres
;
653 yres
= sisbios_mode
[mode_idx
].yres
;
655 ivideo
->rate_idx
= 0;
656 while((sisfb_vrate
[i
].idx
!= 0) && (sisfb_vrate
[i
].xres
<= xres
)) {
657 if((sisfb_vrate
[i
].xres
== xres
) && (sisfb_vrate
[i
].yres
== yres
)) {
658 if(sisfb_vrate
[i
].refresh
== rate
) {
659 ivideo
->rate_idx
= sisfb_vrate
[i
].idx
;
661 } else if(sisfb_vrate
[i
].refresh
> rate
) {
662 if((sisfb_vrate
[i
].refresh
- rate
) <= 3) {
663 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
664 rate
, sisfb_vrate
[i
].refresh
);
665 ivideo
->rate_idx
= sisfb_vrate
[i
].idx
;
666 ivideo
->refresh_rate
= sisfb_vrate
[i
].refresh
;
667 } else if(((rate
- sisfb_vrate
[i
-1].refresh
) <= 2)
668 && (sisfb_vrate
[i
].idx
!= 1)) {
669 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
670 rate
, sisfb_vrate
[i
-1].refresh
);
671 ivideo
->rate_idx
= sisfb_vrate
[i
-1].idx
;
672 ivideo
->refresh_rate
= sisfb_vrate
[i
-1].refresh
;
675 } else if((rate
- sisfb_vrate
[i
].refresh
) <= 2) {
676 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
677 rate
, sisfb_vrate
[i
].refresh
);
678 ivideo
->rate_idx
= sisfb_vrate
[i
].idx
;
684 if(ivideo
->rate_idx
> 0) {
685 return ivideo
->rate_idx
;
687 printk(KERN_INFO
"sisfb: Unsupported rate %d for %dx%d\n",
694 sisfb_bridgeisslave(struct sis_video_info
*ivideo
)
698 if(!(ivideo
->vbflags
& VB_VIDEOBRIDGE
)) return FALSE
;
700 inSISIDXREG(SISPART1
,0x00,P1_00
);
701 if( ((ivideo
->sisvga_engine
== SIS_300_VGA
) && (P1_00
& 0xa0) == 0x20) ||
702 ((ivideo
->sisvga_engine
== SIS_315_VGA
) && (P1_00
& 0x50) == 0x10) ) {
710 sisfballowretracecrt1(struct sis_video_info
*ivideo
)
714 inSISIDXREG(SISCR
,0x17,temp
);
715 if(!(temp
& 0x80)) return FALSE
;
717 inSISIDXREG(SISSR
,0x1f,temp
);
718 if(temp
& 0xc0) return FALSE
;
724 sisfbcheckvretracecrt1(struct sis_video_info
*ivideo
)
726 if(!sisfballowretracecrt1(ivideo
)) return FALSE
;
728 if(inSISREG(SISINPSTAT
) & 0x08) return TRUE
;
733 sisfbwaitretracecrt1(struct sis_video_info
*ivideo
)
737 if(!sisfballowretracecrt1(ivideo
)) return;
740 while((!(inSISREG(SISINPSTAT
) & 0x08)) && --watchdog
);
742 while((inSISREG(SISINPSTAT
) & 0x08) && --watchdog
);
746 sisfbcheckvretracecrt2(struct sis_video_info
*ivideo
)
748 unsigned char temp
, reg
;
750 switch(ivideo
->sisvga_engine
) {
751 case SIS_300_VGA
: reg
= 0x25; break;
752 case SIS_315_VGA
: reg
= 0x30; break;
753 default: return FALSE
;
756 inSISIDXREG(SISPART1
, reg
, temp
);
757 if(temp
& 0x02) return FALSE
;
762 sisfb_CheckVBRetrace(struct sis_video_info
*ivideo
)
764 if(ivideo
->currentvbflags
& VB_DISPTYPE_DISP2
) {
765 if(sisfb_bridgeisslave(ivideo
)) {
766 return(sisfbcheckvretracecrt1(ivideo
));
768 return(sisfbcheckvretracecrt2(ivideo
));
771 return(sisfbcheckvretracecrt1(ivideo
));
775 sisfb_setupvbblankflags(struct sis_video_info
*ivideo
, u32
*vcount
, u32
*hcount
)
777 u8 idx
, reg1
, reg2
, reg3
, reg4
;
780 (*vcount
) = (*hcount
) = 0;
782 if((ivideo
->currentvbflags
& VB_DISPTYPE_DISP2
) && (!(sisfb_bridgeisslave(ivideo
)))) {
783 ret
|= (FB_VBLANK_HAVE_VSYNC
|
784 FB_VBLANK_HAVE_HBLANK
|
785 FB_VBLANK_HAVE_VBLANK
|
786 FB_VBLANK_HAVE_VCOUNT
|
787 FB_VBLANK_HAVE_HCOUNT
);
788 switch(ivideo
->sisvga_engine
) {
789 case SIS_300_VGA
: idx
= 0x25; break;
791 case SIS_315_VGA
: idx
= 0x30; break;
793 inSISIDXREG(SISPART1
,(idx
+0),reg1
); /* 30 */
794 inSISIDXREG(SISPART1
,(idx
+1),reg2
); /* 31 */
795 inSISIDXREG(SISPART1
,(idx
+2),reg3
); /* 32 */
796 inSISIDXREG(SISPART1
,(idx
+3),reg4
); /* 33 */
797 if(!(reg1
& 0x01)) ret
|= FB_VBLANK_VBLANKING
;
798 if(!(reg1
& 0x02)) ret
|= FB_VBLANK_VSYNCING
;
799 if(!(reg4
& 0x80)) ret
|= FB_VBLANK_HBLANKING
;
800 (*vcount
) = reg3
| ((reg4
& 0x70) << 4);
801 (*hcount
) = reg2
| ((reg4
& 0x0f) << 8);
802 } else if(sisfballowretracecrt1(ivideo
)) {
803 ret
|= (FB_VBLANK_HAVE_VSYNC
|
804 FB_VBLANK_HAVE_VBLANK
|
805 FB_VBLANK_HAVE_VCOUNT
|
806 FB_VBLANK_HAVE_HCOUNT
);
807 reg1
= inSISREG(SISINPSTAT
);
808 if(reg1
& 0x08) ret
|= FB_VBLANK_VSYNCING
;
809 if(reg1
& 0x01) ret
|= FB_VBLANK_VBLANKING
;
810 inSISIDXREG(SISCR
,0x20,reg1
);
811 inSISIDXREG(SISCR
,0x1b,reg1
);
812 inSISIDXREG(SISCR
,0x1c,reg2
);
813 inSISIDXREG(SISCR
,0x1d,reg3
);
814 (*vcount
) = reg2
| ((reg3
& 0x07) << 8);
815 (*hcount
) = (reg1
| ((reg3
& 0x10) << 4)) << 3;
821 sisfb_myblank(struct sis_video_info
*ivideo
, int blank
)
823 u8 sr01
, sr11
, sr1f
, cr63
=0, p2_0
, p1_13
;
824 BOOLEAN backlight
= TRUE
;
845 case 2: /* no vsync */
854 case 3: /* no hsync */
876 if(ivideo
->currentvbflags
& VB_DISPTYPE_CRT1
) {
878 if( (!ivideo
->sisfb_thismonitor
.datavalid
) ||
879 ((ivideo
->sisfb_thismonitor
.datavalid
) &&
880 (ivideo
->sisfb_thismonitor
.feature
& 0xe0))) {
882 if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
883 setSISIDXREG(SISCR
, ivideo
->SiS_Pr
.SiS_MyCR63
, 0xbf, cr63
);
886 if(!(sisfb_bridgeisslave(ivideo
))) {
887 setSISIDXREG(SISSR
, 0x01, ~0x20, sr01
);
888 setSISIDXREG(SISSR
, 0x1f, 0x3f, sr1f
);
894 if(ivideo
->currentvbflags
& CRT2_LCD
) {
896 if(ivideo
->vbflags
& (VB_301LV
|VB_302LV
|VB_302ELV
)) {
898 SiS_SiS30xBLOn(&ivideo
->SiS_Pr
, &ivideo
->sishw_ext
);
900 SiS_SiS30xBLOff(&ivideo
->SiS_Pr
, &ivideo
->sishw_ext
);
902 } else if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
903 if(ivideo
->vbflags
& VB_CHRONTEL
) {
905 SiS_Chrontel701xBLOn(&ivideo
->SiS_Pr
,&ivideo
->sishw_ext
);
907 SiS_Chrontel701xBLOff(&ivideo
->SiS_Pr
);
912 if(((ivideo
->sisvga_engine
== SIS_300_VGA
) &&
913 (ivideo
->vbflags
& (VB_301
|VB_30xBDH
|VB_LVDS
))) ||
914 ((ivideo
->sisvga_engine
== SIS_315_VGA
) &&
915 ((ivideo
->vbflags
& (VB_LVDS
| VB_CHRONTEL
)) == VB_LVDS
))) {
916 setSISIDXREG(SISSR
, 0x11, ~0x0c, sr11
);
919 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
920 if((ivideo
->vbflags
& (VB_301B
|VB_301C
|VB_302B
)) &&
921 (!(ivideo
->vbflags
& VB_30xBDH
))) {
922 setSISIDXREG(SISPART1
, 0x13, 0x3f, p1_13
);
924 } else if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
925 if((ivideo
->vbflags
& (VB_301B
|VB_301C
|VB_302B
)) &&
926 (!(ivideo
->vbflags
& VB_30xBDH
))) {
927 setSISIDXREG(SISPART2
, 0x00, 0x1f, p2_0
);
931 } else if(ivideo
->currentvbflags
& CRT2_VGA
) {
933 if(ivideo
->vbflags
& (VB_301B
|VB_301C
|VB_302B
)) {
934 setSISIDXREG(SISPART2
, 0x00, 0x1f, p2_0
);
942 /* ----------- FBDev related routines for all series ----------- */
945 sisfb_get_cmap_len(const struct fb_var_screeninfo
*var
)
947 return (var
->bits_per_pixel
== 8) ? 256 : 16;
951 sisfb_set_vparms(struct sis_video_info
*ivideo
)
953 switch(ivideo
->video_bpp
) {
955 ivideo
->DstColor
= 0x0000;
956 ivideo
->SiS310_AccelDepth
= 0x00000000;
957 ivideo
->video_cmap_len
= 256;
960 ivideo
->DstColor
= 0x8000;
961 ivideo
->SiS310_AccelDepth
= 0x00010000;
962 ivideo
->video_cmap_len
= 16;
965 ivideo
->DstColor
= 0xC000;
966 ivideo
->SiS310_AccelDepth
= 0x00020000;
967 ivideo
->video_cmap_len
= 16;
970 ivideo
->video_cmap_len
= 16;
971 printk(KERN_ERR
"sisfb: Unsupported depth %d", ivideo
->video_bpp
);
978 sisfb_calc_maxyres(struct sis_video_info
*ivideo
, struct fb_var_screeninfo
*var
)
980 int maxyres
= ivideo
->heapstart
/ (var
->xres_virtual
* (var
->bits_per_pixel
>> 3));
982 if(maxyres
> 32767) maxyres
= 32767;
988 sisfb_calc_pitch(struct sis_video_info
*ivideo
, struct fb_var_screeninfo
*var
)
990 ivideo
->video_linelength
= var
->xres_virtual
* (var
->bits_per_pixel
>> 3);
991 ivideo
->scrnpitchCRT1
= ivideo
->video_linelength
;
992 if(!(ivideo
->currentvbflags
& CRT1_LCDA
)) {
993 if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_INTERLACED
) {
994 ivideo
->scrnpitchCRT1
<<= 1;
1001 sisfb_set_pitch(struct sis_video_info
*ivideo
)
1003 BOOLEAN isslavemode
= FALSE
;
1004 unsigned short HDisplay1
= ivideo
->scrnpitchCRT1
>> 3;
1005 unsigned short HDisplay2
= ivideo
->video_linelength
>> 3;
1007 if(sisfb_bridgeisslave(ivideo
)) isslavemode
= TRUE
;
1009 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1010 if((ivideo
->currentvbflags
& VB_DISPTYPE_DISP1
) || (isslavemode
)) {
1011 outSISIDXREG(SISCR
,0x13,(HDisplay1
& 0xFF));
1012 setSISIDXREG(SISSR
,0x0E,0xF0,(HDisplay1
>> 8));
1015 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1016 if((ivideo
->currentvbflags
& VB_DISPTYPE_DISP2
) && (!isslavemode
)) {
1017 orSISIDXREG(SISPART1
,ivideo
->CRT2_write_enable
,0x01);
1018 outSISIDXREG(SISPART1
,0x07,(HDisplay2
& 0xFF));
1019 setSISIDXREG(SISPART1
,0x09,0xF0,(HDisplay2
>> 8));
1024 sisfb_bpp_to_var(struct sis_video_info
*ivideo
, struct fb_var_screeninfo
*var
)
1026 ivideo
->video_cmap_len
= sisfb_get_cmap_len(var
);
1028 switch(var
->bits_per_pixel
) {
1030 var
->red
.offset
= var
->green
.offset
= var
->blue
.offset
= 0;
1031 var
->red
.length
= var
->green
.length
= var
->blue
.length
= 6;
1034 var
->red
.offset
= 11;
1035 var
->red
.length
= 5;
1036 var
->green
.offset
= 5;
1037 var
->green
.length
= 6;
1038 var
->blue
.offset
= 0;
1039 var
->blue
.length
= 5;
1040 var
->transp
.offset
= 0;
1041 var
->transp
.length
= 0;
1044 var
->red
.offset
= 16;
1045 var
->red
.length
= 8;
1046 var
->green
.offset
= 8;
1047 var
->green
.length
= 8;
1048 var
->blue
.offset
= 0;
1049 var
->blue
.length
= 8;
1050 var
->transp
.offset
= 24;
1051 var
->transp
.length
= 8;
1057 sisfb_do_set_var(struct fb_var_screeninfo
*var
, int isactive
, struct fb_info
*info
)
1059 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1060 unsigned int htotal
= 0, vtotal
= 0;
1061 unsigned int drate
= 0, hrate
= 0;
1066 htotal
= var
->left_margin
+ var
->xres
+ var
->right_margin
+ var
->hsync_len
;
1068 vtotal
= var
->upper_margin
+ var
->lower_margin
+ var
->vsync_len
;
1070 pixclock
= var
->pixclock
;
1072 if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_NONINTERLACED
) {
1073 vtotal
+= var
->yres
;
1075 } else if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_DOUBLE
) {
1076 vtotal
+= var
->yres
;
1078 } else if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_INTERLACED
) {
1079 vtotal
+= var
->yres
;
1081 } else vtotal
+= var
->yres
;
1083 if(!(htotal
) || !(vtotal
)) {
1084 DPRINTK("sisfb: Invalid 'var' information\n");
1088 if(pixclock
&& htotal
&& vtotal
) {
1089 drate
= 1000000000 / pixclock
;
1090 hrate
= (drate
* 1000) / htotal
;
1091 ivideo
->refresh_rate
= (unsigned int) (hrate
* 2 / vtotal
);
1093 ivideo
->refresh_rate
= 60;
1096 old_mode
= ivideo
->sisfb_mode_idx
;
1097 ivideo
->sisfb_mode_idx
= 0;
1099 while( (sisbios_mode
[ivideo
->sisfb_mode_idx
].mode_no
[0] != 0) &&
1100 (sisbios_mode
[ivideo
->sisfb_mode_idx
].xres
<= var
->xres
) ) {
1101 if( (sisbios_mode
[ivideo
->sisfb_mode_idx
].xres
== var
->xres
) &&
1102 (sisbios_mode
[ivideo
->sisfb_mode_idx
].yres
== var
->yres
) &&
1103 (sisbios_mode
[ivideo
->sisfb_mode_idx
].bpp
== var
->bits_per_pixel
)) {
1104 ivideo
->mode_no
= sisbios_mode
[ivideo
->sisfb_mode_idx
].mode_no
[ivideo
->mni
];
1108 ivideo
->sisfb_mode_idx
++;
1112 ivideo
->sisfb_mode_idx
= sisfb_validate_mode(ivideo
,
1113 ivideo
->sisfb_mode_idx
, ivideo
->currentvbflags
);
1115 ivideo
->sisfb_mode_idx
= -1;
1118 if(ivideo
->sisfb_mode_idx
< 0) {
1119 printk(KERN_ERR
"sisfb: Mode %dx%dx%d not supported\n", var
->xres
,
1120 var
->yres
, var
->bits_per_pixel
);
1121 ivideo
->sisfb_mode_idx
= old_mode
;
1125 if(sisfb_search_refresh_rate(ivideo
, ivideo
->refresh_rate
, ivideo
->sisfb_mode_idx
) == 0) {
1126 ivideo
->rate_idx
= sisbios_mode
[ivideo
->sisfb_mode_idx
].rate_idx
;
1127 ivideo
->refresh_rate
= 60;
1130 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1131 if(ivideo
->sisfb_thismonitor
.datavalid
) {
1132 if(!sisfb_verify_rate(ivideo
, &ivideo
->sisfb_thismonitor
, ivideo
->sisfb_mode_idx
,
1133 ivideo
->rate_idx
, ivideo
->refresh_rate
)) {
1134 printk(KERN_INFO
"sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1139 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1140 if(((var
->activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) && isactive
) {
1144 sisfb_pre_setmode(ivideo
);
1146 if(SiSSetMode(&ivideo
->SiS_Pr
, &ivideo
->sishw_ext
, ivideo
->mode_no
) == 0) {
1147 printk(KERN_ERR
"sisfb: Setting mode[0x%x] failed\n", ivideo
->mode_no
);
1151 outSISIDXREG(SISSR
, IND_SIS_PASSWORD
, SIS_PASSWORD
);
1153 sisfb_post_setmode(ivideo
);
1155 ivideo
->video_bpp
= sisbios_mode
[ivideo
->sisfb_mode_idx
].bpp
;
1156 ivideo
->video_width
= sisbios_mode
[ivideo
->sisfb_mode_idx
].xres
;
1157 ivideo
->video_height
= sisbios_mode
[ivideo
->sisfb_mode_idx
].yres
;
1159 sisfb_calc_pitch(ivideo
, var
);
1160 sisfb_set_pitch(ivideo
);
1163 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1164 #ifdef STUPID_ACCELF_TEXT_SHIT
1165 if(var
->accel_flags
& FB_ACCELF_TEXT
) {
1166 info
->flags
&= ~FBINFO_HWACCEL_DISABLED
;
1168 info
->flags
|= FBINFO_HWACCEL_DISABLED
;
1171 if(!(info
->flags
& FBINFO_HWACCEL_DISABLED
)) ivideo
->accel
= -1;
1173 if(var
->accel_flags
& FB_ACCELF_TEXT
) ivideo
->accel
= -1;
1176 sisfb_set_vparms(ivideo
);
1178 ivideo
->current_width
= ivideo
->video_width
;
1179 ivideo
->current_height
= ivideo
->video_height
;
1180 ivideo
->current_bpp
= ivideo
->video_bpp
;
1181 ivideo
->current_htotal
= htotal
;
1182 ivideo
->current_vtotal
= vtotal
;
1183 ivideo
->current_linelength
= ivideo
->video_linelength
;
1184 ivideo
->current_pixclock
= var
->pixclock
;
1185 ivideo
->current_refresh_rate
= ivideo
->refresh_rate
;
1186 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1187 ivideo
->sisfb_lastrates
[ivideo
->mode_no
] = ivideo
->refresh_rate
;
1195 sisfb_pan_var(struct sis_video_info
*ivideo
, struct fb_var_screeninfo
*var
)
1199 if(var
->xoffset
> (var
->xres_virtual
- var
->xres
)) {
1202 if(var
->yoffset
> (var
->yres_virtual
- var
->yres
)) {
1206 base
= (var
->yoffset
* var
->xres_virtual
) + var
->xoffset
;
1208 /* calculate base bpp dep. */
1209 switch(var
->bits_per_pixel
) {
1221 outSISIDXREG(SISSR
, IND_SIS_PASSWORD
, SIS_PASSWORD
);
1223 outSISIDXREG(SISCR
, 0x0D, base
& 0xFF);
1224 outSISIDXREG(SISCR
, 0x0C, (base
>> 8) & 0xFF);
1225 outSISIDXREG(SISSR
, 0x0D, (base
>> 16) & 0xFF);
1226 if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
1227 setSISIDXREG(SISSR
, 0x37, 0xFE, (base
>> 24) & 0x01);
1229 if(ivideo
->currentvbflags
& VB_DISPTYPE_DISP2
) {
1230 orSISIDXREG(SISPART1
, ivideo
->CRT2_write_enable
, 0x01);
1231 outSISIDXREG(SISPART1
, 0x06, (base
& 0xFF));
1232 outSISIDXREG(SISPART1
, 0x05, ((base
>> 8) & 0xFF));
1233 outSISIDXREG(SISPART1
, 0x04, ((base
>> 16) & 0xFF));
1234 if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
1235 setSISIDXREG(SISPART1
, 0x02, 0x7F, ((base
>> 24) & 0x01) << 7);
1241 /* ------------ FBDev related routines for 2.4 series ----------- */
1243 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1246 sisfb_crtc_to_var(struct sis_video_info
*ivideo
, struct fb_var_screeninfo
*var
)
1248 u16 VRE
, VBE
, VRS
, VBS
, VDE
, VT
;
1249 u16 HRE
, HBE
, HRS
, HBS
, HDE
, HT
;
1250 u8 sr_data
, cr_data
, cr_data2
, cr_data3
, mr_data
;
1251 int A
, B
, C
, D
, E
, F
, temp
;
1252 unsigned int hrate
, drate
, maxyres
;
1254 inSISIDXREG(SISSR
, IND_SIS_COLOR_MODE
, sr_data
);
1256 if(sr_data
& SIS_INTERLACED_MODE
)
1257 var
->vmode
= FB_VMODE_INTERLACED
;
1259 var
->vmode
= FB_VMODE_NONINTERLACED
;
1261 switch((sr_data
& 0x1C) >> 2) {
1262 case SIS_8BPP_COLOR_MODE
:
1263 var
->bits_per_pixel
= 8;
1265 case SIS_16BPP_COLOR_MODE
:
1266 var
->bits_per_pixel
= 16;
1268 case SIS_32BPP_COLOR_MODE
:
1269 var
->bits_per_pixel
= 32;
1273 sisfb_bpp_to_var(ivideo
, var
);
1275 inSISIDXREG(SISSR
, 0x0A, sr_data
);
1276 inSISIDXREG(SISCR
, 0x06, cr_data
);
1277 inSISIDXREG(SISCR
, 0x07, cr_data2
);
1279 VT
= (cr_data
& 0xFF) |
1280 ((u16
) (cr_data2
& 0x01) << 8) |
1281 ((u16
) (cr_data2
& 0x20) << 4) |
1282 ((u16
) (sr_data
& 0x01) << 10);
1285 inSISIDXREG(SISCR
, 0x12, cr_data
);
1287 VDE
= (cr_data
& 0xff) |
1288 ((u16
) (cr_data2
& 0x02) << 7) |
1289 ((u16
) (cr_data2
& 0x40) << 3) |
1290 ((u16
) (sr_data
& 0x02) << 9);
1293 inSISIDXREG(SISCR
, 0x10, cr_data
);
1295 VRS
= (cr_data
& 0xff) |
1296 ((u16
) (cr_data2
& 0x04) << 6) |
1297 ((u16
) (cr_data2
& 0x80) << 2) |
1298 ((u16
) (sr_data
& 0x08) << 7);
1301 inSISIDXREG(SISCR
, 0x15, cr_data
);
1302 inSISIDXREG(SISCR
, 0x09, cr_data3
);
1304 if(cr_data3
& 0x80) var
->vmode
= FB_VMODE_DOUBLE
;
1306 VBS
= (cr_data
& 0xff) |
1307 ((u16
) (cr_data2
& 0x08) << 5) |
1308 ((u16
) (cr_data3
& 0x20) << 4) |
1309 ((u16
) (sr_data
& 0x04) << 8);
1311 inSISIDXREG(SISCR
, 0x16, cr_data
);
1313 VBE
= (cr_data
& 0xff) | ((u16
) (sr_data
& 0x10) << 4);
1314 temp
= VBE
- ((E
- 1) & 511);
1315 B
= (temp
> 0) ? temp
: (temp
+ 512);
1317 inSISIDXREG(SISCR
, 0x11, cr_data
);
1319 VRE
= (cr_data
& 0x0f) | ((sr_data
& 0x20) >> 1);
1320 temp
= VRE
- ((E
+ F
- 1) & 31);
1321 C
= (temp
> 0) ? temp
: (temp
+ 32);
1326 var
->upper_margin
= D
;
1327 var
->lower_margin
= F
;
1330 if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_INTERLACED
) {
1332 var
->upper_margin
<<= 1;
1333 var
->lower_margin
<<= 1;
1334 var
->vsync_len
<<= 1;
1335 } else if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_DOUBLE
) {
1337 var
->upper_margin
>>= 1;
1338 var
->lower_margin
>>= 1;
1339 var
->vsync_len
>>= 1;
1342 inSISIDXREG(SISSR
, 0x0b, sr_data
);
1343 inSISIDXREG(SISCR
, 0x00, cr_data
);
1345 HT
= (cr_data
& 0xff) | ((u16
) (sr_data
& 0x03) << 8);
1348 inSISIDXREG(SISCR
, 0x01, cr_data
);
1350 HDE
= (cr_data
& 0xff) | ((u16
) (sr_data
& 0x0C) << 6);
1353 inSISIDXREG(SISCR
, 0x04, cr_data
);
1355 HRS
= (cr_data
& 0xff) | ((u16
) (sr_data
& 0xC0) << 2);
1358 inSISIDXREG(SISCR
, 0x02, cr_data
);
1360 HBS
= (cr_data
& 0xff) | ((u16
) (sr_data
& 0x30) << 4);
1362 inSISIDXREG(SISSR
, 0x0c, sr_data
);
1363 inSISIDXREG(SISCR
, 0x03, cr_data
);
1364 inSISIDXREG(SISCR
, 0x05, cr_data2
);
1366 HBE
= (cr_data
& 0x1f) |
1367 ((u16
) (cr_data2
& 0x80) >> 2) |
1368 ((u16
) (sr_data
& 0x03) << 6);
1369 HRE
= (cr_data2
& 0x1f) | ((sr_data
& 0x04) << 3);
1371 temp
= HBE
- ((E
- 1) & 255);
1372 B
= (temp
> 0) ? temp
: (temp
+ 256);
1374 temp
= HRE
- ((E
+ F
+ 3) & 63);
1375 C
= (temp
> 0) ? temp
: (temp
+ 64);
1380 if(var
->xres_virtual
< var
->xres
) {
1381 var
->xres_virtual
= var
->xres
;
1384 if((var
->xres
== 320) &&
1385 (var
->yres
== 200 || var
->yres
== 240)) {
1386 /* Terrible hack, but the correct CRTC data for
1387 * these modes only produces a black screen...
1389 var
->left_margin
= (400 - 376);
1390 var
->right_margin
= (328 - 320);
1391 var
->hsync_len
= (376 - 328);
1393 var
->left_margin
= D
* 8;
1394 var
->right_margin
= F
* 8;
1395 var
->hsync_len
= C
* 8;
1397 var
->activate
= FB_ACTIVATE_NOW
;
1401 mr_data
= inSISREG(SISMISCR
);
1403 var
->sync
&= ~FB_SYNC_VERT_HIGH_ACT
;
1405 var
->sync
|= FB_SYNC_VERT_HIGH_ACT
;
1408 var
->sync
&= ~FB_SYNC_HOR_HIGH_ACT
;
1410 var
->sync
|= FB_SYNC_HOR_HIGH_ACT
;
1416 if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_INTERLACED
) {
1419 hrate
= ivideo
->refresh_rate
* VT
/ 2;
1420 drate
= (hrate
* HT
) / 1000;
1421 var
->pixclock
= (u32
) (1000000000 / drate
);
1423 if(ivideo
->sisfb_ypan
) {
1424 maxyres
= sisfb_calc_maxyres(ivideo
, var
);
1425 if(ivideo
->sisfb_max
) {
1426 var
->yres_virtual
= maxyres
;
1428 if(var
->yres_virtual
> maxyres
) {
1429 var
->yres_virtual
= maxyres
;
1432 if(var
->yres_virtual
<= var
->yres
) {
1433 var
->yres_virtual
= var
->yres
;
1436 var
->yres_virtual
= var
->yres
;
1442 sis_getcolreg(unsigned regno
, unsigned *red
, unsigned *green
, unsigned *blue
,
1443 unsigned *transp
, struct fb_info
*info
)
1445 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1447 if(regno
>= ivideo
->video_cmap_len
) return 1;
1449 *red
= ivideo
->sis_palette
[regno
].red
;
1450 *green
= ivideo
->sis_palette
[regno
].green
;
1451 *blue
= ivideo
->sis_palette
[regno
].blue
;
1458 sisfb_setcolreg(unsigned regno
, unsigned red
, unsigned green
, unsigned blue
,
1459 unsigned transp
, struct fb_info
*info
)
1461 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1463 if(regno
>= ivideo
->video_cmap_len
) return 1;
1465 ivideo
->sis_palette
[regno
].red
= red
;
1466 ivideo
->sis_palette
[regno
].green
= green
;
1467 ivideo
->sis_palette
[regno
].blue
= blue
;
1469 switch(ivideo
->video_bpp
) {
1470 #ifdef FBCON_HAS_CFB8
1472 outSISREG(SISDACA
, regno
);
1473 outSISREG(SISDACD
, (red
>> 10));
1474 outSISREG(SISDACD
, (green
>> 10));
1475 outSISREG(SISDACD
, (blue
>> 10));
1476 if(ivideo
->currentvbflags
& VB_DISPTYPE_DISP2
) {
1477 outSISREG(SISDAC2A
, regno
);
1478 outSISREG(SISDAC2D
, (red
>> 8));
1479 outSISREG(SISDAC2D
, (green
>> 8));
1480 outSISREG(SISDAC2D
, (blue
>> 8));
1484 #ifdef FBCON_HAS_CFB16
1486 ivideo
->sis_fbcon_cmap
.cfb16
[regno
] =
1487 ((red
& 0xf800)) | ((green
& 0xfc00) >> 5) | ((blue
& 0xf800) >> 11);
1490 #ifdef FBCON_HAS_CFB32
1495 ivideo
->sis_fbcon_cmap
.cfb32
[regno
] = (red
<< 16) | (green
<< 8) | (blue
);
1504 sisfb_set_disp(int con
, struct fb_var_screeninfo
*var
, struct fb_info
*info
)
1506 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1507 struct display
*display
;
1508 struct display_switch
*sw
;
1509 struct fb_fix_screeninfo fix
;
1512 display
= (con
>= 0) ? &fb_display
[con
] : &ivideo
->sis_disp
;
1514 sisfb_get_fix(&fix
, con
, info
);
1516 display
->var
= *var
;
1517 display
->screen_base
= (char *)ivideo
->video_vbase
;
1518 display
->visual
= fix
.visual
;
1519 display
->type
= fix
.type
;
1520 display
->type_aux
= fix
.type_aux
;
1521 display
->ypanstep
= fix
.ypanstep
;
1522 display
->ywrapstep
= fix
.ywrapstep
;
1523 display
->line_length
= fix
.line_length
;
1524 display
->can_soft_blank
= 1;
1525 display
->inverse
= ivideo
->sisfb_inverse
;
1526 display
->next_line
= fix
.line_length
;
1530 switch(ivideo
->video_bpp
) {
1531 #ifdef FBCON_HAS_CFB8
1532 case 8: sw
= ivideo
->accel
? &fbcon_sis8
: &fbcon_cfb8
;
1535 #ifdef FBCON_HAS_CFB16
1536 case 16:sw
= ivideo
->accel
? &fbcon_sis16
: &fbcon_cfb16
;
1537 display
->dispsw_data
= &ivideo
->sis_fbcon_cmap
.cfb16
;
1540 #ifdef FBCON_HAS_CFB32
1541 case 32:sw
= ivideo
->accel
? &fbcon_sis32
: &fbcon_cfb32
;
1542 display
->dispsw_data
= &ivideo
->sis_fbcon_cmap
.cfb32
;
1545 default:sw
= &fbcon_dummy
;
1548 memcpy(&ivideo
->sisfb_sw
, sw
, sizeof(*sw
));
1549 display
->dispsw
= &ivideo
->sisfb_sw
;
1551 restore_flags(flags
);
1553 if(ivideo
->sisfb_ypan
) {
1554 /* display->scrollmode = 0; */
1556 display
->scrollmode
= SCROLL_YREDRAW
;
1557 ivideo
->sisfb_sw
.bmove
= fbcon_redraw_bmove
;
1562 sisfb_do_install_cmap(int con
, struct fb_info
*info
)
1564 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1566 if(con
!= ivideo
->currcon
) return;
1568 if(fb_display
[con
].cmap
.len
) {
1569 fb_set_cmap(&fb_display
[con
].cmap
, sisfb_setcolreg
, info
);
1571 int size
= sisfb_get_cmap_len(&fb_display
[con
].var
);
1572 fb_set_cmap(fb_default_cmap(size
), sisfb_setcolreg
, info
);
1577 sisfb_get_var(struct fb_var_screeninfo
*var
, int con
, struct fb_info
*info
)
1579 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1582 memcpy(var
, &ivideo
->default_var
, sizeof(struct fb_var_screeninfo
));
1584 *var
= fb_display
[con
].var
;
1587 if(ivideo
->sisfb_fstn
) {
1588 if(var
->xres
== 320 && var
->yres
== 480) var
->yres
= 240;
1595 sisfb_set_var(struct fb_var_screeninfo
*var
, int con
, struct fb_info
*info
)
1597 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1600 fb_display
[con
].var
.activate
= FB_ACTIVATE_NOW
;
1602 if(sisfb_do_set_var(var
, con
== ivideo
->currcon
, info
)) {
1603 sisfb_crtc_to_var(ivideo
, var
);
1607 sisfb_crtc_to_var(ivideo
, var
);
1609 sisfb_set_disp(con
, var
, info
);
1611 if(info
->changevar
) {
1612 (*info
->changevar
)(con
);
1615 if((err
= fb_alloc_cmap(&fb_display
[con
].cmap
, 0, 0))) {
1619 sisfb_do_install_cmap(con
, info
);
1621 #if 0 /* Why was this called here? */
1622 unsigned int cols
, rows
;
1623 cols
= sisbios_mode
[ivideo
->sisfb_mode_idx
].cols
;
1624 rows
= sisbios_mode
[ivideo
->sisfb_mode_idx
].rows
;
1625 vc_resize_con(rows
, cols
, fb_display
[con
].conp
->vc_num
);
1631 sisfb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
, struct fb_info
*info
)
1633 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1634 struct display
*display
;
1636 display
= (con
>= 0) ? &fb_display
[con
] : &ivideo
->sis_disp
;
1638 if(con
== ivideo
->currcon
) {
1640 return fb_get_cmap(cmap
, kspc
, sis_getcolreg
, info
);
1642 } else if(display
->cmap
.len
) {
1644 fb_copy_cmap(&display
->cmap
, cmap
, kspc
? 0 : 2);
1648 int size
= sisfb_get_cmap_len(&display
->var
);
1649 fb_copy_cmap(fb_default_cmap(size
), cmap
, kspc
? 0 : 2);
1657 sisfb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
, struct fb_info
*info
)
1659 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1660 struct display
*display
;
1663 display
= (con
>= 0) ? &fb_display
[con
] : &ivideo
->sis_disp
;
1665 size
= sisfb_get_cmap_len(&display
->var
);
1666 if(display
->cmap
.len
!= size
) {
1667 err
= fb_alloc_cmap(&display
->cmap
, size
, 0);
1671 if(con
== ivideo
->currcon
) {
1672 return fb_set_cmap(cmap
, kspc
, sisfb_setcolreg
, info
);
1674 fb_copy_cmap(cmap
, &display
->cmap
, kspc
? 0 : 1);
1681 sisfb_pan_display(struct fb_var_screeninfo
*var
, int con
, struct fb_info
* info
)
1683 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1686 if(var
->vmode
& FB_VMODE_YWRAP
) return -EINVAL
;
1688 if((var
->xoffset
+fb_display
[con
].var
.xres
> fb_display
[con
].var
.xres_virtual
) ||
1689 (var
->yoffset
+fb_display
[con
].var
.yres
> fb_display
[con
].var
.yres_virtual
)) {
1693 if(con
== ivideo
->currcon
) {
1694 if((err
= sisfb_pan_var(ivideo
, var
)) < 0) return err
;
1697 fb_display
[con
].var
.xoffset
= var
->xoffset
;
1698 fb_display
[con
].var
.yoffset
= var
->yoffset
;
1704 sisfb_update_var(int con
, struct fb_info
*info
)
1706 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1708 return(sisfb_pan_var(ivideo
, &fb_display
[con
].var
));
1712 sisfb_switch(int con
, struct fb_info
*info
)
1714 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1717 if(fb_display
[ivideo
->currcon
].cmap
.len
) {
1718 fb_get_cmap(&fb_display
[ivideo
->currcon
].cmap
, 1, sis_getcolreg
, info
);
1721 fb_display
[con
].var
.activate
= FB_ACTIVATE_NOW
;
1723 if(!memcmp(&fb_display
[con
].var
, &fb_display
[ivideo
->currcon
].var
,
1724 sizeof(struct fb_var_screeninfo
))) {
1725 ivideo
->currcon
= con
;
1729 ivideo
->currcon
= con
;
1731 sisfb_do_set_var(&fb_display
[con
].var
, 1, info
);
1733 sisfb_set_disp(con
, &fb_display
[con
].var
, info
);
1735 sisfb_do_install_cmap(con
, info
);
1737 cols
= sisbios_mode
[ivideo
->sisfb_mode_idx
].cols
;
1738 rows
= sisbios_mode
[ivideo
->sisfb_mode_idx
].rows
;
1739 vc_resize_con(rows
, cols
, fb_display
[con
].conp
->vc_num
);
1741 sisfb_update_var(con
, info
);
1747 sisfb_blank(int blank
, struct fb_info
*info
)
1749 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1751 sisfb_myblank(ivideo
, blank
);
1755 /* ------------ FBDev related routines for 2.6 series ----------- */
1757 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1760 sisfb_open(struct fb_info
*info
, int user
)
1766 sisfb_release(struct fb_info
*info
, int user
)
1772 sisfb_setcolreg(unsigned regno
, unsigned red
, unsigned green
, unsigned blue
,
1773 unsigned transp
, struct fb_info
*info
)
1775 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1777 if(regno
>= sisfb_get_cmap_len(&info
->var
)) return 1;
1779 switch(info
->var
.bits_per_pixel
) {
1781 outSISREG(SISDACA
, regno
);
1782 outSISREG(SISDACD
, (red
>> 10));
1783 outSISREG(SISDACD
, (green
>> 10));
1784 outSISREG(SISDACD
, (blue
>> 10));
1785 if(ivideo
->currentvbflags
& VB_DISPTYPE_DISP2
) {
1786 outSISREG(SISDAC2A
, regno
);
1787 outSISREG(SISDAC2D
, (red
>> 8));
1788 outSISREG(SISDAC2D
, (green
>> 8));
1789 outSISREG(SISDAC2D
, (blue
>> 8));
1793 ((u32
*)(info
->pseudo_palette
))[regno
] =
1794 ((red
& 0xf800)) | ((green
& 0xfc00) >> 5) | ((blue
& 0xf800) >> 11);
1800 ((u32
*)(info
->pseudo_palette
))[regno
] =
1801 (red
<< 16) | (green
<< 8) | (blue
);
1808 sisfb_set_par(struct fb_info
*info
)
1812 if((err
= sisfb_do_set_var(&info
->var
, 1, info
))) {
1816 sisfb_get_fix(&info
->fix
, info
->currcon
, info
);
1822 sisfb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
1824 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
1825 unsigned int htotal
= 0, vtotal
= 0, myrateindex
= 0;
1826 unsigned int drate
= 0, hrate
= 0, maxyres
;
1828 int refresh_rate
, search_idx
;
1829 BOOLEAN recalc_clock
= FALSE
;
1832 htotal
= var
->left_margin
+ var
->xres
+ var
->right_margin
+ var
->hsync_len
;
1834 vtotal
= var
->upper_margin
+ var
->lower_margin
+ var
->vsync_len
;
1836 pixclock
= var
->pixclock
;
1838 if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_NONINTERLACED
) {
1839 vtotal
+= var
->yres
;
1841 } else if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_DOUBLE
) {
1842 vtotal
+= var
->yres
;
1844 } else if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_INTERLACED
) {
1845 vtotal
+= var
->yres
;
1847 } else vtotal
+= var
->yres
;
1849 if(!(htotal
) || !(vtotal
)) {
1850 SISFAIL("sisfb: no valid timing data");
1854 while( (sisbios_mode
[search_idx
].mode_no
[0] != 0) &&
1855 (sisbios_mode
[search_idx
].xres
<= var
->xres
) ) {
1856 if( (sisbios_mode
[search_idx
].xres
== var
->xres
) &&
1857 (sisbios_mode
[search_idx
].yres
== var
->yres
) &&
1858 (sisbios_mode
[search_idx
].bpp
== var
->bits_per_pixel
)) {
1859 if(sisfb_validate_mode(ivideo
, search_idx
, ivideo
->currentvbflags
) > 0) {
1869 while(sisbios_mode
[search_idx
].mode_no
[0] != 0) {
1870 if( (var
->xres
<= sisbios_mode
[search_idx
].xres
) &&
1871 (var
->yres
<= sisbios_mode
[search_idx
].yres
) &&
1872 (var
->bits_per_pixel
== sisbios_mode
[search_idx
].bpp
) ) {
1873 if(sisfb_validate_mode(ivideo
,search_idx
, ivideo
->currentvbflags
) > 0) {
1881 printk(KERN_DEBUG
"sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1882 var
->xres
, var
->yres
, var
->bits_per_pixel
,
1883 sisbios_mode
[search_idx
].xres
,
1884 sisbios_mode
[search_idx
].yres
,
1885 var
->bits_per_pixel
);
1886 var
->xres
= sisbios_mode
[search_idx
].xres
;
1887 var
->yres
= sisbios_mode
[search_idx
].yres
;
1891 printk(KERN_ERR
"sisfb: Failed to find supported mode near %dx%dx%d\n",
1892 var
->xres
, var
->yres
, var
->bits_per_pixel
);
1897 if( ((ivideo
->vbflags
& VB_LVDS
) || /* Slave modes on LVDS and 301B-DH */
1898 ((ivideo
->vbflags
& VB_30xBDH
) && (ivideo
->currentvbflags
& CRT2_LCD
))) &&
1899 (var
->bits_per_pixel
== 8) ) {
1901 recalc_clock
= TRUE
;
1902 } else if( (ivideo
->current_htotal
== htotal
) && /* x=x & y=y & c=c -> assume depth change */
1903 (ivideo
->current_vtotal
== vtotal
) &&
1904 (ivideo
->current_pixclock
== pixclock
) ) {
1905 drate
= 1000000000 / pixclock
;
1906 hrate
= (drate
* 1000) / htotal
;
1907 refresh_rate
= (unsigned int) (hrate
* 2 / vtotal
);
1908 } else if( ( (ivideo
->current_htotal
!= htotal
) || /* x!=x | y!=y & c=c -> invalid pixclock */
1909 (ivideo
->current_vtotal
!= vtotal
) ) &&
1910 (ivideo
->current_pixclock
== var
->pixclock
) ) {
1911 if(ivideo
->sisfb_lastrates
[sisbios_mode
[search_idx
].mode_no
[ivideo
->mni
]]) {
1912 refresh_rate
= ivideo
->sisfb_lastrates
[sisbios_mode
[search_idx
].mode_no
[ivideo
->mni
]];
1913 } else if(ivideo
->sisfb_parm_rate
!= -1) {
1914 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1915 refresh_rate
= ivideo
->sisfb_parm_rate
;
1919 recalc_clock
= TRUE
;
1920 } else if((pixclock
) && (htotal
) && (vtotal
)) {
1921 drate
= 1000000000 / pixclock
;
1922 hrate
= (drate
* 1000) / htotal
;
1923 refresh_rate
= (unsigned int) (hrate
* 2 / vtotal
);
1924 } else if(ivideo
->current_refresh_rate
) {
1925 refresh_rate
= ivideo
->current_refresh_rate
;
1926 recalc_clock
= TRUE
;
1929 recalc_clock
= TRUE
;
1932 myrateindex
= sisfb_search_refresh_rate(ivideo
, refresh_rate
, search_idx
);
1934 /* Eventually recalculate timing and clock */
1936 if(!myrateindex
) myrateindex
= sisbios_mode
[search_idx
].rate_idx
;
1937 var
->pixclock
= (u32
) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo
->SiS_Pr
,
1939 sisbios_mode
[search_idx
].mode_no
[ivideo
->mni
],
1941 sisfb_mode_rate_to_ddata(&ivideo
->SiS_Pr
, &ivideo
->sishw_ext
,
1942 sisbios_mode
[search_idx
].mode_no
[ivideo
->mni
], myrateindex
, var
);
1943 if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_DOUBLE
) {
1944 var
->pixclock
<<= 1;
1948 if(ivideo
->sisfb_thismonitor
.datavalid
) {
1949 if(!sisfb_verify_rate(ivideo
, &ivideo
->sisfb_thismonitor
, search_idx
,
1950 myrateindex
, refresh_rate
)) {
1951 printk(KERN_INFO
"sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1955 /* Adapt RGB settings */
1956 sisfb_bpp_to_var(ivideo
, var
);
1958 /* Sanity check for offsets */
1959 if(var
->xoffset
< 0) var
->xoffset
= 0;
1960 if(var
->yoffset
< 0) var
->yoffset
= 0;
1962 if(var
->xres
> var
->xres_virtual
) {
1963 var
->xres_virtual
= var
->xres
;
1966 if(ivideo
->sisfb_ypan
) {
1967 maxyres
= sisfb_calc_maxyres(ivideo
, var
);
1968 if(ivideo
->sisfb_max
) {
1969 var
->yres_virtual
= maxyres
;
1971 if(var
->yres_virtual
> maxyres
) {
1972 var
->yres_virtual
= maxyres
;
1975 if(var
->yres_virtual
<= var
->yres
) {
1976 var
->yres_virtual
= var
->yres
;
1979 if(var
->yres
!= var
->yres_virtual
) {
1980 var
->yres_virtual
= var
->yres
;
1986 /* Truncate offsets to maximum if too high */
1987 if(var
->xoffset
> var
->xres_virtual
- var
->xres
) {
1988 var
->xoffset
= var
->xres_virtual
- var
->xres
- 1;
1991 if(var
->yoffset
> var
->yres_virtual
- var
->yres
) {
1992 var
->yoffset
= var
->yres_virtual
- var
->yres
- 1;
1995 /* Set everything else to 0 */
1996 var
->red
.msb_right
=
1997 var
->green
.msb_right
=
1998 var
->blue
.msb_right
=
1999 var
->transp
.offset
=
2000 var
->transp
.length
=
2001 var
->transp
.msb_right
= 0;
2007 sisfb_pan_display(struct fb_var_screeninfo
*var
, struct fb_info
* info
)
2009 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
2012 if(var
->xoffset
> (var
->xres_virtual
- var
->xres
)) {
2015 if(var
->yoffset
> (var
->yres_virtual
- var
->yres
)) {
2019 if(var
->vmode
& FB_VMODE_YWRAP
) return -EINVAL
;
2021 if(var
->xoffset
+ info
->var
.xres
> info
->var
.xres_virtual
||
2022 var
->yoffset
+ info
->var
.yres
> info
->var
.yres_virtual
) {
2026 if((err
= sisfb_pan_var(ivideo
, var
)) < 0) return err
;
2028 info
->var
.xoffset
= var
->xoffset
;
2029 info
->var
.yoffset
= var
->yoffset
;
2035 sisfb_blank(int blank
, struct fb_info
*info
)
2037 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
2039 return(sisfb_myblank(ivideo
, blank
));
2044 /* ----------- FBDev related routines for all series ---------- */
2047 sisfb_ioctl(struct inode
*inode
, struct file
*file
,
2048 unsigned int cmd
, unsigned long arg
,
2049 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2052 struct fb_info
*info
)
2054 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
2055 struct sis_memreq sismemreq
;
2056 struct fb_vblank sisvbblank
;
2059 static int count
= 0;
2060 u32 __user
*argp
= (u32 __user
*) arg
;
2064 if(!capable(CAP_SYS_RAWIO
)) {
2067 if(copy_from_user(&sismemreq
, argp
, sizeof(sismemreq
))) {
2070 sis_malloc(&sismemreq
);
2071 if(copy_to_user(argp
, &sismemreq
, sizeof(sismemreq
))) {
2072 sis_free((u32
)sismemreq
.offset
);
2078 if(!capable(CAP_SYS_RAWIO
)) {
2081 if(get_user(gpu32
, argp
)) {
2087 case FBIOGET_VBLANK
:
2088 sisvbblank
.count
= 0;
2089 sisvbblank
.flags
= sisfb_setupvbblankflags(ivideo
, &sisvbblank
.vcount
, &sisvbblank
.hcount
);
2090 if(copy_to_user(argp
, &sisvbblank
, sizeof(sisvbblank
))) {
2095 case SISFB_GET_INFO_SIZE
:
2096 return put_user(sizeof(sisfb_info
), argp
);
2098 case SISFB_GET_INFO_OLD
:
2100 printk(KERN_INFO
"sisfb: Deprecated ioctl call received - update your application!\n");
2102 case SISFB_GET_INFO
: /* For communication with X driver */
2103 x
.sisfb_id
= SISFB_ID
;
2104 x
.sisfb_version
= VER_MAJOR
;
2105 x
.sisfb_revision
= VER_MINOR
;
2106 x
.sisfb_patchlevel
= VER_LEVEL
;
2107 x
.chip_id
= ivideo
->chip_id
;
2108 x
.memory
= ivideo
->video_size
/ 1024;
2109 x
.heapstart
= ivideo
->heapstart
/ 1024;
2110 if(ivideo
->modechanged
) {
2111 x
.fbvidmode
= ivideo
->mode_no
;
2113 x
.fbvidmode
= ivideo
->modeprechange
;
2115 x
.sisfb_caps
= ivideo
->caps
;
2116 x
.sisfb_tqlen
= 512; /* yet fixed */
2117 x
.sisfb_pcibus
= ivideo
->pcibus
;
2118 x
.sisfb_pcislot
= ivideo
->pcislot
;
2119 x
.sisfb_pcifunc
= ivideo
->pcifunc
;
2120 x
.sisfb_lcdpdc
= ivideo
->detectedpdc
;
2121 x
.sisfb_lcdpdca
= ivideo
->detectedpdca
;
2122 x
.sisfb_lcda
= ivideo
->detectedlcda
;
2123 x
.sisfb_vbflags
= ivideo
->vbflags
;
2124 x
.sisfb_currentvbflags
= ivideo
->currentvbflags
;
2125 x
.sisfb_scalelcd
= ivideo
->SiS_Pr
.UsePanelScaler
;
2126 x
.sisfb_specialtiming
= ivideo
->SiS_Pr
.SiS_CustomT
;
2127 x
.sisfb_haveemi
= ivideo
->SiS_Pr
.HaveEMI
? 1 : 0;
2128 x
.sisfb_haveemilcd
= ivideo
->SiS_Pr
.HaveEMILCD
? 1 : 0;
2129 x
.sisfb_emi30
= ivideo
->SiS_Pr
.EMI_30
;
2130 x
.sisfb_emi31
= ivideo
->SiS_Pr
.EMI_31
;
2131 x
.sisfb_emi32
= ivideo
->SiS_Pr
.EMI_32
;
2132 x
.sisfb_emi33
= ivideo
->SiS_Pr
.EMI_33
;
2133 x
.sisfb_tvxpos
= (u16
)(ivideo
->tvxpos
+ 32);
2134 x
.sisfb_tvypos
= (u16
)(ivideo
->tvypos
+ 32);
2136 if(copy_to_user(argp
, &x
, sizeof(x
))) {
2141 case SISFB_GET_VBRSTATUS_OLD
:
2143 printk(KERN_INFO
"sisfb: Deprecated ioctl call received - update your application!\n");
2145 case SISFB_GET_VBRSTATUS
:
2146 if(sisfb_CheckVBRetrace(ivideo
)) {
2147 return put_user((u32
)1, argp
);
2149 return put_user((u32
)0, argp
);
2152 case SISFB_GET_AUTOMAXIMIZE_OLD
:
2154 printk(KERN_INFO
"sisfb: Deprecated ioctl call received - update your application!\n");
2156 case SISFB_GET_AUTOMAXIMIZE
:
2157 if(ivideo
->sisfb_max
) return put_user((u32
)1, argp
);
2158 else return put_user((u32
)0, argp
);
2160 case SISFB_SET_AUTOMAXIMIZE_OLD
:
2162 printk(KERN_INFO
"sisfb: Deprecated ioctl call received - update your application!\n");
2164 case SISFB_SET_AUTOMAXIMIZE
:
2165 if(copy_from_user(&gpu32
, argp
, sizeof(gpu32
))) {
2168 ivideo
->sisfb_max
= (gpu32
) ? 1 : 0;
2171 case SISFB_SET_TVPOSOFFSET
:
2172 if(copy_from_user(&gpu32
, argp
, sizeof(gpu32
))) {
2175 sisfb_set_TVxposoffset(ivideo
, ((int)(gpu32
>> 16)) - 32);
2176 sisfb_set_TVyposoffset(ivideo
, ((int)(gpu32
& 0xffff)) - 32);
2179 case SISFB_GET_TVPOSOFFSET
:
2180 return put_user((u32
)(((ivideo
->tvxpos
+32)<<16)|((ivideo
->tvypos
+32)&0xffff)), argp
);
2182 case SISFB_SET_LOCK
:
2183 if(copy_from_user(&gpu32
, argp
, sizeof(gpu32
))) {
2186 ivideo
->sisfblocked
= (gpu32
) ? 1 : 0;
2196 sisfb_get_fix(struct fb_fix_screeninfo
*fix
, int con
, struct fb_info
*info
)
2198 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
2200 memset(fix
, 0, sizeof(struct fb_fix_screeninfo
));
2202 strcpy(fix
->id
, ivideo
->myid
);
2204 fix
->smem_start
= ivideo
->video_base
;
2205 fix
->smem_len
= ivideo
->sisfb_mem
;
2206 fix
->type
= FB_TYPE_PACKED_PIXELS
;
2208 fix
->visual
= (ivideo
->video_bpp
== 8) ? FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_TRUECOLOR
;
2210 fix
->ypanstep
= (ivideo
->sisfb_ypan
) ? 1 : 0;
2212 fix
->line_length
= ivideo
->video_linelength
;
2213 fix
->mmio_start
= ivideo
->mmio_base
;
2214 fix
->mmio_len
= ivideo
->mmio_size
;
2215 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
2216 fix
->accel
= FB_ACCEL_SIS_GLAMOUR
;
2217 } else if((ivideo
->chip
== SIS_330
) || (ivideo
->chip
== SIS_760
)) {
2218 fix
->accel
= FB_ACCEL_SIS_XABRE
;
2220 fix
->accel
= FB_ACCEL_SIS_GLAMOUR_2
;
2226 /* ---------------- fb_ops structures ----------------- */
2228 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2229 static struct fb_ops sisfb_ops
= {
2230 .owner
= THIS_MODULE
,
2231 .fb_get_fix
= sisfb_get_fix
,
2232 .fb_get_var
= sisfb_get_var
,
2233 .fb_set_var
= sisfb_set_var
,
2234 .fb_get_cmap
= sisfb_get_cmap
,
2235 .fb_set_cmap
= sisfb_set_cmap
,
2236 .fb_pan_display
= sisfb_pan_display
,
2237 .fb_ioctl
= sisfb_ioctl
2241 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
2242 static struct fb_ops sisfb_ops
= {
2243 .owner
= THIS_MODULE
,
2244 .fb_open
= sisfb_open
,
2245 .fb_release
= sisfb_release
,
2246 .fb_check_var
= sisfb_check_var
,
2247 .fb_set_par
= sisfb_set_par
,
2248 .fb_setcolreg
= sisfb_setcolreg
,
2249 .fb_pan_display
= sisfb_pan_display
,
2250 .fb_blank
= sisfb_blank
,
2251 .fb_fillrect
= fbcon_sis_fillrect
,
2252 .fb_copyarea
= fbcon_sis_copyarea
,
2253 .fb_imageblit
= cfb_imageblit
,
2254 .fb_cursor
= soft_cursor
,
2255 .fb_sync
= fbcon_sis_sync
,
2256 .fb_ioctl
= sisfb_ioctl
2260 /* ---------------- Chip generation dependent routines ---------------- */
2262 static struct pci_dev
* sisfb_get_northbridge(int basechipid
)
2264 struct pci_dev
*pdev
= NULL
;
2265 int nbridgenum
, nbridgeidx
, i
;
2266 const unsigned short nbridgeids
[] = {
2267 PCI_DEVICE_ID_SI_540
, /* for SiS 540 VGA */
2268 PCI_DEVICE_ID_SI_630
, /* for SiS 630/730 VGA */
2269 PCI_DEVICE_ID_SI_730
,
2270 PCI_DEVICE_ID_SI_550
, /* for SiS 550 VGA */
2271 PCI_DEVICE_ID_SI_650
, /* for SiS 650/651/740 VGA */
2272 PCI_DEVICE_ID_SI_651
,
2273 PCI_DEVICE_ID_SI_740
,
2274 PCI_DEVICE_ID_SI_661
, /* for SiS 661/741/660/760 VGA */
2275 PCI_DEVICE_ID_SI_741
,
2276 PCI_DEVICE_ID_SI_660
,
2277 PCI_DEVICE_ID_SI_760
2280 switch(basechipid
) {
2281 #ifdef CONFIG_FB_SIS_300
2282 case SIS_540
: nbridgeidx
= 0; nbridgenum
= 1; break;
2283 case SIS_630
: nbridgeidx
= 1; nbridgenum
= 2; break;
2285 #ifdef CONFIG_FB_SIS_315
2286 case SIS_550
: nbridgeidx
= 3; nbridgenum
= 1; break;
2287 case SIS_650
: nbridgeidx
= 4; nbridgenum
= 3; break;
2288 case SIS_660
: nbridgeidx
= 7; nbridgenum
= 4; break;
2290 default: return NULL
;
2292 for(i
= 0; i
< nbridgenum
; i
++) {
2293 if((pdev
= pci_find_device(PCI_VENDOR_ID_SI
, nbridgeids
[nbridgeidx
+i
], NULL
))) break;
2298 static int __devinit
sisfb_get_dram_size(struct sis_video_info
*ivideo
)
2300 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2304 ivideo
->video_size
= 0;
2306 switch(ivideo
->chip
) {
2307 #ifdef CONFIG_FB_SIS_300
2309 inSISIDXREG(SISSR
, 0x14, reg
);
2310 ivideo
->video_size
= ((reg
& 0x3F) + 1) << 20;
2315 if(!ivideo
->nbridge
) return -1;
2316 pci_read_config_byte(ivideo
->nbridge
, 0x63, ®
);
2317 ivideo
->video_size
= 1 << (((reg
& 0x70) >> 4) + 21);
2320 #ifdef CONFIG_FB_SIS_315
2324 inSISIDXREG(SISSR
, 0x14, reg
);
2325 ivideo
->video_size
= (1 << ((reg
& 0xf0) >> 4)) << 20;
2326 switch((reg
>> 2) & 0x03) {
2329 ivideo
->video_size
<<= 1;
2332 ivideo
->video_size
+= (ivideo
->video_size
/2);
2336 inSISIDXREG(SISSR
, 0x14, reg
);
2337 ivideo
->video_size
= (1 << ((reg
& 0xf0) >> 4)) << 20;
2338 if(reg
& 0x0c) ivideo
->video_size
<<= 1;
2343 inSISIDXREG(SISSR
, 0x14, reg
);
2344 ivideo
->video_size
= (((reg
& 0x3f) + 1) << 2) << 20;
2348 inSISIDXREG(SISCR
, 0x79, reg
);
2349 ivideo
->video_size
= (1 << ((reg
& 0xf0) >> 4)) << 20;
2353 inSISIDXREG(SISCR
, 0x79, reg
);
2354 reg
= (reg
& 0xf0) >> 4;
2355 if(reg
) ivideo
->video_size
= (1 << reg
) << 20;
2356 inSISIDXREG(SISCR
, 0x78, reg
);
2359 if(reg
== 0x10) ivideo
->video_size
+= (32 << 20);
2360 else ivideo
->video_size
+= (64 << 20);
2370 /* -------------- video bridge device detection --------------- */
2372 static void __devinit
sisfb_detect_VB_connect(struct sis_video_info
*ivideo
)
2376 #ifdef CONFIG_FB_SIS_300
2377 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
2378 inSISIDXREG(SISSR
, 0x17, temp
);
2379 if((temp
& 0x0F) && (ivideo
->chip
!= SIS_300
)) {
2380 /* PAL/NTSC is stored on SR16 on such machines */
2381 if(!(ivideo
->vbflags
& (TV_PAL
| TV_NTSC
| TV_PALM
| TV_PALN
))) {
2382 inSISIDXREG(SISSR
, 0x16, temp
);
2384 ivideo
->vbflags
|= TV_PAL
;
2386 ivideo
->vbflags
|= TV_NTSC
;
2392 inSISIDXREG(SISCR
, 0x32, cr32
);
2394 if(cr32
& SIS_CRT1
) {
2395 ivideo
->sisfb_crt1off
= 0;
2397 ivideo
->sisfb_crt1off
= (cr32
& 0xDF) ? 1 : 0;
2400 ivideo
->vbflags
&= ~(CRT2_TV
| CRT2_LCD
| CRT2_VGA
);
2402 if(cr32
& SIS_VB_TV
) ivideo
->vbflags
|= CRT2_TV
;
2403 if(cr32
& SIS_VB_LCD
) ivideo
->vbflags
|= CRT2_LCD
;
2404 if(cr32
& SIS_VB_CRT2
) ivideo
->vbflags
|= CRT2_VGA
;
2406 /* Check given parms for hardware compatibility.
2407 * (Cannot do this in the search_xx routines since we don't
2408 * know what hardware we are running on then)
2411 if(ivideo
->chip
!= SIS_550
) {
2412 ivideo
->sisfb_dstn
= ivideo
->sisfb_fstn
= 0;
2415 if(ivideo
->sisfb_tvplug
!= -1) {
2416 if( (ivideo
->sisvga_engine
!= SIS_315_VGA
) ||
2417 (!(ivideo
->vbflags
& (VB_301C
|VB_301LV
|VB_302LV
))) ) {
2418 if(ivideo
->sisfb_tvplug
& TV_YPBPR
) {
2419 ivideo
->sisfb_tvplug
= -1;
2420 printk(KERN_ERR
"sisfb: YPbPr not supported\n");
2424 if(ivideo
->sisfb_tvplug
!= -1) {
2425 if( (ivideo
->sisvga_engine
!= SIS_315_VGA
) ||
2426 (!(ivideo
->vbflags
& (VB_301
|VB_301B
|VB_302B
))) ) {
2427 if(ivideo
->sisfb_tvplug
& TV_HIVISION
) {
2428 ivideo
->sisfb_tvplug
= -1;
2429 printk(KERN_ERR
"sisfb: HiVision not supported\n");
2433 if(ivideo
->sisfb_tvstd
!= -1) {
2434 if( (!(ivideo
->vbflags
& VB_SISBRIDGE
)) &&
2435 (!((ivideo
->sisvga_engine
== SIS_315_VGA
) && (ivideo
->vbflags
& VB_CHRONTEL
))) ) {
2436 if(ivideo
->sisfb_tvstd
& (TV_PALN
| TV_PALN
| TV_NTSCJ
)) {
2437 ivideo
->sisfb_tvstd
= -1;
2438 printk(KERN_ERR
"sisfb: PALM/PALN/NTSCJ not supported\n");
2443 /* Detect/set TV plug & type */
2444 if(ivideo
->sisfb_tvplug
!= -1) {
2445 ivideo
->vbflags
|= ivideo
->sisfb_tvplug
;
2447 if(cr32
& SIS_VB_YPBPR
) ivideo
->vbflags
|= (TV_YPBPR
|TV_YPBPR525I
); /* default: 480i */
2448 else if(cr32
& SIS_VB_HIVISION
) ivideo
->vbflags
|= TV_HIVISION
;
2449 else if(cr32
& SIS_VB_SCART
) ivideo
->vbflags
|= TV_SCART
;
2451 if(cr32
& SIS_VB_SVIDEO
) ivideo
->vbflags
|= TV_SVIDEO
;
2452 if(cr32
& SIS_VB_COMPOSITE
) ivideo
->vbflags
|= TV_AVIDEO
;
2456 if(!(ivideo
->vbflags
& (TV_YPBPR
| TV_HIVISION
))) {
2457 if(ivideo
->sisfb_tvstd
!= -1) {
2458 ivideo
->vbflags
&= ~(TV_NTSC
| TV_PAL
| TV_PALM
| TV_PALN
| TV_NTSCJ
);
2459 ivideo
->vbflags
|= ivideo
->sisfb_tvstd
;
2461 if(ivideo
->vbflags
& TV_SCART
) {
2462 ivideo
->vbflags
&= ~(TV_NTSC
| TV_PALM
| TV_PALN
| TV_NTSCJ
);
2463 ivideo
->vbflags
|= TV_PAL
;
2465 if(!(ivideo
->vbflags
& (TV_PAL
| TV_NTSC
| TV_PALM
| TV_PALN
| TV_NTSCJ
))) {
2466 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
2467 inSISIDXREG(SISSR
, 0x38, temp
);
2468 if(temp
& 0x01) ivideo
->vbflags
|= TV_PAL
;
2469 else ivideo
->vbflags
|= TV_NTSC
;
2470 } else if((ivideo
->chip
<= SIS_315PRO
) || (ivideo
->chip
>= SIS_330
)) {
2471 inSISIDXREG(SISSR
, 0x38, temp
);
2472 if(temp
& 0x01) ivideo
->vbflags
|= TV_PAL
;
2473 else ivideo
->vbflags
|= TV_NTSC
;
2475 inSISIDXREG(SISCR
, 0x79, temp
);
2476 if(temp
& 0x20) ivideo
->vbflags
|= TV_PAL
;
2477 else ivideo
->vbflags
|= TV_NTSC
;
2482 /* Copy forceCRT1 option to CRT1off if option is given */
2483 if(ivideo
->sisfb_forcecrt1
!= -1) {
2484 ivideo
->sisfb_crt1off
= (ivideo
->sisfb_forcecrt1
) ? 0 : 1;
2488 static void __devinit
sisfb_get_VB_type(struct sis_video_info
*ivideo
)
2490 char stdstr
[] = "sisfb: Detected";
2491 char bridgestr
[] = "video bridge";
2495 inSISIDXREG(SISPART4
, 0x00, vb_chipid
);
2498 inSISIDXREG(SISPART4
, 0x01, reg
);
2500 ivideo
->vbflags
|= VB_301
;
2501 printk(KERN_INFO
"%s SiS301 %s\n", stdstr
, bridgestr
);
2502 } else if(reg
< 0xc0) {
2503 ivideo
->vbflags
|= VB_301B
;
2504 inSISIDXREG(SISPART4
,0x23,reg
);
2506 ivideo
->vbflags
|= VB_30xBDH
;
2507 printk(KERN_INFO
"%s SiS301B-DH %s\n", stdstr
, bridgestr
);
2509 printk(KERN_INFO
"%s SiS301B %s\n", stdstr
, bridgestr
);
2511 } else if(reg
< 0xd0) {
2512 ivideo
->vbflags
|= VB_301C
;
2513 printk(KERN_INFO
"%s SiS301C %s\n", stdstr
, bridgestr
);
2514 } else if(reg
< 0xe0) {
2515 ivideo
->vbflags
|= VB_301LV
;
2516 printk(KERN_INFO
"%s SiS301LV %s\n", stdstr
, bridgestr
);
2517 } else if(reg
<= 0xe1) {
2518 inSISIDXREG(SISPART4
,0x39,reg
);
2520 ivideo
->vbflags
|= VB_302LV
;
2521 printk(KERN_INFO
"%s SiS302LV %s\n", stdstr
, bridgestr
);
2523 ivideo
->vbflags
|= VB_301C
;
2524 printk(KERN_INFO
"%s SiS301C(P4) %s\n", stdstr
, bridgestr
);
2526 ivideo
->vbflags
|= VB_302ELV
;
2527 printk(KERN_INFO
"%s SiS302ELV %s\n", stdstr
, bridgestr
);
2533 ivideo
->vbflags
|= VB_302B
;
2534 printk(KERN_INFO
"%s SiS302B %s\n", stdstr
, bridgestr
);
2538 if((!(ivideo
->vbflags
& VB_VIDEOBRIDGE
)) && (ivideo
->chip
!= SIS_300
)) {
2539 inSISIDXREG(SISCR
, 0x37, reg
);
2540 reg
&= SIS_EXTERNAL_CHIP_MASK
;
2542 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
2543 #ifdef CONFIG_FB_SIS_300
2545 case SIS_EXTERNAL_CHIP_LVDS
:
2546 ivideo
->vbflags
|= VB_LVDS
;
2548 case SIS_EXTERNAL_CHIP_TRUMPION
:
2549 ivideo
->vbflags
|= VB_TRUMPION
;
2551 case SIS_EXTERNAL_CHIP_CHRONTEL
:
2552 ivideo
->vbflags
|= VB_CHRONTEL
;
2554 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL
:
2555 ivideo
->vbflags
|= (VB_LVDS
| VB_CHRONTEL
);
2558 if(ivideo
->vbflags
& VB_CHRONTEL
) ivideo
->chronteltype
= 1;
2560 } else if(ivideo
->chip
< SIS_661
) {
2561 #ifdef CONFIG_FB_SIS_315
2563 case SIS310_EXTERNAL_CHIP_LVDS
:
2564 ivideo
->vbflags
|= VB_LVDS
;
2566 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL
:
2567 ivideo
->vbflags
|= (VB_LVDS
| VB_CHRONTEL
);
2570 if(ivideo
->vbflags
& VB_CHRONTEL
) ivideo
->chronteltype
= 2;
2572 } else if(ivideo
->chip
>= SIS_661
) {
2573 #ifdef CONFIG_FB_SIS_315
2574 inSISIDXREG(SISCR
, 0x38, reg
);
2578 ivideo
->vbflags
|= VB_LVDS
;
2581 ivideo
->vbflags
|= (VB_LVDS
| VB_CHRONTEL
);
2584 ivideo
->vbflags
|= (VB_LVDS
| VB_CONEXANT
);
2587 if(ivideo
->vbflags
& VB_CHRONTEL
) ivideo
->chronteltype
= 2;
2590 if(ivideo
->vbflags
& VB_LVDS
) {
2591 printk(KERN_INFO
"%s LVDS transmitter\n", stdstr
);
2593 if(ivideo
->vbflags
& VB_TRUMPION
) {
2594 printk(KERN_INFO
"%s Trumpion Zurac LCD scaler\n", stdstr
);
2596 if(ivideo
->vbflags
& VB_CHRONTEL
) {
2597 printk(KERN_INFO
"%s Chrontel TV encoder\n", stdstr
);
2599 if(ivideo
->vbflags
& VB_CONEXANT
) {
2600 printk(KERN_INFO
"%s Conexant external device\n", stdstr
);
2604 if(ivideo
->vbflags
& VB_SISBRIDGE
) {
2605 SiS_Sense30x(ivideo
);
2606 } else if(ivideo
->vbflags
& VB_CHRONTEL
) {
2607 SiS_SenseCh(ivideo
);
2611 /* ------------------ Sensing routines ------------------ */
2613 static BOOLEAN __devinit
sisfb_test_DDC1(struct sis_video_info
*ivideo
)
2618 old
= SiS_ReadDDC1Bit(&ivideo
->SiS_Pr
);
2620 if(old
!= SiS_ReadDDC1Bit(&ivideo
->SiS_Pr
)) break;
2622 return (count
== -1) ? FALSE
: TRUE
;
2625 static void __devinit
sisfb_sense_crt1(struct sis_video_info
*ivideo
)
2627 BOOLEAN mustwait
= FALSE
;
2629 #ifdef CONFIG_FB_SIS_315
2635 inSISIDXREG(SISSR
,0x1F,SR1F
);
2636 orSISIDXREG(SISSR
,0x1F,0x04);
2637 andSISIDXREG(SISSR
,0x1F,0x3F);
2638 if(SR1F
& 0xc0) mustwait
= TRUE
;
2640 #ifdef CONFIG_FB_SIS_315
2641 if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
2642 inSISIDXREG(SISCR
,ivideo
->SiS_Pr
.SiS_MyCR63
,CR63
);
2644 andSISIDXREG(SISCR
,ivideo
->SiS_Pr
.SiS_MyCR63
,0xBF);
2648 inSISIDXREG(SISCR
,0x17,CR17
);
2651 orSISIDXREG(SISCR
,0x17,0x80);
2653 outSISIDXREG(SISSR
, 0x00, 0x01);
2654 outSISIDXREG(SISSR
, 0x00, 0x03);
2658 for(i
=0; i
< 10; i
++) sisfbwaitretracecrt1(ivideo
);
2661 #ifdef CONFIG_FB_SIS_315
2662 if(ivideo
->chip
>= SIS_330
) {
2663 andSISIDXREG(SISCR
,0x32,~0x20);
2664 if(ivideo
->chip
>= SIS_340
) {
2665 outSISIDXREG(SISCR
, 0x57, 0x4a);
2667 outSISIDXREG(SISCR
, 0x57, 0x5f);
2669 orSISIDXREG(SISCR
, 0x53, 0x02);
2670 while((inSISREG(SISINPSTAT
)) & 0x01) break;
2671 while(!((inSISREG(SISINPSTAT
)) & 0x01)) break;
2672 if((inSISREG(SISMISCW
)) & 0x10) temp
= 1;
2673 andSISIDXREG(SISCR
, 0x53, 0xfd);
2674 andSISIDXREG(SISCR
, 0x57, 0x00);
2678 if(temp
== 0xffff) {
2681 temp
= SiS_HandleDDC(&ivideo
->SiS_Pr
, ivideo
->vbflags
, ivideo
->sisvga_engine
, 0, 0, NULL
);
2682 } while(((temp
== 0) || (temp
== 0xffff)) && i
--);
2684 if((temp
== 0) || (temp
== 0xffff)) {
2685 if(sisfb_test_DDC1(ivideo
)) temp
= 1;
2689 if((temp
) && (temp
!= 0xffff)) {
2690 orSISIDXREG(SISCR
,0x32,0x20);
2693 #ifdef CONFIG_FB_SIS_315
2694 if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
2695 setSISIDXREG(SISCR
,ivideo
->SiS_Pr
.SiS_MyCR63
,0xBF,CR63
);
2699 setSISIDXREG(SISCR
,0x17,0x7F,CR17
);
2701 outSISIDXREG(SISSR
,0x1F,SR1F
);
2704 /* Determine and detect attached devices on SiS30x */
2705 static int __devinit
SISDoSense(struct sis_video_info
*ivideo
, u16 type
, u16 test
)
2707 int temp
, mytest
, result
, i
, j
;
2709 for(j
= 0; j
< 10; j
++) {
2711 for(i
= 0; i
< 3; i
++) {
2713 outSISIDXREG(SISPART4
,0x11,(type
& 0x00ff));
2714 temp
= (type
>> 8) | (mytest
& 0x00ff);
2715 setSISIDXREG(SISPART4
,0x10,0xe0,temp
);
2716 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 0x1500);
2719 inSISIDXREG(SISPART4
,0x03,temp
);
2722 if(temp
== mytest
) result
++;
2724 outSISIDXREG(SISPART4
,0x11,0x00);
2725 andSISIDXREG(SISPART4
,0x10,0xe0);
2726 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 0x1000);
2729 if((result
== 0) || (result
>= 2)) break;
2734 static void __devinit
SiS_Sense30x(struct sis_video_info
*ivideo
)
2736 u8 backupP4_0d
,backupP2_00
,backupP2_4d
,backupSR_1e
,biosflag
=0;
2737 u16 svhs
=0, svhs_c
=0;
2738 u16 cvbs
=0, cvbs_c
=0;
2739 u16 vga2
=0, vga2_c
=0;
2741 char stdstr
[] = "sisfb: Detected";
2742 char tvstr
[] = "TV connected to";
2744 if(ivideo
->vbflags
& VB_301
) {
2745 svhs
= 0x00b9; cvbs
= 0x00b3; vga2
= 0x00d1;
2746 inSISIDXREG(SISPART4
,0x01,myflag
);
2748 svhs
= 0x00dd; cvbs
= 0x00ee; vga2
= 0x00fd;
2750 } else if(ivideo
->vbflags
& (VB_301B
| VB_302B
)) {
2751 svhs
= 0x016b; cvbs
= 0x0174; vga2
= 0x0190;
2752 } else if(ivideo
->vbflags
& (VB_301LV
| VB_302LV
)) {
2753 svhs
= 0x0200; cvbs
= 0x0100;
2754 } else if(ivideo
->vbflags
& (VB_301C
| VB_302ELV
)) {
2755 svhs
= 0x016b; cvbs
= 0x0110; vga2
= 0x0190;
2758 vga2_c
= 0x0e08; svhs_c
= 0x0404; cvbs_c
= 0x0804;
2759 if(ivideo
->vbflags
& (VB_301LV
|VB_302LV
|VB_302ELV
)) {
2760 svhs_c
= 0x0408; cvbs_c
= 0x0808;
2764 if(ivideo
->chip
== SIS_300
) {
2765 inSISIDXREG(SISSR
,0x3b,myflag
);
2766 if(!(myflag
& 0x01)) vga2
= vga2_c
= 0;
2769 inSISIDXREG(SISSR
,0x1e,backupSR_1e
);
2770 orSISIDXREG(SISSR
,0x1e,0x20);
2772 inSISIDXREG(SISPART4
,0x0d,backupP4_0d
);
2773 if(ivideo
->vbflags
& VB_301C
) {
2774 setSISIDXREG(SISPART4
,0x0d,~0x07,0x01);
2776 orSISIDXREG(SISPART4
,0x0d,0x04);
2778 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 0x2000);
2780 inSISIDXREG(SISPART2
,0x00,backupP2_00
);
2781 outSISIDXREG(SISPART2
,0x00,((backupP2_00
| 0x1c) & 0xfc));
2783 inSISIDXREG(SISPART2
,0x4d,backupP2_4d
);
2784 if(ivideo
->vbflags
& (VB_301C
|VB_301LV
|VB_302LV
|VB_302ELV
)) {
2785 outSISIDXREG(SISPART2
,0x4d,(backupP2_4d
& ~0x10));
2788 if(!(ivideo
->vbflags
& VB_301C
)) {
2789 SISDoSense(ivideo
, 0, 0);
2792 andSISIDXREG(SISCR
, 0x32, ~0x14);
2794 if(vga2_c
|| vga2
) {
2795 if(SISDoSense(ivideo
, vga2
, vga2_c
)) {
2796 if(biosflag
& 0x01) {
2797 printk(KERN_INFO
"%s %s SCART output\n", stdstr
, tvstr
);
2798 orSISIDXREG(SISCR
, 0x32, 0x04);
2800 printk(KERN_INFO
"%s secondary VGA connection\n", stdstr
);
2801 orSISIDXREG(SISCR
, 0x32, 0x10);
2806 andSISIDXREG(SISCR
, 0x32, 0x3f);
2808 if(ivideo
->vbflags
& VB_301C
) {
2809 orSISIDXREG(SISPART4
,0x0d,0x04);
2812 if((ivideo
->sisvga_engine
== SIS_315_VGA
) &&
2813 (ivideo
->vbflags
& (VB_301C
|VB_301LV
|VB_302LV
|VB_302ELV
))) {
2814 outSISIDXREG(SISPART2
,0x4d,(backupP2_4d
| 0x10));
2815 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 0x2000);
2816 if((result
= SISDoSense(ivideo
, svhs
, 0x0604))) {
2817 if((result
= SISDoSense(ivideo
, cvbs
, 0x0804))) {
2818 printk(KERN_INFO
"%s %s YPbPr component output\n", stdstr
, tvstr
);
2819 orSISIDXREG(SISCR
,0x32,0x80);
2822 outSISIDXREG(SISPART2
,0x4d,backupP2_4d
);
2825 andSISIDXREG(SISCR
, 0x32, ~0x03);
2827 if(!(ivideo
->vbflags
& TV_YPBPR
)) {
2828 if((result
= SISDoSense(ivideo
, svhs
, svhs_c
))) {
2829 printk(KERN_INFO
"%s %s SVIDEO output\n", stdstr
, tvstr
);
2830 orSISIDXREG(SISCR
, 0x32, 0x02);
2832 if((biosflag
& 0x02) || (!result
)) {
2833 if(SISDoSense(ivideo
, cvbs
, cvbs_c
)) {
2834 printk(KERN_INFO
"%s %s COMPOSITE output\n", stdstr
, tvstr
);
2835 orSISIDXREG(SISCR
, 0x32, 0x01);
2840 SISDoSense(ivideo
, 0, 0);
2842 outSISIDXREG(SISPART2
,0x00,backupP2_00
);
2843 outSISIDXREG(SISPART4
,0x0d,backupP4_0d
);
2844 outSISIDXREG(SISSR
,0x1e,backupSR_1e
);
2846 if(ivideo
->vbflags
& VB_301C
) {
2847 inSISIDXREG(SISPART2
,0x00,biosflag
);
2848 if(biosflag
& 0x20) {
2849 for(myflag
= 2; myflag
> 0; myflag
--) {
2851 outSISIDXREG(SISPART2
,0x00,biosflag
);
2856 outSISIDXREG(SISPART2
,0x00,backupP2_00
);
2859 /* Determine and detect attached TV's on Chrontel */
2860 static void __devinit
SiS_SenseCh(struct sis_video_info
*ivideo
)
2862 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2864 char stdstr
[] = "sisfb: Chrontel: Detected TV connected to";
2866 #ifdef CONFIG_FB_SIS_300
2867 unsigned char test
[3];
2871 if(ivideo
->chip
< SIS_315H
) {
2873 #ifdef CONFIG_FB_SIS_300
2874 ivideo
->SiS_Pr
.SiS_IF_DEF_CH70xx
= 1; /* Chrontel 700x */
2875 SiS_SetChrontelGPIO(&ivideo
->SiS_Pr
, 0x9c); /* Set general purpose IO for Chrontel communication */
2876 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 1000);
2877 temp1
= SiS_GetCH700x(&ivideo
->SiS_Pr
, 0x25);
2878 /* See Chrontel TB31 for explanation */
2879 temp2
= SiS_GetCH700x(&ivideo
->SiS_Pr
, 0x0e);
2880 if(((temp2
& 0x07) == 0x01) || (temp2
& 0x04)) {
2881 SiS_SetCH700x(&ivideo
->SiS_Pr
, 0x0b0e);
2882 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 300);
2884 temp2
= SiS_GetCH700x(&ivideo
->SiS_Pr
, 0x25);
2885 if(temp2
!= temp1
) temp1
= temp2
;
2887 if((temp1
>= 0x22) && (temp1
<= 0x50)) {
2888 /* Read power status */
2889 temp1
= SiS_GetCH700x(&ivideo
->SiS_Pr
, 0x0e);
2890 if((temp1
& 0x03) != 0x03) {
2891 /* Power all outputs */
2892 SiS_SetCH700x(&ivideo
->SiS_Pr
, 0x0B0E);
2893 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 300);
2895 /* Sense connected TV devices */
2896 for(i
= 0; i
< 3; i
++) {
2897 SiS_SetCH700x(&ivideo
->SiS_Pr
, 0x0110);
2898 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 0x96);
2899 SiS_SetCH700x(&ivideo
->SiS_Pr
, 0x0010);
2900 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 0x96);
2901 temp1
= SiS_GetCH700x(&ivideo
->SiS_Pr
, 0x10);
2902 if(!(temp1
& 0x08)) test
[i
] = 0x02;
2903 else if(!(temp1
& 0x02)) test
[i
] = 0x01;
2905 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 0x96);
2908 if(test
[0] == test
[1]) temp1
= test
[0];
2909 else if(test
[0] == test
[2]) temp1
= test
[0];
2910 else if(test
[1] == test
[2]) temp1
= test
[1];
2913 "sisfb: TV detection unreliable - test results varied\n");
2917 printk(KERN_INFO
"%s SVIDEO output\n", stdstr
);
2918 ivideo
->vbflags
|= TV_SVIDEO
;
2919 orSISIDXREG(SISCR
, 0x32, 0x02);
2920 andSISIDXREG(SISCR
, 0x32, ~0x05);
2921 } else if (temp1
== 0x01) {
2922 printk(KERN_INFO
"%s CVBS output\n", stdstr
);
2923 ivideo
->vbflags
|= TV_AVIDEO
;
2924 orSISIDXREG(SISCR
, 0x32, 0x01);
2925 andSISIDXREG(SISCR
, 0x32, ~0x06);
2927 SiS_SetCH70xxANDOR(&ivideo
->SiS_Pr
, 0x010E,0xF8);
2928 andSISIDXREG(SISCR
, 0x32, ~0x07);
2930 } else if(temp1
== 0) {
2931 SiS_SetCH70xxANDOR(&ivideo
->SiS_Pr
, 0x010E,0xF8);
2932 andSISIDXREG(SISCR
, 0x32, ~0x07);
2934 /* Set general purpose IO for Chrontel communication */
2935 SiS_SetChrontelGPIO(&ivideo
->SiS_Pr
, 0x00);
2940 #ifdef CONFIG_FB_SIS_315
2941 ivideo
->SiS_Pr
.SiS_IF_DEF_CH70xx
= 2; /* Chrontel 7019 */
2942 temp1
= SiS_GetCH701x(&ivideo
->SiS_Pr
, 0x49);
2943 SiS_SetCH701x(&ivideo
->SiS_Pr
, 0x2049);
2944 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 0x96);
2945 temp2
= SiS_GetCH701x(&ivideo
->SiS_Pr
, 0x20);
2947 SiS_SetCH701x(&ivideo
->SiS_Pr
, (temp2
<< 8) | 0x20);
2948 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 0x96);
2950 SiS_SetCH701x(&ivideo
->SiS_Pr
, (temp2
<< 8) | 0x20);
2951 SiS_DDC2Delay(&ivideo
->SiS_Pr
, 0x96);
2952 temp2
= SiS_GetCH701x(&ivideo
->SiS_Pr
, 0x20);
2953 SiS_SetCH701x(&ivideo
->SiS_Pr
, (temp1
<< 8) | 0x49);
2955 if(temp2
& 0x02) temp1
|= 0x01;
2956 if(temp2
& 0x10) temp1
|= 0x01;
2957 if(temp2
& 0x04) temp1
|= 0x02;
2958 if( (temp1
& 0x01) && (temp1
& 0x02) ) temp1
= 0x04;
2961 printk(KERN_INFO
"%s CVBS output\n", stdstr
);
2962 ivideo
->vbflags
|= TV_AVIDEO
;
2963 orSISIDXREG(SISCR
, 0x32, 0x01);
2964 andSISIDXREG(SISCR
, 0x32, ~0x06);
2967 printk(KERN_INFO
"%s SVIDEO output\n", stdstr
);
2968 ivideo
->vbflags
|= TV_SVIDEO
;
2969 orSISIDXREG(SISCR
, 0x32, 0x02);
2970 andSISIDXREG(SISCR
, 0x32, ~0x05);
2973 printk(KERN_INFO
"%s SCART output\n", stdstr
);
2974 orSISIDXREG(SISCR
, 0x32, 0x04);
2975 andSISIDXREG(SISCR
, 0x32, ~0x03);
2978 andSISIDXREG(SISCR
, 0x32, ~0x07);
2984 /* ------------------------ Heap routines -------------------------- */
2986 static u32 __devinit
2987 sisfb_getheapstart(struct sis_video_info
*ivideo
)
2989 u32 ret
= ivideo
->sisfb_parm_mem
* 1024;
2990 u32 max
= ivideo
->video_size
- ivideo
->hwcursor_size
;
2993 /* Calculate heap start = end of memory for console
2995 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
2996 * C = console, D = heap, H = HWCursor, Q = cmd-queue
2998 * Basically given by "mem" parameter
3000 * maximum = videosize - cmd_queue - hwcursor
3001 * (results in a heap of size 0)
3002 * default = SiS 300: depends on videosize
3003 * SiS 315/330: 32k below max
3006 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
3007 max
-= TURBO_QUEUE_AREA_SIZE
;
3008 if(ivideo
->video_size
> 0x1000000) {
3010 } else if(ivideo
->video_size
> 0x800000) {
3016 max
-= COMMAND_QUEUE_AREA_SIZE
;
3020 if((!ret
) || (ret
> max
) || (ivideo
->cardnumber
!= 0)) {
3027 static int __devinit
3028 sisfb_heap_init(struct sis_video_info
*ivideo
)
3032 ivideo
->heapstart
= ivideo
->sisfb_mem
= sisfb_getheapstart(ivideo
);
3034 ivideo
->sisfb_heap_start
= ivideo
->video_vbase
+ ivideo
->heapstart
;
3035 ivideo
->sisfb_heap_end
= ivideo
->video_vbase
+ ivideo
->video_size
;
3037 /* Initialize command queue (We use MMIO only) */
3039 #ifdef CONFIG_FB_SIS_315
3040 if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
3044 ivideo
->sisfb_heap_end
-= COMMAND_QUEUE_AREA_SIZE
;
3046 outSISIDXREG(SISSR
, IND_SIS_CMDQUEUE_THRESHOLD
, COMMAND_QUEUE_THRESHOLD
);
3047 outSISIDXREG(SISSR
, IND_SIS_CMDQUEUE_SET
, SIS_CMD_QUEUE_RESET
);
3049 tempq
= MMIO_IN32(ivideo
->mmio_vbase
, MMIO_QUEUE_READPORT
);
3050 MMIO_OUT32(ivideo
->mmio_vbase
, MMIO_QUEUE_WRITEPORT
, tempq
);
3052 temp
= SIS_CMD_QUEUE_SIZE_512k
;
3053 temp
|= (SIS_MMIO_CMD_ENABLE
| SIS_CMD_AUTO_CORR
);
3054 outSISIDXREG(SISSR
, IND_SIS_CMDQUEUE_SET
, temp
);
3056 tempq
= (u32
)(ivideo
->video_size
- COMMAND_QUEUE_AREA_SIZE
);
3057 MMIO_OUT32(ivideo
->mmio_vbase
, MMIO_QUEUE_PHYBASE
, tempq
);
3059 ivideo
->caps
|= MMIO_CMD_QUEUE_CAP
;
3063 #ifdef CONFIG_FB_SIS_300
3064 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
3065 unsigned long tqueue_pos
;
3068 ivideo
->sisfb_heap_end
-= TURBO_QUEUE_AREA_SIZE
;
3070 tqueue_pos
= (ivideo
->video_size
- TURBO_QUEUE_AREA_SIZE
) / (64 * 1024);
3072 inSISIDXREG(SISSR
, IND_SIS_TURBOQUEUE_SET
, tq_state
);
3075 tq_state
|= (u8
)(tqueue_pos
>> 8);
3076 outSISIDXREG(SISSR
, IND_SIS_TURBOQUEUE_SET
, tq_state
);
3078 outSISIDXREG(SISSR
, IND_SIS_TURBOQUEUE_ADR
, (u8
)(tqueue_pos
& 0xff));
3080 ivideo
->caps
|= TURBO_QUEUE_CAP
;
3084 /* Reserve memory for the HWCursor */
3085 ivideo
->sisfb_heap_end
-= ivideo
->hwcursor_size
;
3086 ivideo
->hwcursor_vbase
= ivideo
->sisfb_heap_end
;
3087 ivideo
->caps
|= HW_CURSOR_CAP
;
3089 ivideo
->sisfb_heap_size
= ivideo
->sisfb_heap_end
- ivideo
->sisfb_heap_start
;
3091 if(ivideo
->cardnumber
== 0) {
3093 printk(KERN_INFO
"sisfb: Memory heap starting at %dK, size %dK\n",
3094 (int)(ivideo
->heapstart
/ 1024), (int)(ivideo
->sisfb_heap_size
/ 1024));
3096 sisfb_heap
.vinfo
= ivideo
;
3098 sisfb_heap
.poha_chain
= NULL
;
3099 sisfb_heap
.poh_freelist
= NULL
;
3101 poh
= sisfb_poh_new_node();
3102 if(poh
== NULL
) return 1;
3104 poh
->poh_next
= &sisfb_heap
.oh_free
;
3105 poh
->poh_prev
= &sisfb_heap
.oh_free
;
3106 poh
->size
= ivideo
->sisfb_heap_size
;
3107 poh
->offset
= ivideo
->heapstart
;
3109 sisfb_heap
.oh_free
.poh_next
= poh
;
3110 sisfb_heap
.oh_free
.poh_prev
= poh
;
3111 sisfb_heap
.oh_free
.size
= 0;
3112 sisfb_heap
.max_freesize
= poh
->size
;
3114 sisfb_heap
.oh_used
.poh_next
= &sisfb_heap
.oh_used
;
3115 sisfb_heap
.oh_used
.poh_prev
= &sisfb_heap
.oh_used
;
3116 sisfb_heap
.oh_used
.size
= SENTINEL
;
3120 printk(KERN_INFO
"Skipped heap initialization for secondary cards\n");
3128 sisfb_poh_new_node(void)
3135 if(sisfb_heap
.poh_freelist
== NULL
) {
3136 poha
= kmalloc(SIS_OH_ALLOC_SIZE
, GFP_KERNEL
);
3137 if(!poha
) return NULL
;
3139 poha
->poha_next
= sisfb_heap
.poha_chain
;
3140 sisfb_heap
.poha_chain
= poha
;
3142 cOhs
= (SIS_OH_ALLOC_SIZE
- sizeof(SIS_OHALLOC
)) / sizeof(SIS_OH
) + 1;
3144 poh
= &poha
->aoh
[0];
3145 for(i
= cOhs
- 1; i
!= 0; i
--) {
3146 poh
->poh_next
= poh
+ 1;
3150 poh
->poh_next
= NULL
;
3151 sisfb_heap
.poh_freelist
= &poha
->aoh
[0];
3154 poh
= sisfb_heap
.poh_freelist
;
3155 sisfb_heap
.poh_freelist
= poh
->poh_next
;
3161 sisfb_poh_allocate(u32 size
)
3167 if(size
> sisfb_heap
.max_freesize
) {
3168 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3169 (unsigned int) size
/ 1024);
3173 pohThis
= sisfb_heap
.oh_free
.poh_next
;
3175 while(pohThis
!= &sisfb_heap
.oh_free
) {
3176 if (size
<= pohThis
->size
) {
3180 pohThis
= pohThis
->poh_next
;
3184 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3185 (unsigned int) size
/ 1024);
3189 if(size
== pohThis
->size
) {
3191 sisfb_delete_node(pohThis
);
3193 pohRoot
= sisfb_poh_new_node();
3195 if(pohRoot
== NULL
) {
3199 pohRoot
->offset
= pohThis
->offset
;
3200 pohRoot
->size
= size
;
3202 pohThis
->offset
+= size
;
3203 pohThis
->size
-= size
;
3206 sisfb_heap
.max_freesize
-= size
;
3208 pohThis
= &sisfb_heap
.oh_used
;
3209 sisfb_insert_node(pohThis
, pohRoot
);
3215 sisfb_delete_node(SIS_OH
*poh
)
3220 poh_prev
= poh
->poh_prev
;
3221 poh_next
= poh
->poh_next
;
3223 poh_prev
->poh_next
= poh_next
;
3224 poh_next
->poh_prev
= poh_prev
;
3228 sisfb_insert_node(SIS_OH
*pohList
, SIS_OH
*poh
)
3232 pohTemp
= pohList
->poh_next
;
3234 pohList
->poh_next
= poh
;
3235 pohTemp
->poh_prev
= poh
;
3237 poh
->poh_prev
= pohList
;
3238 poh
->poh_next
= pohTemp
;
3242 sisfb_poh_free(u32 base
)
3252 poh_freed
= sisfb_heap
.oh_used
.poh_next
;
3254 while(poh_freed
!= &sisfb_heap
.oh_used
) {
3255 if(poh_freed
->offset
== base
) {
3260 poh_freed
= poh_freed
->poh_next
;
3263 if(!foundNode
) return(NULL
);
3265 sisfb_heap
.max_freesize
+= poh_freed
->size
;
3267 poh_prev
= poh_next
= NULL
;
3268 ulUpper
= poh_freed
->offset
+ poh_freed
->size
;
3269 ulLower
= poh_freed
->offset
;
3271 pohThis
= sisfb_heap
.oh_free
.poh_next
;
3273 while(pohThis
!= &sisfb_heap
.oh_free
) {
3274 if(pohThis
->offset
== ulUpper
) {
3276 } else if((pohThis
->offset
+ pohThis
->size
) == ulLower
) {
3279 pohThis
= pohThis
->poh_next
;
3282 sisfb_delete_node(poh_freed
);
3284 if(poh_prev
&& poh_next
) {
3285 poh_prev
->size
+= (poh_freed
->size
+ poh_next
->size
);
3286 sisfb_delete_node(poh_next
);
3287 sisfb_free_node(poh_freed
);
3288 sisfb_free_node(poh_next
);
3293 poh_prev
->size
+= poh_freed
->size
;
3294 sisfb_free_node(poh_freed
);
3299 poh_next
->size
+= poh_freed
->size
;
3300 poh_next
->offset
= poh_freed
->offset
;
3301 sisfb_free_node(poh_freed
);
3305 sisfb_insert_node(&sisfb_heap
.oh_free
, poh_freed
);
3311 sisfb_free_node(SIS_OH
*poh
)
3313 if(poh
== NULL
) return;
3315 poh
->poh_next
= sisfb_heap
.poh_freelist
;
3316 sisfb_heap
.poh_freelist
= poh
;
3320 sis_malloc(struct sis_memreq
*req
)
3322 struct sis_video_info
*ivideo
= sisfb_heap
.vinfo
;
3325 if((ivideo
) && (!ivideo
->havenoheap
)) {
3326 poh
= sisfb_poh_allocate((u32
)req
->size
);
3330 req
->offset
= req
->size
= 0;
3331 DPRINTK("sisfb: Video RAM allocation failed\n");
3333 req
->offset
= poh
->offset
;
3334 req
->size
= poh
->size
;
3335 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3336 (poh
->offset
+ ivideo
->video_vbase
));
3340 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3345 struct sis_video_info
*ivideo
= sisfb_heap
.vinfo
;
3348 if((!ivideo
) || (ivideo
->havenoheap
)) return;
3350 poh
= sisfb_poh_free((u32
)base
);
3353 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3354 (unsigned int) base
);
3358 /* --------------------- SetMode routines ------------------------- */
3361 sisfb_pre_setmode(struct sis_video_info
*ivideo
)
3363 u8 cr30
= 0, cr31
= 0, cr33
= 0, cr35
= 0, cr38
= 0;
3366 ivideo
->currentvbflags
&= (VB_VIDEOBRIDGE
| VB_DISPTYPE_DISP2
);
3368 inSISIDXREG(SISCR
, 0x31, cr31
);
3372 cr33
= ivideo
->rate_idx
& 0x0F;
3374 #ifdef CONFIG_FB_SIS_315
3375 if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
3376 if(ivideo
->chip
>= SIS_661
) {
3377 inSISIDXREG(SISCR
, 0x38, cr38
);
3378 cr38
&= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3381 inSISIDXREG(SISCR
, tvregnum
, cr38
);
3382 cr38
&= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3386 #ifdef CONFIG_FB_SIS_300
3387 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
3389 inSISIDXREG(SISCR
, tvregnum
, cr38
);
3393 SiS_SetEnableDstn(&ivideo
->SiS_Pr
, FALSE
);
3394 SiS_SetEnableFstn(&ivideo
->SiS_Pr
, FALSE
);
3396 switch(ivideo
->currentvbflags
& VB_DISPTYPE_DISP2
) {
3399 cr38
&= ~0xc0; /* Clear PAL-M / PAL-N bits */
3400 if((ivideo
->vbflags
& TV_YPBPR
) && (ivideo
->vbflags
& (VB_301C
|VB_301LV
|VB_302LV
))) {
3401 #ifdef CONFIG_FB_SIS_315
3402 if(ivideo
->chip
>= SIS_661
) {
3404 if(ivideo
->vbflags
& TV_YPBPR525P
) cr35
|= 0x20;
3405 else if(ivideo
->vbflags
& TV_YPBPR750P
) cr35
|= 0x40;
3406 else if(ivideo
->vbflags
& TV_YPBPR1080I
) cr35
|= 0x60;
3407 cr30
|= SIS_SIMULTANEOUS_VIEW_ENABLE
;
3409 ivideo
->currentvbflags
|= (TV_YPBPR
| (ivideo
->vbflags
& TV_YPBPRALL
));
3410 } else if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
3411 cr30
|= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE
);
3413 if(ivideo
->vbflags
& TV_YPBPR525P
) cr38
|= 0x10;
3414 else if(ivideo
->vbflags
& TV_YPBPR750P
) cr38
|= 0x20;
3415 else if(ivideo
->vbflags
& TV_YPBPR1080I
) cr38
|= 0x30;
3417 ivideo
->currentvbflags
|= (TV_YPBPR
| (ivideo
->vbflags
& TV_YPBPRALL
));
3420 } else if((ivideo
->vbflags
& TV_HIVISION
) && (ivideo
->vbflags
& (VB_301
|VB_301B
|VB_302B
))) {
3421 if(ivideo
->chip
>= SIS_661
) {
3427 cr30
|= SIS_SIMULTANEOUS_VIEW_ENABLE
;
3430 ivideo
->currentvbflags
|= TV_HIVISION
;
3431 } else if(ivideo
->vbflags
& TV_SCART
) {
3432 cr30
= (SIS_VB_OUTPUT_SCART
| SIS_SIMULTANEOUS_VIEW_ENABLE
);
3435 ivideo
->currentvbflags
|= TV_SCART
;
3437 if(ivideo
->vbflags
& TV_SVIDEO
) {
3438 cr30
= (SIS_VB_OUTPUT_SVIDEO
| SIS_SIMULTANEOUS_VIEW_ENABLE
);
3439 ivideo
->currentvbflags
|= TV_SVIDEO
;
3441 if(ivideo
->vbflags
& TV_AVIDEO
) {
3442 cr30
= (SIS_VB_OUTPUT_COMPOSITE
| SIS_SIMULTANEOUS_VIEW_ENABLE
);
3443 ivideo
->currentvbflags
|= TV_AVIDEO
;
3446 cr31
|= SIS_DRIVER_MODE
;
3448 if(ivideo
->vbflags
& (TV_AVIDEO
|TV_SVIDEO
)) {
3449 if(ivideo
->vbflags
& TV_PAL
) {
3450 cr31
|= 0x01; cr35
|= 0x01;
3451 ivideo
->currentvbflags
|= TV_PAL
;
3452 if(ivideo
->vbflags
& TV_PALM
) {
3453 cr38
|= 0x40; cr35
|= 0x04;
3454 ivideo
->currentvbflags
|= TV_PALM
;
3455 } else if(ivideo
->vbflags
& TV_PALN
) {
3456 cr38
|= 0x80; cr35
|= 0x08;
3457 ivideo
->currentvbflags
|= TV_PALN
;
3460 cr31
&= ~0x01; cr35
&= ~0x01;
3461 ivideo
->currentvbflags
|= TV_NTSC
;
3462 if(ivideo
->vbflags
& TV_NTSCJ
) {
3463 cr38
|= 0x40; cr35
|= 0x02;
3464 ivideo
->currentvbflags
|= TV_NTSCJ
;
3471 cr30
= (SIS_VB_OUTPUT_LCD
| SIS_SIMULTANEOUS_VIEW_ENABLE
);
3472 cr31
|= SIS_DRIVER_MODE
;
3473 SiS_SetEnableDstn(&ivideo
->SiS_Pr
, ivideo
->sisfb_dstn
);
3474 SiS_SetEnableFstn(&ivideo
->SiS_Pr
, ivideo
->sisfb_fstn
);
3478 cr30
= (SIS_VB_OUTPUT_CRT2
| SIS_SIMULTANEOUS_VIEW_ENABLE
);
3479 cr31
|= SIS_DRIVER_MODE
;
3480 if(ivideo
->sisfb_nocrt2rate
) {
3481 cr33
|= (sisbios_mode
[ivideo
->sisfb_mode_idx
].rate_idx
<< 4);
3483 cr33
|= ((ivideo
->rate_idx
& 0x0F) << 4);
3487 default: /* disable CRT2 */
3489 cr31
|= (SIS_DRIVER_MODE
| SIS_VB_OUTPUT_DISABLE
);
3492 outSISIDXREG(SISCR
, 0x30, cr30
);
3493 outSISIDXREG(SISCR
, 0x33, cr33
);
3495 if(ivideo
->chip
>= SIS_661
) {
3496 #ifdef CONFIG_FB_SIS_315
3497 cr31
&= ~0x01; /* Clear PAL flag (now in CR35) */
3498 setSISIDXREG(SISCR
, 0x35, ~0x10, cr35
); /* Leave overscan bit alone */
3499 cr38
&= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3500 setSISIDXREG(SISCR
, 0x38, 0xf8, cr38
);
3502 } else if(ivideo
->chip
!= SIS_300
) {
3503 outSISIDXREG(SISCR
, tvregnum
, cr38
);
3505 outSISIDXREG(SISCR
, 0x31, cr31
);
3507 if(ivideo
->accel
) sisfb_syncaccel(ivideo
);
3509 ivideo
->SiS_Pr
.SiS_UseOEM
= ivideo
->sisfb_useoem
;
3512 /* Fix SR11 for 661 and later */
3513 #ifdef CONFIG_FB_SIS_315
3515 sisfb_fixup_SR11(struct sis_video_info
*ivideo
)
3519 if(ivideo
->chip
>= SIS_661
) {
3520 inSISIDXREG(SISSR
,0x11,tmpreg
);
3522 inSISIDXREG(SISSR
,0x3e,tmpreg
);
3523 tmpreg
= (tmpreg
+ 1) & 0xff;
3524 outSISIDXREG(SISSR
,0x3e,tmpreg
);
3525 inSISIDXREG(SISSR
,0x11,tmpreg
);
3528 andSISIDXREG(SISSR
,0x11,0x0f);
3534 static void sisfb_set_TVxposoffset(struct sis_video_info
*ivideo
, int val
)
3536 if(val
> 32) val
= 32;
3537 if(val
< -32) val
= -32;
3538 ivideo
->tvxpos
= val
;
3540 if(ivideo
->sisfblocked
) return;
3541 if(!ivideo
->modechanged
) return;
3543 if(ivideo
->currentvbflags
& CRT2_TV
) {
3545 if(ivideo
->vbflags
& VB_CHRONTEL
) {
3547 int x
= ivideo
->tvx
;
3549 switch(ivideo
->chronteltype
) {
3553 outSISIDXREG(SISSR
,0x05,0x86);
3554 SiS_SetCH700x(&ivideo
->SiS_Pr
, (((x
& 0xff) << 8) | 0x0a));
3555 SiS_SetCH70xxANDOR(&ivideo
->SiS_Pr
, (((x
& 0x0100) << 1) | 0x08),0xFD);
3558 /* Not supported by hardware */
3562 } else if(ivideo
->vbflags
& VB_SISBRIDGE
) {
3564 u8 p2_1f
,p2_20
,p2_2b
,p2_42
,p2_43
;
3565 unsigned short temp
;
3567 p2_1f
= ivideo
->p2_1f
;
3568 p2_20
= ivideo
->p2_20
;
3569 p2_2b
= ivideo
->p2_2b
;
3570 p2_42
= ivideo
->p2_42
;
3571 p2_43
= ivideo
->p2_43
;
3573 temp
= p2_1f
| ((p2_20
& 0xf0) << 4);
3575 p2_1f
= temp
& 0xff;
3576 p2_20
= (temp
& 0xf00) >> 4;
3577 p2_2b
= ((p2_2b
& 0x0f) + (val
* 2)) & 0x0f;
3578 temp
= p2_43
| ((p2_42
& 0xf0) << 4);
3580 p2_43
= temp
& 0xff;
3581 p2_42
= (temp
& 0xf00) >> 4;
3582 outSISIDXREG(SISPART2
,0x1f,p2_1f
);
3583 setSISIDXREG(SISPART2
,0x20,0x0F,p2_20
);
3584 setSISIDXREG(SISPART2
,0x2b,0xF0,p2_2b
);
3585 setSISIDXREG(SISPART2
,0x42,0x0F,p2_42
);
3586 outSISIDXREG(SISPART2
,0x43,p2_43
);
3591 static void sisfb_set_TVyposoffset(struct sis_video_info
*ivideo
, int val
)
3593 if(val
> 32) val
= 32;
3594 if(val
< -32) val
= -32;
3595 ivideo
->tvypos
= val
;
3597 if(ivideo
->sisfblocked
) return;
3598 if(!ivideo
->modechanged
) return;
3600 if(ivideo
->currentvbflags
& CRT2_TV
) {
3602 if(ivideo
->vbflags
& VB_CHRONTEL
) {
3604 int y
= ivideo
->tvy
;
3606 switch(ivideo
->chronteltype
) {
3610 outSISIDXREG(SISSR
,0x05,0x86);
3611 SiS_SetCH700x(&ivideo
->SiS_Pr
, (((y
& 0xff) << 8) | 0x0b));
3612 SiS_SetCH70xxANDOR(&ivideo
->SiS_Pr
, ((y
& 0x0100) | 0x08),0xFE);
3615 /* Not supported by hardware */
3619 } else if(ivideo
->vbflags
& VB_SISBRIDGE
) {
3623 p2_01
= ivideo
->p2_01
;
3624 p2_02
= ivideo
->p2_02
;
3628 while((p2_01
<= 0) || (p2_02
<= 0)) {
3632 outSISIDXREG(SISPART2
,0x01,p2_01
);
3633 outSISIDXREG(SISPART2
,0x02,p2_02
);
3639 sisfb_post_setmode(struct sis_video_info
*ivideo
)
3641 BOOLEAN crt1isoff
= FALSE
;
3642 BOOLEAN doit
= TRUE
;
3643 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3646 #ifdef CONFIG_FB_SIS_315
3650 outSISIDXREG(SISSR
,0x05,0x86);
3652 #ifdef CONFIG_FB_SIS_315
3653 sisfb_fixup_SR11(ivideo
);
3656 /* Now we actually HAVE changed the display mode */
3657 ivideo
->modechanged
= 1;
3659 /* We can't switch off CRT1 if bridge is in slave mode */
3660 if(ivideo
->vbflags
& VB_VIDEOBRIDGE
) {
3661 if(sisfb_bridgeisslave(ivideo
)) doit
= FALSE
;
3662 } else ivideo
->sisfb_crt1off
= 0;
3664 #ifdef CONFIG_FB_SIS_300
3665 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
3666 if((ivideo
->sisfb_crt1off
) && (doit
)) {
3673 setSISIDXREG(SISCR
, 0x17, 0x7f, reg
);
3676 #ifdef CONFIG_FB_SIS_315
3677 if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
3678 if((ivideo
->sisfb_crt1off
) && (doit
)) {
3688 setSISIDXREG(SISCR
, ivideo
->SiS_Pr
.SiS_MyCR63
, ~0x40, reg
);
3689 setSISIDXREG(SISSR
, 0x1f, ~0xc0, reg1
);
3694 ivideo
->currentvbflags
&= ~VB_DISPTYPE_CRT1
;
3695 ivideo
->currentvbflags
|= VB_SINGLE_MODE
;
3697 ivideo
->currentvbflags
|= VB_DISPTYPE_CRT1
;
3698 if(ivideo
->currentvbflags
& VB_DISPTYPE_CRT2
) {
3699 ivideo
->currentvbflags
|= VB_MIRROR_MODE
;
3701 ivideo
->currentvbflags
|= VB_SINGLE_MODE
;
3705 andSISIDXREG(SISSR
, IND_SIS_RAMDAC_CONTROL
, ~0x04);
3707 if(ivideo
->currentvbflags
& CRT2_TV
) {
3708 if(ivideo
->vbflags
& VB_SISBRIDGE
) {
3709 inSISIDXREG(SISPART2
,0x1f,ivideo
->p2_1f
);
3710 inSISIDXREG(SISPART2
,0x20,ivideo
->p2_20
);
3711 inSISIDXREG(SISPART2
,0x2b,ivideo
->p2_2b
);
3712 inSISIDXREG(SISPART2
,0x42,ivideo
->p2_42
);
3713 inSISIDXREG(SISPART2
,0x43,ivideo
->p2_43
);
3714 inSISIDXREG(SISPART2
,0x01,ivideo
->p2_01
);
3715 inSISIDXREG(SISPART2
,0x02,ivideo
->p2_02
);
3716 } else if(ivideo
->vbflags
& VB_CHRONTEL
) {
3717 if(ivideo
->chronteltype
== 1) {
3718 ivideo
->tvx
= SiS_GetCH700x(&ivideo
->SiS_Pr
, 0x0a);
3719 ivideo
->tvx
|= (((SiS_GetCH700x(&ivideo
->SiS_Pr
, 0x08) & 0x02) >> 1) << 8);
3720 ivideo
->tvy
= SiS_GetCH700x(&ivideo
->SiS_Pr
, 0x0b);
3721 ivideo
->tvy
|= ((SiS_GetCH700x(&ivideo
->SiS_Pr
, 0x08) & 0x01) << 8);
3726 if(ivideo
->tvxpos
) {
3727 sisfb_set_TVxposoffset(ivideo
, ivideo
->tvxpos
);
3729 if(ivideo
->tvypos
) {
3730 sisfb_set_TVyposoffset(ivideo
, ivideo
->tvypos
);
3733 if((ivideo
->currentvbflags
& CRT2_TV
) && (ivideo
->vbflags
& VB_301
)) { /* Set filter for SiS301 */
3735 unsigned char filter_tb
= 0;
3737 switch (ivideo
->video_width
) {
3739 filter_tb
= (ivideo
->vbflags
& TV_NTSC
) ? 4 : 12;
3742 filter_tb
= (ivideo
->vbflags
& TV_NTSC
) ? 5 : 13;
3745 filter_tb
= (ivideo
->vbflags
& TV_NTSC
) ? 6 : 14;
3749 filter_tb
= (ivideo
->vbflags
& TV_NTSC
) ? 7 : 15;
3752 ivideo
->sisfb_filter
= -1;
3756 orSISIDXREG(SISPART1
, ivideo
->CRT2_write_enable
, 0x01);
3758 if(ivideo
->vbflags
& TV_NTSC
) {
3760 andSISIDXREG(SISPART2
, 0x3a, 0x1f);
3762 if (ivideo
->vbflags
& TV_SVIDEO
) {
3764 andSISIDXREG(SISPART2
, 0x30, 0xdf);
3766 } else if (ivideo
->vbflags
& TV_AVIDEO
) {
3768 orSISIDXREG(SISPART2
, 0x30, 0x20);
3770 switch (ivideo
->video_width
) {
3772 outSISIDXREG(SISPART2
, 0x35, 0xEB);
3773 outSISIDXREG(SISPART2
, 0x36, 0x04);
3774 outSISIDXREG(SISPART2
, 0x37, 0x25);
3775 outSISIDXREG(SISPART2
, 0x38, 0x18);
3778 outSISIDXREG(SISPART2
, 0x35, 0xEE);
3779 outSISIDXREG(SISPART2
, 0x36, 0x0C);
3780 outSISIDXREG(SISPART2
, 0x37, 0x22);
3781 outSISIDXREG(SISPART2
, 0x38, 0x08);
3785 outSISIDXREG(SISPART2
, 0x35, 0xEB);
3786 outSISIDXREG(SISPART2
, 0x36, 0x15);
3787 outSISIDXREG(SISPART2
, 0x37, 0x25);
3788 outSISIDXREG(SISPART2
, 0x38, 0xF6);
3793 } else if(ivideo
->vbflags
& TV_PAL
) {
3795 andSISIDXREG(SISPART2
, 0x3A, 0x1F);
3797 if (ivideo
->vbflags
& TV_SVIDEO
) {
3799 andSISIDXREG(SISPART2
, 0x30, 0xDF);
3801 } else if (ivideo
->vbflags
& TV_AVIDEO
) {
3803 orSISIDXREG(SISPART2
, 0x30, 0x20);
3805 switch (ivideo
->video_width
) {
3807 outSISIDXREG(SISPART2
, 0x35, 0xF1);
3808 outSISIDXREG(SISPART2
, 0x36, 0xF7);
3809 outSISIDXREG(SISPART2
, 0x37, 0x1F);
3810 outSISIDXREG(SISPART2
, 0x38, 0x32);
3813 outSISIDXREG(SISPART2
, 0x35, 0xF3);
3814 outSISIDXREG(SISPART2
, 0x36, 0x00);
3815 outSISIDXREG(SISPART2
, 0x37, 0x1D);
3816 outSISIDXREG(SISPART2
, 0x38, 0x20);
3820 outSISIDXREG(SISPART2
, 0x35, 0xFC);
3821 outSISIDXREG(SISPART2
, 0x36, 0xFB);
3822 outSISIDXREG(SISPART2
, 0x37, 0x14);
3823 outSISIDXREG(SISPART2
, 0x38, 0x2A);
3829 if((ivideo
->sisfb_filter
>= 0) && (ivideo
->sisfb_filter
<= 7)) {
3830 outSISIDXREG(SISPART2
,0x35,(sis_TV_filter
[filter_tb
].filter
[ivideo
->sisfb_filter
][0]));
3831 outSISIDXREG(SISPART2
,0x36,(sis_TV_filter
[filter_tb
].filter
[ivideo
->sisfb_filter
][1]));
3832 outSISIDXREG(SISPART2
,0x37,(sis_TV_filter
[filter_tb
].filter
[ivideo
->sisfb_filter
][2]));
3833 outSISIDXREG(SISPART2
,0x38,(sis_TV_filter
[filter_tb
].filter
[ivideo
->sisfb_filter
][3]));
3840 int __init
sisfb_setup(char *options
)
3844 sisfb_setdefaultparms();
3846 printk(KERN_DEBUG
"sisfb: Options %s\n", options
);
3848 if(!options
|| !(*options
)) {
3852 while((this_opt
= strsep(&options
, ",")) != NULL
) {
3854 if(!(*this_opt
)) continue;
3856 if(!strnicmp(this_opt
, "off", 3)) {
3858 } else if(!strnicmp(this_opt
, "forcecrt2type:", 14)) {
3859 /* Need to check crt2 type first for fstn/dstn */
3860 sisfb_search_crt2type(this_opt
+ 14);
3861 } else if(!strnicmp(this_opt
, "tvmode:",7)) {
3862 sisfb_search_tvstd(this_opt
+ 7);
3863 } else if(!strnicmp(this_opt
, "tvstandard:",11)) {
3864 sisfb_search_tvstd(this_opt
+ 7);
3865 } else if(!strnicmp(this_opt
, "mode:", 5)) {
3866 sisfb_search_mode(this_opt
+ 5, FALSE
);
3867 } else if(!strnicmp(this_opt
, "vesa:", 5)) {
3868 sisfb_search_vesamode(simple_strtoul(this_opt
+ 5, NULL
, 0), FALSE
);
3869 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
3870 } else if(!strnicmp(this_opt
, "inverse", 7)) {
3872 /* fb_invert_cmaps(); */
3873 } else if(!strnicmp(this_opt
, "font:", 5)) {
3874 if(strlen(this_opt
+ 5) < 40) {
3875 strncpy(sisfb_fontname
, this_opt
+ 5, sizeof(sisfb_fontname
) - 1);
3876 sisfb_fontname
[sizeof(sisfb_fontname
) - 1] = '\0';
3879 } else if(!strnicmp(this_opt
, "rate:", 5)) {
3880 sisfb_parm_rate
= simple_strtoul(this_opt
+ 5, NULL
, 0);
3881 } else if(!strnicmp(this_opt
, "filter:", 7)) {
3882 sisfb_filter
= (int)simple_strtoul(this_opt
+ 7, NULL
, 0);
3883 } else if(!strnicmp(this_opt
, "forcecrt1:", 10)) {
3884 sisfb_forcecrt1
= (int)simple_strtoul(this_opt
+ 10, NULL
, 0);
3885 } else if(!strnicmp(this_opt
, "mem:",4)) {
3886 sisfb_parm_mem
= simple_strtoul(this_opt
+ 4, NULL
, 0);
3887 } else if(!strnicmp(this_opt
, "pdc:", 4)) {
3888 sisfb_pdc
= simple_strtoul(this_opt
+ 4, NULL
, 0);
3889 } else if(!strnicmp(this_opt
, "pdc1:", 5)) {
3890 sisfb_pdca
= simple_strtoul(this_opt
+ 5, NULL
, 0);
3891 } else if(!strnicmp(this_opt
, "noaccel", 7)) {
3893 } else if(!strnicmp(this_opt
, "accel", 5)) {
3895 } else if(!strnicmp(this_opt
, "noypan", 6)) {
3897 } else if(!strnicmp(this_opt
, "ypan", 4)) {
3899 } else if(!strnicmp(this_opt
, "nomax", 5)) {
3901 } else if(!strnicmp(this_opt
, "max", 3)) {
3903 } else if(!strnicmp(this_opt
, "userom:", 7)) {
3904 sisfb_userom
= (int)simple_strtoul(this_opt
+ 7, NULL
, 0);
3905 } else if(!strnicmp(this_opt
, "useoem:", 7)) {
3906 sisfb_useoem
= (int)simple_strtoul(this_opt
+ 7, NULL
, 0);
3907 } else if(!strnicmp(this_opt
, "nocrt2rate", 10)) {
3908 sisfb_nocrt2rate
= 1;
3909 } else if(!strnicmp(this_opt
, "scalelcd:", 9)) {
3910 unsigned long temp
= 2;
3911 temp
= simple_strtoul(this_opt
+ 9, NULL
, 0);
3912 if((temp
== 0) || (temp
== 1)) {
3913 sisfb_scalelcd
= temp
^ 1;
3915 } else if(!strnicmp(this_opt
, "tvxposoffset:", 13)) {
3917 temp
= (int)simple_strtol(this_opt
+ 13, NULL
, 0);
3918 if((temp
>= -32) && (temp
<= 32)) {
3919 sisfb_tvxposoffset
= temp
;
3921 } else if(!strnicmp(this_opt
, "tvyposoffset:", 13)) {
3923 temp
= (int)simple_strtol(this_opt
+ 13, NULL
, 0);
3924 if((temp
>= -32) && (temp
<= 32)) {
3925 sisfb_tvyposoffset
= temp
;
3927 } else if(!strnicmp(this_opt
, "specialtiming:", 14)) {
3928 sisfb_search_specialtiming(this_opt
+ 14);
3929 } else if(!strnicmp(this_opt
, "lvdshl:", 7)) {
3931 temp
= simple_strtoul(this_opt
+ 7, NULL
, 0);
3932 if((temp
>= 0) && (temp
<= 3)) {
3933 sisfb_lvdshl
= temp
;
3935 } else if(this_opt
[0] >= '0' && this_opt
[0] <= '9') {
3936 sisfb_search_mode(this_opt
, TRUE
);
3937 #if !defined(__i386__) && !defined(__x86_64__)
3938 } else if(!strnicmp(this_opt
, "resetcard", 9)) {
3939 sisfb_resetcard
= 1;
3940 } else if(!strnicmp(this_opt
, "videoram:", 9)) {
3941 sisfb_videoram
= simple_strtoul(this_opt
+ 9, NULL
, 0);
3944 printk(KERN_INFO
"sisfb: Invalid option %s\n", this_opt
);
3955 static void __iomem
* __devinit
sis_find_rom(struct pci_dev
*pdev
)
3957 struct sis_video_info
*ivideo
= pci_get_drvdata(pdev
);
3959 #if defined(__i386__) || defined(__x86_64__)
3961 void __iomem
*rom_base
, *rom
;
3963 unsigned short pciid
;
3965 for(segstart
=0x000c0000; segstart
<0x000f0000; segstart
+=0x00001000) {
3967 rom_base
= ioremap(segstart
, 0x10000);
3968 if(!rom_base
) continue;
3970 if((readb(rom_base
) != 0x55) || (readb(rom_base
+ 1) != 0xaa)) {
3975 romptr
= (unsigned short)(readb(rom_base
+ 0x18) | (readb(rom_base
+ 0x19) << 8));
3976 if(romptr
> (0x10000 - 8)) {
3981 rom
= rom_base
+ romptr
;
3983 if((readb(rom
) != 'P') || (readb(rom
+ 1) != 'C') ||
3984 (readb(rom
+ 2) != 'I') || (readb(rom
+ 3) != 'R')) {
3989 pciid
= readb(rom
+ 4) | (readb(rom
+ 5) << 8);
3990 if(pciid
!= 0x1039) {
3995 pciid
= readb(rom
+ 6) | (readb(rom
+ 7) << 8);
3996 if(pciid
== ivideo
->chip_id
) return rom_base
;
4001 void __iomem
*rom_base
, *rom
, *myrombase
= NULL
;
4003 unsigned short pciid
;
4006 pci_read_config_dword(pdev
, PCI_ROM_ADDRESS
, &backup
);
4007 pci_write_config_dword(pdev
, PCI_ROM_ADDRESS
,
4008 (ivideo
->video_base
& PCI_ROM_ADDRESS_MASK
) | PCI_ROM_ADDRESS_ENABLE
);
4010 rom_base
= ioremap(ivideo
->video_base
, 65536);
4012 if((readb(rom_base
) == 0x55) && (readb(rom_base
+ 1) == 0xaa)) {
4013 romptr
= (u16
)(readb(rom_base
+ 0x18) | (readb(rom_base
+ 0x19) << 8));
4014 if(romptr
<= (0x10000 - 8)) {
4015 rom
= rom_base
+ romptr
;
4016 if((readb(rom
) == 'P') && (readb(rom
+ 1) == 'C') &&
4017 (readb(rom
+ 2) == 'I') && (readb(rom
+ 3) == 'R')) {
4018 pciid
= readb(rom
+ 4) | (readb(rom
+ 5) << 8);
4019 if(pciid
== 0x1039) {
4020 pciid
= readb(rom
+ 6) | (readb(rom
+ 7) << 8);
4021 if(pciid
== ivideo
->chip_id
) {
4022 if((myrombase
= vmalloc(65536))) {
4023 memcpy_fromio(myrombase
, rom_base
, 65536);
4032 pci_write_config_dword(pdev
, PCI_ROM_ADDRESS
, backup
);
4033 if(myrombase
) return myrombase
;
4038 #ifdef CONFIG_FB_SIS_300
4039 static int __devinit
4040 sisfb_chkbuswidth300(struct pci_dev
*pdev
, void __iomem
*FBAddress
)
4042 struct sis_video_info
*ivideo
= pci_get_drvdata(pdev
);
4047 andSISIDXREG(SISSR
,0x15,0xFB);
4048 orSISIDXREG(SISSR
,0x15,0x04);
4049 outSISIDXREG(SISSR
,0x13,0x00);
4050 outSISIDXREG(SISSR
,0x14,0xBF);
4052 for(i
=0; i
<2; i
++) {
4054 for(j
=0; j
<4; j
++) {
4055 writew(temp
, FBAddress
);
4056 if(readw(FBAddress
) == temp
) break;
4057 orSISIDXREG(SISSR
,0x3c,0x01);
4058 inSISIDXREG(SISSR
,0x05,reg
);
4059 inSISIDXREG(SISSR
,0x05,reg
);
4060 andSISIDXREG(SISSR
,0x3c,0xfe);
4061 inSISIDXREG(SISSR
,0x05,reg
);
4062 inSISIDXREG(SISSR
,0x05,reg
);
4067 writel(0x01234567L
, FBAddress
);
4068 writel(0x456789ABL
, (FBAddress
+4));
4069 writel(0x89ABCDEFL
, (FBAddress
+8));
4070 writel(0xCDEF0123L
, (FBAddress
+12));
4071 inSISIDXREG(SISSR
,0x3b,reg
);
4073 if(readl((FBAddress
+12)) == 0xCDEF0123L
) return(4); /* Channel A 128bit */
4075 if(readl((FBAddress
+4)) == 0x456789ABL
) return(2); /* Channel B 64bit */
4076 return(1); /* 32bit */
4079 static void __devinit
4080 sisfb_setramsize300(struct pci_dev
*pdev
)
4082 struct sis_video_info
*ivideo
= pci_get_drvdata(pdev
);
4083 void __iomem
*FBAddr
= ivideo
->sishw_ext
.pjVideoMemoryAddress
, *Addr
;
4084 USHORT SR13
, SR14
=0, buswidth
, Done
, data
, TotalCapacity
, PhysicalAdrOtherPage
=0;
4085 int PseudoRankCapacity
, PseudoTotalCapacity
, PseudoAdrPinCount
;
4086 int RankCapacity
, AdrPinCount
, BankNumHigh
, BankNumMid
, MB2Bank
;
4087 int PageCapacity
, PhysicalAdrHigh
, PhysicalAdrHalfPage
, i
, j
, k
;
4088 const USHORT SiS_DRAMType
[17][5] = {
4089 {0x0C,0x0A,0x02,0x40,0x39},
4090 {0x0D,0x0A,0x01,0x40,0x48},
4091 {0x0C,0x09,0x02,0x20,0x35},
4092 {0x0D,0x09,0x01,0x20,0x44},
4093 {0x0C,0x08,0x02,0x10,0x31},
4094 {0x0D,0x08,0x01,0x10,0x40},
4095 {0x0C,0x0A,0x01,0x20,0x34},
4096 {0x0C,0x09,0x01,0x08,0x32},
4097 {0x0B,0x08,0x02,0x08,0x21},
4098 {0x0C,0x08,0x01,0x08,0x30},
4099 {0x0A,0x08,0x02,0x04,0x11},
4100 {0x0B,0x0A,0x01,0x10,0x28},
4101 {0x09,0x08,0x02,0x02,0x01},
4102 {0x0B,0x09,0x01,0x08,0x24},
4103 {0x0B,0x08,0x01,0x04,0x20},
4104 {0x0A,0x08,0x01,0x02,0x10},
4105 {0x09,0x08,0x01,0x01,0x00}
4108 buswidth
= sisfb_chkbuswidth300(pdev
, FBAddr
);
4112 for(i
= 6; i
>= 0; i
--) {
4114 PseudoRankCapacity
= 1 << i
;
4115 for(j
= 4; j
>= 1; j
--) {
4117 PseudoTotalCapacity
= PseudoRankCapacity
* j
;
4118 PseudoAdrPinCount
= 15 - j
;
4119 if(PseudoTotalCapacity
<= 64) {
4120 for(k
= 0; k
<= 16; k
++) {
4122 RankCapacity
= buswidth
* SiS_DRAMType
[k
][3];
4123 AdrPinCount
= SiS_DRAMType
[k
][2] + SiS_DRAMType
[k
][0];
4124 if(RankCapacity
== PseudoRankCapacity
)
4125 if(AdrPinCount
<= PseudoAdrPinCount
) {
4126 if(j
== 3) { /* Rank No */
4127 BankNumHigh
= RankCapacity
* MB2Bank
* 3 - 1;
4128 BankNumMid
= RankCapacity
* MB2Bank
* 1 - 1;
4130 BankNumHigh
= RankCapacity
* MB2Bank
* j
- 1;
4131 BankNumMid
= RankCapacity
* MB2Bank
* j
/ 2 - 1;
4133 PageCapacity
= (1 << SiS_DRAMType
[k
][1]) * buswidth
* 4;
4134 PhysicalAdrHigh
= BankNumHigh
;
4135 PhysicalAdrHalfPage
= (PageCapacity
/ 2 + PhysicalAdrHigh
) % PageCapacity
;
4136 PhysicalAdrOtherPage
= PageCapacity
* SiS_DRAMType
[k
][2] + PhysicalAdrHigh
;
4138 andSISIDXREG(SISSR
,0x15,0xFB); /* Test */
4139 orSISIDXREG(SISSR
,0x15,0x04); /* Test */
4140 TotalCapacity
= SiS_DRAMType
[k
][3] * buswidth
;
4141 SR13
= SiS_DRAMType
[k
][4];
4142 if(buswidth
== 4) SR14
= (TotalCapacity
- 1) | 0x80;
4143 if(buswidth
== 2) SR14
= (TotalCapacity
- 1) | 0x40;
4144 if(buswidth
== 1) SR14
= (TotalCapacity
- 1) | 0x00;
4145 outSISIDXREG(SISSR
,0x13,SR13
);
4146 outSISIDXREG(SISSR
,0x14,SR14
);
4147 Addr
= FBAddr
+ BankNumHigh
* 64 * 1024 + PhysicalAdrHigh
;
4148 /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */
4149 writew(((USHORT
)PhysicalAdrHigh
), Addr
);
4150 Addr
= FBAddr
+ BankNumMid
* 64 * 1024 + PhysicalAdrHigh
;
4151 /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */
4152 writew(((USHORT
)BankNumMid
), Addr
);
4153 Addr
= FBAddr
+ BankNumHigh
* 64 * 1024 + PhysicalAdrHalfPage
;
4154 /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */
4155 writew(((USHORT
)PhysicalAdrHalfPage
), Addr
);
4156 Addr
= FBAddr
+ BankNumHigh
* 64 * 1024 + PhysicalAdrOtherPage
;
4157 /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */
4158 writew(((USHORT
)PhysicalAdrOtherPage
), Addr
);
4160 Addr
= FBAddr
+ BankNumHigh
* 64 * 1024 + PhysicalAdrHigh
;
4161 data
= readw(Addr
); /* *((USHORT *)(Addr)); */
4162 if(data
== PhysicalAdrHigh
) Done
= 1;
4170 static void __devinit
sisfb_post_sis300(struct pci_dev
*pdev
)
4172 struct sis_video_info
*ivideo
= pci_get_drvdata(pdev
);
4173 u8 reg
, v1
, v2
, v3
, v4
, v5
, v6
, v7
, v8
;
4174 u16 index
, rindex
, memtype
= 0;
4176 outSISIDXREG(SISSR
,0x05,0x86);
4178 if(ivideo
->sishw_ext
.UseROM
) {
4179 if(ivideo
->sishw_ext
.pjVirtualRomBase
[0x52] & 0x80) {
4180 memtype
= ivideo
->sishw_ext
.pjVirtualRomBase
[0x52];
4182 inSISIDXREG(SISSR
,0x3a,memtype
);
4187 if(ivideo
->revision_id
<= 0x13) {
4188 v1
= 0x44; v2
= 0x42; v3
= 0x80;
4189 v4
= 0x44; v5
= 0x42; v6
= 0x80;
4191 v1
= 0x68; v2
= 0x43; v3
= 0x80; /* Assume 125Mhz MCLK */
4192 v4
= 0x68; v5
= 0x43; v6
= 0x80; /* Assume 125Mhz ECLK */
4193 if(ivideo
->sishw_ext
.UseROM
) {
4194 index
= memtype
* 5;
4195 rindex
= index
+ 0x54;
4196 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[rindex
++];
4197 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[rindex
++];
4198 v3
= ivideo
->sishw_ext
.pjVirtualRomBase
[rindex
++];
4199 rindex
= index
+ 0x7c;
4200 v4
= ivideo
->sishw_ext
.pjVirtualRomBase
[rindex
++];
4201 v5
= ivideo
->sishw_ext
.pjVirtualRomBase
[rindex
++];
4202 v6
= ivideo
->sishw_ext
.pjVirtualRomBase
[rindex
++];
4205 outSISIDXREG(SISSR
,0x28,v1
);
4206 outSISIDXREG(SISSR
,0x29,v2
);
4207 outSISIDXREG(SISSR
,0x2a,v3
);
4208 outSISIDXREG(SISSR
,0x2e,v4
);
4209 outSISIDXREG(SISSR
,0x2f,v5
);
4210 outSISIDXREG(SISSR
,0x30,v6
);
4212 if(ivideo
->sishw_ext
.UseROM
) v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xa4];
4213 outSISIDXREG(SISSR
,0x07,v1
); /* DAC speed */
4214 outSISIDXREG(SISSR
,0x11,0x0f); /* DDC, power save */
4215 v1
= 0x01; v2
= 0x43; v3
= 0x1e; v4
= 0x2a;
4216 v5
= 0x06; v6
= 0x00; v7
= 0x00; v8
= 0x00;
4217 if(ivideo
->sishw_ext
.UseROM
) {
4219 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[memtype
];
4220 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[memtype
+ 8];
4221 v3
= ivideo
->sishw_ext
.pjVirtualRomBase
[memtype
+ 16];
4222 v4
= ivideo
->sishw_ext
.pjVirtualRomBase
[memtype
+ 24];
4223 v5
= ivideo
->sishw_ext
.pjVirtualRomBase
[memtype
+ 32];
4224 v6
= ivideo
->sishw_ext
.pjVirtualRomBase
[memtype
+ 40];
4225 v7
= ivideo
->sishw_ext
.pjVirtualRomBase
[memtype
+ 48];
4226 v8
= ivideo
->sishw_ext
.pjVirtualRomBase
[memtype
+ 56];
4228 if(ivideo
->revision_id
>= 0x80) v3
&= 0xfd;
4229 outSISIDXREG(SISSR
,0x15,v1
); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4230 outSISIDXREG(SISSR
,0x16,v2
);
4231 outSISIDXREG(SISSR
,0x17,v3
);
4232 outSISIDXREG(SISSR
,0x18,v4
);
4233 outSISIDXREG(SISSR
,0x19,v5
);
4234 outSISIDXREG(SISSR
,0x1a,v6
);
4235 outSISIDXREG(SISSR
,0x1b,v7
);
4236 outSISIDXREG(SISSR
,0x1c,v8
); /* ---- */
4237 andSISIDXREG(SISSR
,0x15,0xfb);
4238 orSISIDXREG(SISSR
,0x15,0x04);
4239 if(ivideo
->sishw_ext
.UseROM
) {
4240 if(ivideo
->sishw_ext
.pjVirtualRomBase
[0x53] & 0x02) {
4241 orSISIDXREG(SISSR
,0x19,0x20);
4244 v1
= 0x04; /* DAC pedestal (BIOS 0xe5) */
4245 if(ivideo
->revision_id
>= 0x80) v1
|= 0x01;
4246 outSISIDXREG(SISSR
,0x1f,v1
);
4247 outSISIDXREG(SISSR
,0x20,0xa0); /* linear & relocated io */
4248 v1
= 0xf6; v2
= 0x0d; v3
= 0x00;
4249 if(ivideo
->sishw_ext
.UseROM
) {
4250 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xe8];
4251 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xe9];
4252 v3
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xea];
4254 outSISIDXREG(SISSR
,0x23,v1
);
4255 outSISIDXREG(SISSR
,0x24,v2
);
4256 outSISIDXREG(SISSR
,0x25,v3
);
4257 outSISIDXREG(SISSR
,0x21,0x84);
4258 outSISIDXREG(SISSR
,0x22,0x00);
4259 outSISIDXREG(SISCR
,0x37,0x00);
4260 orSISIDXREG(SISPART1
,0x24,0x01); /* unlock crt2 */
4261 outSISIDXREG(SISPART1
,0x00,0x00);
4262 v1
= 0x40; v2
= 0x11;
4263 if(ivideo
->sishw_ext
.UseROM
) {
4264 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xec];
4265 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xeb];
4267 outSISIDXREG(SISPART1
,0x02,v1
);
4268 if(ivideo
->revision_id
>= 0x80) v2
&= ~0x01;
4269 inSISIDXREG(SISPART4
,0x00,reg
);
4270 if((reg
== 1) || (reg
== 2)) {
4271 outSISIDXREG(SISCR
,0x37,0x02);
4272 outSISIDXREG(SISPART2
,0x00,0x1c);
4273 v4
= 0x00; v5
= 0x00; v6
= 0x10;
4274 if(ivideo
->sishw_ext
.UseROM
) {
4275 v4
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xf5];
4276 v5
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xf6];
4277 v6
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xf7];
4279 outSISIDXREG(SISPART4
,0x0d,v4
);
4280 outSISIDXREG(SISPART4
,0x0e,v5
);
4281 outSISIDXREG(SISPART4
,0x10,v6
);
4282 outSISIDXREG(SISPART4
,0x0f,0x3f);
4283 inSISIDXREG(SISPART4
,0x01,reg
);
4285 inSISIDXREG(SISPART4
,0x23,reg
);
4288 outSISIDXREG(SISPART4
,0x23,reg
);
4293 outSISIDXREG(SISSR
,0x32,v2
);
4294 andSISIDXREG(SISPART1
,0x24,0xfe); /* Lock CRT2 */
4295 inSISIDXREG(SISSR
,0x16,reg
);
4297 outSISIDXREG(SISCR
,0x35,reg
);
4298 outSISIDXREG(SISCR
,0x83,0x00);
4299 #if !defined(__i386__) && !defined(__x86_64__)
4300 if(sisfb_videoram
) {
4301 outSISIDXREG(SISSR
,0x13,0x28); /* ? */
4302 reg
= ((sisfb_videoram
>> 10) - 1) | 0x40;
4303 outSISIDXREG(SISSR
,0x14,reg
);
4306 /* Need to map max FB size for finding out about RAM size */
4307 ivideo
->sishw_ext
.pjVideoMemoryAddress
= ioremap(ivideo
->video_base
, 0x4000000);
4308 if(ivideo
->sishw_ext
.pjVideoMemoryAddress
) {
4309 sisfb_setramsize300(pdev
);
4310 iounmap(ivideo
->sishw_ext
.pjVideoMemoryAddress
);
4312 printk(KERN_DEBUG
"sisfb: Failed to map memory for size detection, assuming 8MB\n");
4313 outSISIDXREG(SISSR
,0x13,0x28); /* ? */
4314 outSISIDXREG(SISSR
,0x14,0x47); /* 8MB, 64bit default */
4316 #if !defined(__i386__) && !defined(__x86_64__)
4319 if(ivideo
->sishw_ext
.UseROM
) {
4320 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xe6];
4321 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xe7];
4323 inSISIDXREG(SISSR
,0x3a,reg
);
4324 if((reg
& 0x30) == 0x30) {
4325 v1
= 0x04; /* PCI */
4328 v1
= 0x14; /* AGP */
4332 outSISIDXREG(SISSR
,0x21,v1
);
4333 outSISIDXREG(SISSR
,0x22,v2
);
4337 #ifdef CONFIG_FB_SIS_315
4338 static void __devinit
sisfb_post_sis315330(struct pci_dev
*pdev
)
4340 #ifdef YET_TO_BE_DONE
4341 struct sis_video_info
*ivideo
= pci_get_drvdata(pdev
);
4342 u8 reg
, v1
, v2
, v3
, v4
, v5
, v6
, v7
, v8
;
4343 u16 index
, rindex
, memtype
= 0;
4344 u32 reg1_32
, reg2_32
, reg3_32
;
4348 /* outSISIDXREG(0x3c4,0x05,0x86); */
4349 outSISIDXREG(SISSR
,0x05,0x86);
4351 /* Enable relocated i/o ports */
4352 /* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */
4353 setSISIDXREG(SISSR
,0x20,~0x10,0x20);
4356 for(i
= 0; i
< 0x22; i
++) {
4357 outSISIDXREG(SISSR
,(0x06 + i
),0x00);
4360 if( is
330) v1
= 0x0b;
4361 for(i
= 0; i
< v1
; i
++) {
4362 outSISIDXREG(SISSR
,(0x31 + i
),0x00);
4364 for(i
= 0; i
< 0x10; i
++) {
4365 outSISIDXREG(SISCR
,(0x30 + i
),0x00);
4369 reg
= inSISREG(SISMISCR
);
4370 outSISIDXREG(SISSR
,0x28,0x81);
4371 outSISIDXREG(SISSR
,0x2A,0x00);
4372 outSISIDXREG(SISSR
,0x29,0xE1);
4373 outSISREG(SISMISCW
,(reg
| 0x0c));
4374 outSISIDXREG(SISSR
,0x2B,0x81);
4375 outSISIDXREG(SISSR
,0x2D,0x00);
4376 outSISIDXREG(SISSR
,0x2C,0xE1);
4377 outSISIDXREG(SISSR
,0x2E,0x81);
4378 outSISIDXREG(SISSR
,0x30,0x00);
4379 outSISIDXREG(SISSR
,0x2F,0xE1);
4380 SiS_DDC2Delay(....);
4381 outSISREG(SISMISCW
,reg
);
4383 /* Get memory type */
4384 if(ivideo
->sishw_ext
.UseROM
) {
4385 if(ivideo
->sishw_ext
.pjVirtualRomBase
[0x52] & 0x80)) {
4386 memtype
= ivideo
->sishw_ext
.pjVirtualRomBase
[0x52];
4388 inSISIDXREG(SISSR
,0x3a,memtype
);
4392 if(memtype
<= 1) memtype
= 0;
4394 inSISIDXREG(SISCR
,0x5F,reg
);
4397 case 0x00: memtype
= 1; break;
4398 case 0x10: memtype
= 3; break;
4399 case 0x20: memtype
= 3; break;
4400 default: memtype
= 2;
4407 v1
= 0x3b; v2
= 0x22; v3
= 0x01; /* Assume 143Mhz MCLK */
4408 v4
= 0x5c; v5
= 0x23; v6
= 0x01; /* Assume 166Mhz ECLK */
4409 if(ivideo
->sishw_ext
.UseROM
) {
4410 index
= memtype
* 5;
4411 rindex
= index
+ 0x54;
4412 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[rindex
++];
4413 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[rindex
++];
4414 v3
= ivideo
->sishw_ext
.pjVirtualRomBase
[rindex
++];
4415 rindex
= index
+ 0x68;
4416 v4
= ivideo
->sishw_ext
.pjVirtualRomBase
[rindex
++];
4417 v5
= ivideo
->sishw_ext
.pjVirtualRomBase
[rindex
++];
4418 v6
= ivideo
->sishw_ext
.pjVirtualRomBase
[rindex
++];
4420 outSISIDXREG(SISSR
,0x28,v1
);
4421 outSISIDXREG(SISSR
,0x29,v2
);
4422 outSISIDXREG(SISSR
,0x2a,v3
);
4424 inSISIDXREG(SISSR
,0x3a,reg
);
4430 outSISIDXREG(SISSR
,0x2e,v4
);
4431 outSISIDXREG(SISSR
,0x2f,v5
);
4432 outSISIDXREG(SISSR
,0x30,v6
);
4434 /* End of comp with 330 */
4437 if(ivideo
->sishw_ext
.UseROM
) v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0x7c];
4438 outSISIDXREG(SISSR
,0x07,v1
);
4439 outSISIDXREG(SISSR
,0x11,0x0f);
4441 v1
= 0x00; v2
= 0x0f; v3
= 0xba; v4
= 0xa9;
4442 v5
= 0xa0; v6
= 0x00; v7
= 0x30;
4443 if(ivideo
->sishw_ext
.UseROM
) {
4444 index
= memtype
+ 0x7d;
4445 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
];
4446 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 4];
4447 v3
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 8];
4448 v4
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 12];
4449 v5
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 16];
4450 v6
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 20];
4451 v7
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 24];
4453 outSISIDXREG(SISSR
,0x15,v1
); /* Ram type (assuming 0, BIOS 0x7d step 4) */
4454 outSISIDXREG(SISSR
,0x16,v2
);
4455 outSISIDXREG(SISSR
,0x17,v3
);
4456 outSISIDXREG(SISSR
,0x18,v4
);
4457 outSISIDXREG(SISSR
,0x19,v5
);
4458 outSISIDXREG(SISSR
,0x1a,v6
);
4459 outSISIDXREG(SISSR
,0x1b,v7
);
4460 outSISIDXREG(SISSR
,0x1c,v8
); /* ---- */
4462 v1
= 0x77; v2
= 0x77; v3
= 0x00; v4
= 0x5b; v5
= 0x00;
4463 if(ivideo
->sishw_ext
.UseROM
) {
4464 index
= memtype
+ 0xa2;
4465 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
];
4466 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 4];
4467 v3
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 8];
4468 v4
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 12];
4469 v5
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 16];
4471 outSISIDXREG(SISCR
,0x40,v1
);
4472 outSISIDXREG(SISCR
,0x41,v2
);
4473 outSISIDXREG(SISCR
,0x42,v3
);
4474 outSISIDXREG(SISCR
,0x43,v4
);
4475 outSISIDXREG(SISCR
,0x44,v5
);
4480 if(ivideo
->sishw_ext
.UseROM
) {
4481 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xBA];
4483 outSISIDXREG(SISCR
,0x59,v1
);
4485 v1
= 0x
; v2
= 0x
; v3
= 0x
; v4
= 0x
;
4486 v5
= 0x
; v6
= 0x
; v7
= 0x
; v8
= 0x
;
4487 if(ivideo
->sishw_ext
.UseROM
) {
4488 index
= memtype
+ 0xbe;
4489 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
];
4490 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 4];
4491 v3
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 8];
4492 v4
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 12];
4493 v5
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 16];
4494 v6
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 20];
4495 v7
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 24];
4496 v8
= ivideo
->sishw_ext
.pjVirtualRomBase
[index
+ 28];
4498 outSISIDXREG(SISCR
,0x68,v1
);
4499 outSISIDXREG(SISCR
,0x69,v2
);
4500 outSISIDXREG(SISCR
,0x6a,v3
);
4501 outSISIDXREG(SISCR
,0x6b,v4
);
4502 outSISIDXREG(SISCR
,0x6c,v5
);
4503 outSISIDXREG(SISCR
,0x6d,v6
);
4504 outSISIDXREG(SISCR
,0x6e,v7
);
4505 outSISIDXREG(SISCR
,0x6f,v8
);
4508 inSISIDXREG(SISSR
,0x3b,reg
);
4511 inSISIDXREG(SISCR
,0x5F,reg
);
4515 outSISIDXREG(SISCR
,0x48,v1
);
4516 outSISIDXREG(SISCR
,0x4c,0x20);
4521 if(ivideo
->sishw_ext
.UseROM
) {
4522 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xBA];
4524 outSISIDXREG(SISCR
,0x59,v1
);
4531 outSISIDXREG(SISCR
,0x48,0x23);
4533 andSISIDXREG(SISSR
,0x16,0x0f);
4535 orSISIDXREG(SISSR
,0x16,0x80);
4538 if(ivideo
->sishw_ext
.UseROM
) {
4539 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0x81 + memtype
];
4541 if(!(v1
& 0x10)) v2
= 0xc0;
4543 orSISIDXREG(SISSR
,0x16,v2
);
4544 andSISIDXREG(SISSR
,0x16,0x0f);
4545 if(!(v1
& 0x10)) v2
= 0x80;
4547 orSISIDXREG(SISSR
,0x16,v2
);
4551 const u8 sr3cseq1
[] = { 0xc0,0xe0,0xf0,0xe0,0xf0,0xa0,0xb0,0xa0,0xb0,0x90,0xd0 };
4552 const u8 sr3cseq2
[] = { 0xc0,0xa0,0xb0,0xa0,0xb0,0xe0,0xf0,0xa0,0xb0,0x90,0xd0 };
4553 for(i
= 0; i
< 11; i
++) {
4554 outSISIDXREG(SISSR
,0x3c,sr3cseq1
[i
]);
4556 outSISIDXREG(SISSR
,0x3d,0x00);
4557 outSISIDXREG(SISSR
,0x3d,0x04);
4558 SiS_DDC2Delay(0x200);
4559 v1
= inSISIDXREG(SISCR
,0xEC);
4560 v2
= inSISIDXREG(SISCR
,0xED);
4561 reg1_32
= (v2
<< 8) | v1
;
4562 outSISIDXREG(SISSR
,0x3D,0x00);
4563 for(i
= 0; i
< 11; i
++) {
4564 outSISIDXREG(SISSR
,0x3c,sr3cseq2
[i
]);
4566 outSISIDXREG(SISSR
,0x3d,0x00);
4567 outSISIDXREG(SISSR
,0x3d,0x04);
4568 SiS_DDC2Delay(0x200);
4569 v1
= inSISIDXREG(SISCR
,0xEC);
4570 v2
= inSISIDXREG(SISCR
,0xED);
4571 reg2_32
= (v2
<< 8) | v1
;
4572 outSISIDXREG(SISSR
,0x3D,0x00);
4573 reg3_32
= reg2_32
<< 1;
4577 if(reg3_32
> reg1_32
) v1
= 0x10;
4578 outSISIDXREG(SISCR
,0x59,v1
);
4584 if(ivideo
->sishw_ext
.UseROM
) {
4585 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0x99];
4587 outSISIDXREG(SISSR
,0x1f,v1
);
4589 outSISIDXREG(SISSR
,0x20,0x20);
4591 v1
= 0xf6; v2
= 0x0d; v3
= 0x33;
4592 if(ivideo
->sishw_ext
.UseROM
) {
4593 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0x9c];
4594 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[0x9d];
4595 v3
= ivideo
->sishw_ext
.pjVirtualRomBase
[0x9e];
4597 outSISIDXREG(SISSR
,0x23,v1
);
4598 outSISIDXREG(SISSR
,0x24,v2
);
4599 outSISIDXREG(SISSR
,0x25,v3
);
4601 outSISIDXREG(SISSR
,0x21,0x84);
4602 outSISIDXREG(SISSR
,0x22,0x00);
4603 outSISIDXREG(SISSR
,0x27,0x1f);
4605 v1
= 0x00; v2
= 0x00;
4606 if(ivideo
->sishw_ext
.UseROM
) {
4607 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0x9F];
4608 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xA1];
4610 outSISIDXREG(SISSR
,0x31,v1
);
4611 outSISIDXREG(SISSR
,0x33,v2
);
4614 if(ivideo
->sishw_ext
.UseROM
) {
4615 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xA0];
4617 v2
= inSISIDXREG(SISPART4
,0x00);
4618 if((v2
!= 1) && (v2
!= 2)) v1
&= 0xef;
4619 outSISIDXREG(SISSR
,0x32,v1
);
4622 pci_read_config_long(pdev
, 0x50, ®1_32
);
4626 v1
= 0xAA; v2
= 0x33;
4627 if(ivideo
->sishw_ext
.UseROM
) {
4628 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xF7];
4629 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[0x9E];
4632 v1
= 0x88; v2
= 0x03;
4633 if(ivideo
->sishw_ext
.UseROM
) {
4634 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xF8];
4635 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xF6];
4638 outSISIDXREG(SISCR
,0x49,v1
);
4639 outSISIDXREG(SISSR
,0x25,v2
);
4641 v1
= inSISIDXREG(SISPART4
,0x00);
4642 if((v1
== 1) || (v1
== 2)) {
4643 orSISIDXREG(SISPART1
,0x2F,0x01); /* Unlock CRT2 */
4644 outSISIDXREG(SISPART1
,0x00,0x00);
4646 if(ivideo
->sishw_ext
.UseROM
) {
4647 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xb6];
4649 outSISIDXREG(SISPART1
,0x02,v1
);
4650 outSISIDXREG(SISPART1
,0x2E,0x08);
4651 outSISIDXREG(SISPART2
,0x00,0x1c);
4652 v1
= 0x40; v2
= 0x00; v3
= 0x80;
4653 if(ivideo
->sishw_ext
.UseROM
) {
4654 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xb7];
4655 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xb8];
4656 v3
= ivideo
->sishw_ext
.pjVirtualRomBase
[0xbb];
4658 outSISIDXREG(SISPART4
,0x0d,v1
);
4659 outSISIDXREG(SISPART4
,0x0e,v2
);
4660 outSISIDXREG(SISPART4
,0x10,v3
);
4661 outSISIDXREG(SISPART4
,0x0F,0x3F);
4663 inSISIDXREG(SISPART4
,0x01,reg
);
4665 inSISIDXREG(SISPART4
,0x23,reg
);
4668 outSISIDXREG(SISPART4
,0x23,reg
);
4671 outSISIDXREG(SISCR
,0x37,0x02); /* Why? */
4673 outSISIDXREG(SISCR
,0x83,0x00);
4674 outSISIDXREG(SISCR
,0x90,0x00);
4675 andSISIDXREG(SISSR
,0x5B,0xDF);
4676 outSISIDXREG(SISVID
,0x00,0x86);
4677 outSISIDXREG(SISVID
,0x32,0x00);
4678 outSISIDXREG(SISVID
,0x30,0x00);
4679 outSISIDXREG(SISVID
,0x32,0x01);
4680 outSISIDXREG(SISVID
,0x30,0x00);
4681 orSISIDXREG(SISCR
,0x63,0x80);
4687 orSISIDXREG(SISSR
,0x16,0x0f);
4688 orSISIDXREG(SISSR
,0x18,0xA9);
4689 orSISIDXREG(SISSR
,0x19,0xA0);
4690 orSISIDXREG(SISSR
,0x1B,0x30);
4691 andSISIDXREG(SISSR
,0x17,0xF8);
4692 orSISIDXREG(SISSR
,0x19,0x03);
4693 andSIDIDXREG(SISSR
,0x13,0x00);
4695 /* Need to map max FB size for finding out about RAM size */
4696 ivideo
->sishw_ext
.pjVideoMemoryAddress
= ioremap(ivideo
->video_base
, 0x4000000);
4697 if(ivideo
->sishw_ext
.pjVideoMemoryAddress
) {
4698 /* Find out about bus width */
4700 outSISIDXREG(SISSR
,0x14,0x02);
4701 andSISIDXREG(SISSR
,0x16,0x0F);
4702 orSISIDXREG(SISSR
,0x16,0x80);
4712 /* Find out about size */
4715 iounmap(ivideo
->sishw_ext
.pjVideoMemoryAddress
);
4717 printk(KERN_DEBUG
"sisfb: Failed to map memory for size detection, assuming 8MB\n");
4718 outSISIDXREG(SISSR
,0x14,0x
??); /* 8MB, 64bit default */
4721 /* AGP (Missing: Checks for VIA and AMD hosts) */
4722 v1
= 0xA5; v2
= 0xFB;
4723 if(ivideo
->sishw_ext
.UseROM
) {
4724 v1
= ivideo
->sishw_ext
.pjVirtualRomBase
[0x9A];
4725 v2
= ivideo
->sishw_ext
.pjVirtualRomBase
[0x9B];
4727 outSISIDXREG(SISSR
,0x21,v1
);
4728 outSISIDXREG(SISSR
,0x22,v2
);
4736 int __devinit
sisfb_probe(struct pci_dev
*pdev
, const struct pci_device_id
*ent
)
4738 struct sisfb_chip_info
*chipinfo
= &sisfb_chip_info
[ent
->driver_data
];
4739 struct sis_video_info
*ivideo
= NULL
;
4740 struct fb_info
*sis_fb_info
= NULL
;
4743 int sisvga_enabled
= 0, i
;
4745 if(sisfb_off
) return -ENXIO
;
4747 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
4748 sis_fb_info
= framebuffer_alloc(sizeof(*ivideo
), &pdev
->dev
);
4749 if(!sis_fb_info
) return -ENOMEM
;
4751 sis_fb_info
= kmalloc(sizeof(*sis_fb_info
) + sizeof(*ivideo
), GFP_KERNEL
);
4752 if(!sis_fb_info
) return -ENOMEM
;
4753 memset(sis_fb_info
, 0, sizeof(*sis_fb_info
) + sizeof(*ivideo
));
4754 sis_fb_info
->par
= ((char *)sis_fb_info
+ sizeof(*sis_fb_info
));
4757 ivideo
= (struct sis_video_info
*)sis_fb_info
->par
;
4758 ivideo
->memyselfandi
= sis_fb_info
;
4760 if(card_list
== NULL
) {
4761 ivideo
->cardnumber
= 0;
4763 struct sis_video_info
*countvideo
= card_list
;
4764 ivideo
->cardnumber
= 1;
4765 while ((countvideo
= countvideo
->next
) != NULL
) ivideo
->cardnumber
++;
4768 strncpy(ivideo
->myid
, chipinfo
->chip_name
, 30);
4770 ivideo
->chip_id
= pdev
->device
;
4771 pci_read_config_byte(pdev
, PCI_REVISION_ID
, &ivideo
->revision_id
);
4772 ivideo
->sishw_ext
.jChipRevision
= ivideo
->revision_id
;
4773 pci_read_config_word(pdev
, PCI_COMMAND
, ®16
);
4774 sisvga_enabled
= reg16
& 0x01;
4775 ivideo
->pcibus
= pdev
->bus
->number
;
4776 ivideo
->pcislot
= PCI_SLOT(pdev
->devfn
);
4777 ivideo
->pcifunc
= PCI_FUNC(pdev
->devfn
);
4778 ivideo
->subsysvendor
= pdev
->subsystem_vendor
;
4779 ivideo
->subsysdevice
= pdev
->subsystem_device
;
4780 #ifdef SIS_CONFIG_COMPAT
4781 ivideo
->ioctl32registered
= 0;
4782 ivideo
->ioctl32vblankregistered
= 0;
4786 if(sisfb_mode_idx
== -1) {
4787 sisfb_get_vga_mode_from_kernel();
4791 ivideo
->chip
= chipinfo
->chip
;
4792 ivideo
->sisvga_engine
= chipinfo
->vgaengine
;
4793 ivideo
->hwcursor_size
= chipinfo
->hwcursor_size
;
4794 ivideo
->CRT2_write_enable
= chipinfo
->CRT2_write_enable
;
4795 ivideo
->mni
= chipinfo
->mni
;
4797 ivideo
->detectedpdc
= 0xff;
4798 ivideo
->detectedpdca
= 0xff;
4799 ivideo
->detectedlcda
= 0xff;
4801 ivideo
->sisfb_thismonitor
.datavalid
= FALSE
;
4803 ivideo
->sisfb_parm_mem
= sisfb_parm_mem
;
4804 ivideo
->sisfb_accel
= sisfb_accel
;
4805 ivideo
->sisfb_ypan
= sisfb_ypan
;
4806 ivideo
->sisfb_max
= sisfb_max
;
4807 ivideo
->sisfb_userom
= sisfb_userom
;
4808 ivideo
->sisfb_useoem
= sisfb_useoem
;
4809 ivideo
->sisfb_mode_idx
= sisfb_mode_idx
;
4810 ivideo
->sisfb_parm_rate
= sisfb_parm_rate
;
4811 ivideo
->sisfb_crt1off
= sisfb_crt1off
;
4812 ivideo
->sisfb_forcecrt1
= sisfb_forcecrt1
;
4813 ivideo
->sisfb_crt2type
= sisfb_crt2type
;
4814 ivideo
->sisfb_crt2flags
= sisfb_crt2flags
;
4815 /* pdc(a), scalelcd, special timing, lvdshl handled below */
4816 ivideo
->sisfb_dstn
= sisfb_dstn
;
4817 ivideo
->sisfb_fstn
= sisfb_fstn
;
4818 ivideo
->sisfb_tvplug
= sisfb_tvplug
;
4819 ivideo
->sisfb_tvstd
= sisfb_tvstd
;
4820 ivideo
->tvxpos
= sisfb_tvxposoffset
;
4821 ivideo
->tvypos
= sisfb_tvyposoffset
;
4822 ivideo
->sisfb_filter
= sisfb_filter
;
4823 ivideo
->sisfb_nocrt2rate
= sisfb_nocrt2rate
;
4824 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4825 ivideo
->sisfb_inverse
= sisfb_inverse
;
4828 ivideo
->refresh_rate
= 0;
4829 if(ivideo
->sisfb_parm_rate
!= -1) {
4830 ivideo
->refresh_rate
= ivideo
->sisfb_parm_rate
;
4833 ivideo
->SiS_Pr
.UsePanelScaler
= sisfb_scalelcd
;
4834 ivideo
->SiS_Pr
.CenterScreen
= -1;
4835 ivideo
->SiS_Pr
.SiS_CustomT
= sisfb_specialtiming
;
4836 ivideo
->SiS_Pr
.LVDSHL
= sisfb_lvdshl
;
4838 ivideo
->SiS_Pr
.SiS_Backup70xx
= 0xff;
4839 ivideo
->SiS_Pr
.SiS_CHOverScan
= -1;
4840 ivideo
->SiS_Pr
.SiS_ChSW
= FALSE
;
4841 ivideo
->SiS_Pr
.SiS_UseLCDA
= FALSE
;
4842 ivideo
->SiS_Pr
.HaveEMI
= FALSE
;
4843 ivideo
->SiS_Pr
.HaveEMILCD
= FALSE
;
4844 ivideo
->SiS_Pr
.OverruleEMI
= FALSE
;
4845 ivideo
->SiS_Pr
.SiS_SensibleSR11
= FALSE
;
4846 ivideo
->SiS_Pr
.SiS_MyCR63
= 0x63;
4847 ivideo
->SiS_Pr
.PDC
= -1;
4848 ivideo
->SiS_Pr
.PDCA
= -1;
4849 #ifdef CONFIG_FB_SIS_315
4850 if(ivideo
->chip
>= SIS_330
) {
4851 ivideo
->SiS_Pr
.SiS_MyCR63
= 0x53;
4852 if(ivideo
->chip
>= SIS_661
) {
4853 ivideo
->SiS_Pr
.SiS_SensibleSR11
= TRUE
;
4858 memcpy(&ivideo
->default_var
, &my_default_var
, sizeof(my_default_var
));
4860 pci_set_drvdata(pdev
, ivideo
);
4862 /* Patch special cases */
4863 if((ivideo
->nbridge
= sisfb_get_northbridge(ivideo
->chip
))) {
4864 switch(ivideo
->nbridge
->device
) {
4865 #ifdef CONFIG_FB_SIS_300
4866 case PCI_DEVICE_ID_SI_730
:
4867 ivideo
->chip
= SIS_730
;
4868 strcpy(ivideo
->myid
, "SiS 730");
4871 #ifdef CONFIG_FB_SIS_315
4872 case PCI_DEVICE_ID_SI_651
:
4873 /* ivideo->chip is ok */
4874 strcpy(ivideo
->myid
, "SiS 651");
4876 case PCI_DEVICE_ID_SI_740
:
4877 ivideo
->chip
= SIS_740
;
4878 strcpy(ivideo
->myid
, "SiS 740");
4880 case PCI_DEVICE_ID_SI_661
:
4881 ivideo
->chip
= SIS_661
;
4882 strcpy(ivideo
->myid
, "SiS 661");
4884 case PCI_DEVICE_ID_SI_741
:
4885 ivideo
->chip
= SIS_741
;
4886 strcpy(ivideo
->myid
, "SiS 741");
4888 case PCI_DEVICE_ID_SI_760
:
4889 ivideo
->chip
= SIS_760
;
4890 strcpy(ivideo
->myid
, "SiS 760");
4896 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4897 strcpy(sis_fb_info
->modename
, ivideo
->myid
);
4900 ivideo
->sishw_ext
.jChipType
= ivideo
->chip
;
4902 #ifdef CONFIG_FB_SIS_315
4903 if((ivideo
->sishw_ext
.jChipType
== SIS_315PRO
) ||
4904 (ivideo
->sishw_ext
.jChipType
== SIS_315
)) {
4905 ivideo
->sishw_ext
.jChipType
= SIS_315H
;
4909 ivideo
->video_base
= pci_resource_start(pdev
, 0);
4910 ivideo
->mmio_base
= pci_resource_start(pdev
, 1);
4911 ivideo
->mmio_size
= pci_resource_len(pdev
, 1);
4912 ivideo
->SiS_Pr
.RelIO
= pci_resource_start(pdev
, 2) + 0x30;
4913 ivideo
->sishw_ext
.ulIOAddress
= ivideo
->vga_base
= ivideo
->SiS_Pr
.RelIO
;
4915 if(!sisvga_enabled
) {
4916 if(pci_enable_device(pdev
)) {
4917 pci_set_drvdata(pdev
, NULL
);
4923 SiSRegInit(&ivideo
->SiS_Pr
, ivideo
->sishw_ext
.ulIOAddress
);
4925 #ifdef CONFIG_FB_SIS_300
4926 /* Find PCI systems for Chrontel/GPIO communication setup */
4927 if(ivideo
->chip
== SIS_630
) {
4930 if(mychswtable
[i
].subsysVendor
== ivideo
->subsysvendor
&&
4931 mychswtable
[i
].subsysCard
== ivideo
->subsysdevice
) {
4932 ivideo
->SiS_Pr
.SiS_ChSW
= TRUE
;
4933 printk(KERN_DEBUG
"sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
4934 mychswtable
[i
].vendorName
, mychswtable
[i
].cardName
);
4938 } while(mychswtable
[i
].subsysVendor
!= 0);
4942 outSISIDXREG(SISSR
, 0x05, 0x86);
4944 if( (!sisvga_enabled
)
4945 #if !defined(__i386__) && !defined(__x86_64__)
4946 || (sisfb_resetcard
)
4949 for(i
= 0x30; i
<= 0x3f; i
++) {
4950 outSISIDXREG(SISCR
,i
,0x00);
4954 /* Find out about current video mode */
4955 inSISIDXREG(SISCR
,0x34,reg
);
4957 ivideo
->modeprechange
= reg
& 0x7f;
4959 ivideo
->modeprechange
= 0x03;
4960 #if defined(__i386__) || defined(__x86_64__)
4962 unsigned char __iomem
*tt
= ioremap(0, 0x1000);
4964 ivideo
->modeprechange
= tt
[0x449];
4971 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4973 if((reg
& 0x80) && (reg
!= 0xff)) {
4974 if((sisbios_mode
[ivideo
->sisfb_mode_idx
].mode_no
[ivideo
->mni
]) != 0xFF) {
4975 printk(KERN_INFO
"sisfb: Cannot initialize display mode, X server is active\n");
4976 pci_set_drvdata(pdev
, NULL
);
4984 ivideo
->sishw_ext
.bIntegratedMMEnabled
= TRUE
;
4985 #ifdef CONFIG_FB_SIS_300
4986 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
4987 if(ivideo
->chip
!= SIS_300
) {
4988 inSISIDXREG(SISSR
, 0x1a, reg
);
4990 ivideo
->sishw_ext
.bIntegratedMMEnabled
= FALSE
;
4996 ivideo
->bios_abase
= NULL
;
4997 ivideo
->bios_vbase
= NULL
;
4998 if(ivideo
->sisfb_userom
) {
4999 ivideo
->sishw_ext
.pjVirtualRomBase
= sis_find_rom(pdev
);
5000 #if defined(__i386__) || defined(__x86_64__)
5001 ivideo
->bios_vbase
= ivideo
->sishw_ext
.pjVirtualRomBase
; /* mapped */
5003 ivideo
->bios_abase
= ivideo
->sishw_ext
.pjVirtualRomBase
; /* allocated */
5005 if(ivideo
->sishw_ext
.pjVirtualRomBase
) {
5006 printk(KERN_INFO
"sisfb: Video ROM found and %s to 0x%p\n",
5007 ivideo
->bios_vbase
? "mapped" : "copied",
5008 ivideo
->sishw_ext
.pjVirtualRomBase
);
5009 ivideo
->sishw_ext
.UseROM
= TRUE
;
5011 ivideo
->sishw_ext
.UseROM
= FALSE
;
5012 printk(KERN_INFO
"sisfb: Video ROM not found\n");
5015 ivideo
->sishw_ext
.pjVirtualRomBase
= NULL
;
5016 ivideo
->sishw_ext
.UseROM
= FALSE
;
5017 printk(KERN_INFO
"sisfb: Video ROM usage disabled\n");
5020 /* Find systems for special custom timing */
5021 if(ivideo
->SiS_Pr
.SiS_CustomT
== CUT_NONE
) {
5023 unsigned char *biosver
= NULL
;
5024 unsigned char *biosdate
= NULL
;
5028 if(ivideo
->sishw_ext
.UseROM
) {
5029 biosver
= ivideo
->sishw_ext
.pjVirtualRomBase
+ 0x06;
5030 biosdate
= ivideo
->sishw_ext
.pjVirtualRomBase
+ 0x2c;
5031 for(i
=0; i
<32768; i
++) chksum
+= ivideo
->sishw_ext
.pjVirtualRomBase
[i
];
5036 if( (mycustomttable
[i
].chipID
== ivideo
->chip
) &&
5037 ((!strlen(mycustomttable
[i
].biosversion
)) ||
5038 (ivideo
->sishw_ext
.UseROM
&&
5039 (!strncmp(mycustomttable
[i
].biosversion
, biosver
, strlen(mycustomttable
[i
].biosversion
))))) &&
5040 ((!strlen(mycustomttable
[i
].biosdate
)) ||
5041 (ivideo
->sishw_ext
.UseROM
&&
5042 (!strncmp(mycustomttable
[i
].biosdate
, biosdate
, strlen(mycustomttable
[i
].biosdate
))))) &&
5043 ((!mycustomttable
[i
].bioschksum
) ||
5044 (ivideo
->sishw_ext
.UseROM
&&
5045 (mycustomttable
[i
].bioschksum
== chksum
))) &&
5046 (mycustomttable
[i
].pcisubsysvendor
== ivideo
->subsysvendor
) &&
5047 (mycustomttable
[i
].pcisubsyscard
== ivideo
->subsysdevice
) ) {
5049 for(j
= 0; j
< 5; j
++) {
5050 if(mycustomttable
[i
].biosFootprintAddr
[j
]) {
5051 if(ivideo
->sishw_ext
.UseROM
) {
5052 if(ivideo
->sishw_ext
.pjVirtualRomBase
[mycustomttable
[i
].biosFootprintAddr
[j
]] !=
5053 mycustomttable
[i
].biosFootprintData
[j
]) {
5056 } else footprint
= FALSE
;
5060 ivideo
->SiS_Pr
.SiS_CustomT
= mycustomttable
[i
].SpecialID
;
5061 printk(KERN_DEBUG
"sisfb: Identified [%s %s], special timing applies\n",
5062 mycustomttable
[i
].vendorName
,
5063 mycustomttable
[i
].cardName
);
5064 printk(KERN_DEBUG
"sisfb: [specialtiming parameter name: %s]\n",
5065 mycustomttable
[i
].optionName
);
5070 } while(mycustomttable
[i
].chipID
);
5073 #ifdef CONFIG_FB_SIS_300
5074 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
5075 if( (!sisvga_enabled
)
5076 #if !defined(__i386__) && !defined(__x86_64__)
5077 || (sisfb_resetcard
)
5080 if(ivideo
->chip
== SIS_300
) {
5081 sisfb_post_sis300(pdev
);
5087 #ifdef CONFIG_FB_SIS_315
5088 if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
5089 if( (!sisvga_enabled
)
5090 #if !defined(__i386__) && !defined(__x86_64__)
5091 || (sisfb_resetcard
)
5094 if((ivideo
->chip
== SIS_315H
) ||
5095 (ivideo
->chip
== SIS_315
) ||
5096 (ivideo
->chip
== SIS_315PRO
) ||
5097 (ivideo
->chip
== SIS_330
)) {
5098 sisfb_post_sis315330(pdev
);
5104 if(sisfb_get_dram_size(ivideo
)) {
5105 printk(KERN_INFO
"sisfb: Fatal error: Unable to determine RAM size.\n");
5106 if(ivideo
->bios_abase
) vfree(ivideo
->bios_abase
);
5107 pci_set_drvdata(pdev
, NULL
);
5112 if((ivideo
->sisfb_mode_idx
< 0) ||
5113 ((sisbios_mode
[ivideo
->sisfb_mode_idx
].mode_no
[ivideo
->mni
]) != 0xFF)) {
5114 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
5115 orSISIDXREG(SISSR
, IND_SIS_PCI_ADDRESS_SET
, (SIS_PCI_ADDR_ENABLE
| SIS_MEM_MAP_IO_ENABLE
));
5116 /* Enable 2D accelerator engine */
5117 orSISIDXREG(SISSR
, IND_SIS_MODULE_ENABLE
, SIS_ENABLE_2D
);
5120 if(sisfb_pdc
!= 0xff) {
5121 if(ivideo
->sisvga_engine
== SIS_300_VGA
) sisfb_pdc
&= 0x3c;
5122 else sisfb_pdc
&= 0x1f;
5123 ivideo
->SiS_Pr
.PDC
= sisfb_pdc
;
5125 #ifdef CONFIG_FB_SIS_315
5126 if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
5127 if(sisfb_pdca
!= 0xff) ivideo
->SiS_Pr
.PDCA
= sisfb_pdca
& 0x1f;
5131 if(!request_mem_region(ivideo
->video_base
, ivideo
->video_size
, "sisfb FB")) {
5132 printk(KERN_ERR
"sisfb: Fatal error: Unable to reserve frame buffer memory\n");
5133 printk(KERN_ERR
"sisfb: Is there another framebuffer driver active?\n");
5134 if(ivideo
->bios_abase
) vfree(ivideo
->bios_abase
);
5135 if(ivideo
->bios_vbase
) iounmap(ivideo
->bios_vbase
);
5136 pci_set_drvdata(pdev
, NULL
);
5141 if(!request_mem_region(ivideo
->mmio_base
, ivideo
->mmio_size
, "sisfb MMIO")) {
5142 printk(KERN_ERR
"sisfb: Fatal error: Unable to reserve MMIO region\n");
5143 release_mem_region(ivideo
->video_base
, ivideo
->video_size
);
5144 if(ivideo
->bios_abase
) vfree(ivideo
->bios_abase
);
5145 if(ivideo
->bios_vbase
) iounmap(ivideo
->bios_vbase
);
5146 pci_set_drvdata(pdev
, NULL
);
5151 ivideo
->video_vbase
= ioremap(ivideo
->video_base
, ivideo
->video_size
);
5152 ivideo
->sishw_ext
.pjVideoMemoryAddress
= ivideo
->video_vbase
;
5153 if(!ivideo
->video_vbase
) {
5154 printk(KERN_ERR
"sisfb: Fatal error: Unable to map frame buffer memory\n");
5155 release_mem_region(ivideo
->video_base
, ivideo
->video_size
);
5156 release_mem_region(ivideo
->mmio_base
, ivideo
->mmio_size
);
5157 if(ivideo
->bios_abase
) vfree(ivideo
->bios_abase
);
5158 if(ivideo
->bios_vbase
) iounmap(ivideo
->bios_vbase
);
5159 pci_set_drvdata(pdev
, NULL
);
5164 ivideo
->mmio_vbase
= ioremap(ivideo
->mmio_base
, ivideo
->mmio_size
);
5165 if(!ivideo
->mmio_vbase
) {
5166 printk(KERN_ERR
"sisfb: Fatal error: Unable to map MMIO region\n");
5167 iounmap(ivideo
->video_vbase
);
5168 release_mem_region(ivideo
->video_base
, ivideo
->video_size
);
5169 release_mem_region(ivideo
->mmio_base
, ivideo
->mmio_size
);
5170 if(ivideo
->bios_abase
) vfree(ivideo
->bios_abase
);
5171 if(ivideo
->bios_vbase
) iounmap(ivideo
->bios_vbase
);
5172 pci_set_drvdata(pdev
, NULL
);
5177 printk(KERN_INFO
"sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %ldk\n",
5178 ivideo
->video_base
, ivideo
->video_vbase
, ivideo
->video_size
/ 1024);
5180 printk(KERN_INFO
"sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
5181 ivideo
->mmio_base
, ivideo
->mmio_vbase
, ivideo
->mmio_size
/ 1024);
5183 if((ivideo
->havenoheap
= sisfb_heap_init(ivideo
))) {
5184 printk(KERN_WARNING
"sisfb: Failed to initialize offscreen memory heap\n");
5187 /* Used for clearing the screen only, therefore respect our mem limit */
5188 ivideo
->sishw_ext
.ulVideoMemorySize
= ivideo
->sisfb_mem
;
5192 ivideo
->vbflags
= 0;
5193 ivideo
->lcddefmodeidx
= DEFAULT_LCDMODE
;
5194 ivideo
->tvdefmodeidx
= DEFAULT_TVMODE
;
5195 ivideo
->defmodeidx
= DEFAULT_MODE
;
5197 ivideo
->newrom
= SiSDetermineROMLayout661(&ivideo
->SiS_Pr
, &ivideo
->sishw_ext
);
5199 if((ivideo
->sisfb_mode_idx
< 0) ||
5200 ((sisbios_mode
[ivideo
->sisfb_mode_idx
].mode_no
[ivideo
->mni
]) != 0xFF)) {
5202 sisfb_sense_crt1(ivideo
);
5204 sisfb_get_VB_type(ivideo
);
5206 if(ivideo
->vbflags
& VB_VIDEOBRIDGE
) {
5207 sisfb_detect_VB_connect(ivideo
);
5210 ivideo
->currentvbflags
= ivideo
->vbflags
& (VB_VIDEOBRIDGE
| TV_STANDARD
);
5212 if(ivideo
->vbflags
& VB_VIDEOBRIDGE
) {
5213 if(ivideo
->sisfb_crt2type
!= -1) {
5214 if((ivideo
->sisfb_crt2type
== CRT2_LCD
) && (ivideo
->vbflags
& CRT2_LCD
)) {
5215 ivideo
->currentvbflags
|= CRT2_LCD
;
5216 } else if(ivideo
->sisfb_crt2type
!= CRT2_LCD
) {
5217 ivideo
->currentvbflags
|= ivideo
->sisfb_crt2type
;
5220 /* Chrontel 700x TV detection often unreliable, therefore use a
5221 * different default order on such machines
5223 if((ivideo
->sisvga_engine
== SIS_300_VGA
) && (ivideo
->vbflags
& VB_CHRONTEL
)) {
5224 if(ivideo
->vbflags
& CRT2_LCD
) ivideo
->currentvbflags
|= CRT2_LCD
;
5225 else if(ivideo
->vbflags
& CRT2_TV
) ivideo
->currentvbflags
|= CRT2_TV
;
5226 else if(ivideo
->vbflags
& CRT2_VGA
) ivideo
->currentvbflags
|= CRT2_VGA
;
5228 if(ivideo
->vbflags
& CRT2_TV
) ivideo
->currentvbflags
|= CRT2_TV
;
5229 else if(ivideo
->vbflags
& CRT2_LCD
) ivideo
->currentvbflags
|= CRT2_LCD
;
5230 else if(ivideo
->vbflags
& CRT2_VGA
) ivideo
->currentvbflags
|= CRT2_VGA
;
5235 if(ivideo
->vbflags
& CRT2_LCD
) {
5236 inSISIDXREG(SISCR
, 0x36, reg
);
5238 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
5239 ivideo
->sishw_ext
.ulCRT2LCDType
= sis300paneltype
[reg
];
5240 } else if(ivideo
->chip
>= SIS_661
) {
5241 ivideo
->sishw_ext
.ulCRT2LCDType
= sis661paneltype
[reg
];
5243 ivideo
->sishw_ext
.ulCRT2LCDType
= sis310paneltype
[reg
];
5244 if((ivideo
->chip
== SIS_550
) && (sisfb_fstn
)) {
5245 if((ivideo
->sishw_ext
.ulCRT2LCDType
!= LCD_640x480_2
) &&
5246 (ivideo
->sishw_ext
.ulCRT2LCDType
!= LCD_640x480_3
)) {
5247 ivideo
->sishw_ext
.ulCRT2LCDType
= LCD_320x480
;
5251 if(ivideo
->sishw_ext
.ulCRT2LCDType
== LCD_UNKNOWN
) {
5252 ivideo
->sishw_ext
.ulCRT2LCDType
= LCD_1024x768
;
5253 printk(KERN_DEBUG
"sisfb: Illegal panel ID (%02x), assuming 1024x768\n", reg
);
5255 for(i
= 0; i
< SIS_LCD_NUMBER
; i
++) {
5256 if(ivideo
->sishw_ext
.ulCRT2LCDType
== sis_lcd_data
[i
].lcdtype
) {
5257 ivideo
->lcdxres
= sis_lcd_data
[i
].xres
;
5258 ivideo
->lcdyres
= sis_lcd_data
[i
].yres
;
5259 ivideo
->lcddefmodeidx
= sis_lcd_data
[i
].default_mode_idx
;
5263 if(ivideo
->SiS_Pr
.SiS_CustomT
== CUT_BARCO1366
) {
5264 ivideo
->lcdxres
= 1360; ivideo
->lcdyres
= 1024; ivideo
->lcddefmodeidx
= 99;
5265 } else if(ivideo
->SiS_Pr
.SiS_CustomT
== CUT_PANEL848
) {
5266 ivideo
->lcdxres
= 848; ivideo
->lcdyres
= 480; ivideo
->lcddefmodeidx
= 47;
5268 printk(KERN_DEBUG
"sisfb: Detected %dx%d flat panel\n",
5269 ivideo
->lcdxres
, ivideo
->lcdyres
);
5272 #ifdef CONFIG_FB_SIS_300
5273 /* Save the current PanelDelayCompensation if the LCD is currently used */
5274 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
5275 if(ivideo
->vbflags
& (VB_LVDS
| VB_30xBDH
)) {
5277 inSISIDXREG(SISCR
,0x30,tmp
);
5279 /* Currently on LCD? If yes, read current pdc */
5280 inSISIDXREG(SISPART1
,0x13,ivideo
->detectedpdc
);
5281 ivideo
->detectedpdc
&= 0x3c;
5282 if(ivideo
->SiS_Pr
.PDC
== -1) {
5283 /* Let option override detection */
5284 ivideo
->SiS_Pr
.PDC
= ivideo
->detectedpdc
;
5286 printk(KERN_INFO
"sisfb: Detected LCD PDC 0x%02x\n",
5287 ivideo
->detectedpdc
);
5289 if((ivideo
->SiS_Pr
.PDC
!= -1) && (ivideo
->SiS_Pr
.PDC
!= ivideo
->detectedpdc
)) {
5290 printk(KERN_INFO
"sisfb: Using LCD PDC 0x%02x\n",
5291 ivideo
->SiS_Pr
.PDC
);
5297 #ifdef CONFIG_FB_SIS_315
5298 if(ivideo
->sisvga_engine
== SIS_315_VGA
) {
5300 /* Try to find about LCDA */
5301 if(ivideo
->vbflags
& (VB_301C
| VB_302B
| VB_301LV
| VB_302LV
| VB_302ELV
)) {
5303 inSISIDXREG(SISPART1
,0x13,tmp
);
5305 ivideo
->SiS_Pr
.SiS_UseLCDA
= TRUE
;
5306 ivideo
->detectedlcda
= 0x03;
5311 if(ivideo
->vbflags
& (VB_301LV
| VB_302LV
| VB_302ELV
)) {
5313 inSISIDXREG(SISCR
,0x30,tmp
);
5314 if((tmp
& 0x20) || (ivideo
->detectedlcda
!= 0xff)) {
5315 /* Currently on LCD? If yes, read current pdc */
5317 inSISIDXREG(SISPART1
,0x2D,pdc
);
5318 ivideo
->detectedpdc
= (pdc
& 0x0f) << 1;
5319 ivideo
->detectedpdca
= (pdc
& 0xf0) >> 3;
5320 inSISIDXREG(SISPART1
,0x35,pdc
);
5321 ivideo
->detectedpdc
|= ((pdc
>> 7) & 0x01);
5322 inSISIDXREG(SISPART1
,0x20,pdc
);
5323 ivideo
->detectedpdca
|= ((pdc
>> 6) & 0x01);
5324 if(ivideo
->newrom
) {
5325 /* New ROM invalidates other PDC resp. */
5326 if(ivideo
->detectedlcda
!= 0xff) {
5327 ivideo
->detectedpdc
= 0xff;
5329 ivideo
->detectedpdca
= 0xff;
5332 if(ivideo
->SiS_Pr
.PDC
== -1) {
5333 if(ivideo
->detectedpdc
!= 0xff) {
5334 ivideo
->SiS_Pr
.PDC
= ivideo
->detectedpdc
;
5337 if(ivideo
->SiS_Pr
.PDCA
== -1) {
5338 if(ivideo
->detectedpdca
!= 0xff) {
5339 ivideo
->SiS_Pr
.PDCA
= ivideo
->detectedpdca
;
5342 if(ivideo
->detectedpdc
!= 0xff) {
5344 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
5345 ivideo
->detectedpdc
);
5347 if(ivideo
->detectedpdca
!= 0xff) {
5349 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
5350 ivideo
->detectedpdca
);
5355 if(ivideo
->vbflags
& (VB_302LV
| VB_302ELV
)) {
5356 inSISIDXREG(SISPART4
,0x30,ivideo
->SiS_Pr
.EMI_30
);
5357 inSISIDXREG(SISPART4
,0x31,ivideo
->SiS_Pr
.EMI_31
);
5358 inSISIDXREG(SISPART4
,0x32,ivideo
->SiS_Pr
.EMI_32
);
5359 inSISIDXREG(SISPART4
,0x33,ivideo
->SiS_Pr
.EMI_33
);
5360 ivideo
->SiS_Pr
.HaveEMI
= TRUE
;
5361 if((tmp
& 0x20) || (ivideo
->detectedlcda
!= 0xff)) {
5362 ivideo
->SiS_Pr
.HaveEMILCD
= TRUE
;
5367 /* Let user override detected PDCs (all bridges) */
5368 if(ivideo
->vbflags
& (VB_301B
| VB_301C
| VB_301LV
| VB_302LV
| VB_302ELV
)) {
5369 if((ivideo
->SiS_Pr
.PDC
!= -1) && (ivideo
->SiS_Pr
.PDC
!= ivideo
->detectedpdc
)) {
5370 printk(KERN_INFO
"sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
5371 ivideo
->SiS_Pr
.PDC
);
5373 if((ivideo
->SiS_Pr
.PDCA
!= -1) && (ivideo
->SiS_Pr
.PDCA
!= ivideo
->detectedpdca
)) {
5374 printk(KERN_INFO
"sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
5375 ivideo
->SiS_Pr
.PDCA
);
5382 if(!ivideo
->sisfb_crt1off
) {
5383 sisfb_handle_ddc(ivideo
, &ivideo
->sisfb_thismonitor
, 0);
5385 if((ivideo
->vbflags
& (VB_301
|VB_301B
|VB_301C
|VB_302B
)) &&
5386 (ivideo
->vbflags
& (CRT2_VGA
| CRT2_LCD
))) {
5387 sisfb_handle_ddc(ivideo
, &ivideo
->sisfb_thismonitor
, 1);
5391 if(ivideo
->sisfb_mode_idx
>= 0) {
5392 int bu
= ivideo
->sisfb_mode_idx
;
5393 ivideo
->sisfb_mode_idx
= sisfb_validate_mode(ivideo
,
5394 ivideo
->sisfb_mode_idx
, ivideo
->currentvbflags
);
5395 if(bu
!= ivideo
->sisfb_mode_idx
) {
5396 printk(KERN_ERR
"Mode %dx%dx%d failed validation\n",
5397 sisbios_mode
[bu
].xres
,
5398 sisbios_mode
[bu
].yres
,
5399 sisbios_mode
[bu
].bpp
);
5403 if(ivideo
->sisfb_mode_idx
< 0) {
5404 switch(ivideo
->currentvbflags
& VB_DISPTYPE_DISP2
) {
5406 ivideo
->sisfb_mode_idx
= ivideo
->lcddefmodeidx
;
5409 ivideo
->sisfb_mode_idx
= ivideo
->tvdefmodeidx
;
5412 ivideo
->sisfb_mode_idx
= ivideo
->defmodeidx
;
5417 ivideo
->mode_no
= sisbios_mode
[ivideo
->sisfb_mode_idx
].mode_no
[ivideo
->mni
];
5419 if(ivideo
->refresh_rate
!= 0) {
5420 sisfb_search_refresh_rate(ivideo
, ivideo
->refresh_rate
, ivideo
->sisfb_mode_idx
);
5423 if(ivideo
->rate_idx
== 0) {
5424 ivideo
->rate_idx
= sisbios_mode
[ivideo
->sisfb_mode_idx
].rate_idx
;
5425 ivideo
->refresh_rate
= 60;
5428 if(ivideo
->sisfb_thismonitor
.datavalid
) {
5429 if(!sisfb_verify_rate(ivideo
, &ivideo
->sisfb_thismonitor
, ivideo
->sisfb_mode_idx
,
5430 ivideo
->rate_idx
, ivideo
->refresh_rate
)) {
5431 printk(KERN_INFO
"sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
5435 ivideo
->video_bpp
= sisbios_mode
[ivideo
->sisfb_mode_idx
].bpp
;
5436 ivideo
->video_width
= sisbios_mode
[ivideo
->sisfb_mode_idx
].xres
;
5437 ivideo
->video_height
= sisbios_mode
[ivideo
->sisfb_mode_idx
].yres
;
5439 sisfb_set_vparms(ivideo
);
5441 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5443 /* ---------------- For 2.4: Now switch the mode ------------------ */
5445 printk(KERN_INFO
"sisfb: Mode is %dx%dx%d (%dHz)\n",
5446 ivideo
->video_width
, ivideo
->video_height
, ivideo
->video_bpp
,
5447 ivideo
->refresh_rate
);
5449 sisfb_pre_setmode(ivideo
);
5451 if(SiSSetMode(&ivideo
->SiS_Pr
, &ivideo
->sishw_ext
, ivideo
->mode_no
) == 0) {
5452 printk(KERN_ERR
"sisfb: Fatal error: Setting mode[0x%x] failed\n",
5454 iounmap(ivideo
->video_vbase
);
5455 iounmap(ivideo
->mmio_vbase
);
5456 release_mem_region(ivideo
->video_base
, ivideo
->video_size
);
5457 release_mem_region(ivideo
->mmio_base
, ivideo
->mmio_size
);
5458 if(ivideo
->bios_abase
) vfree(ivideo
->bios_abase
);
5459 if(ivideo
->bios_vbase
) iounmap(ivideo
->bios_vbase
);
5460 pci_set_drvdata(pdev
, NULL
);
5465 outSISIDXREG(SISSR
, IND_SIS_PASSWORD
, SIS_PASSWORD
);
5467 sisfb_post_setmode(ivideo
);
5469 /* Maximize regardless of sisfb_max at startup */
5470 ivideo
->default_var
.yres_virtual
= 32767;
5472 /* Force reset of x virtual in crtc_to_var */
5473 ivideo
->default_var
.xres_virtual
= 0;
5475 sisfb_crtc_to_var(ivideo
, &ivideo
->default_var
);
5477 sisfb_calc_pitch(ivideo
, &ivideo
->default_var
);
5478 sisfb_set_pitch(ivideo
);
5481 if(ivideo
->sisfb_accel
) {
5483 ivideo
->default_var
.accel_flags
|= FB_ACCELF_TEXT
;
5485 sisfb_initaccel(ivideo
);
5487 sis_fb_info
->node
= -1;
5488 sis_fb_info
->flags
= FBINFO_FLAG_DEFAULT
;
5489 sis_fb_info
->fbops
= &sisfb_ops
;
5490 sis_fb_info
->disp
= &ivideo
->sis_disp
;
5491 sis_fb_info
->blank
= &sisfb_blank
;
5492 sis_fb_info
->switch_con
= &sisfb_switch
;
5493 sis_fb_info
->updatevar
= &sisfb_update_var
;
5494 sis_fb_info
->changevar
= NULL
;
5495 strcpy(sis_fb_info
->fontname
, sisfb_fontname
);
5497 sisfb_set_disp(-1, &ivideo
->default_var
, sis_fb_info
);
5499 #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
5501 printk(KERN_INFO
"sisfb: Default mode is %dx%dx%d (%dHz)\n",
5502 ivideo
->video_width
, ivideo
->video_height
, ivideo
->video_bpp
,
5503 ivideo
->refresh_rate
);
5505 ivideo
->default_var
.xres
= ivideo
->default_var
.xres_virtual
= ivideo
->video_width
;
5506 ivideo
->default_var
.yres
= ivideo
->default_var
.yres_virtual
= ivideo
->video_height
;
5507 ivideo
->default_var
.bits_per_pixel
= ivideo
->video_bpp
;
5509 sisfb_bpp_to_var(ivideo
, &ivideo
->default_var
);
5511 ivideo
->default_var
.pixclock
= (u32
) (1000000000 /
5512 sisfb_mode_rate_to_dclock(&ivideo
->SiS_Pr
, &ivideo
->sishw_ext
,
5513 ivideo
->mode_no
, ivideo
->rate_idx
));
5515 if(sisfb_mode_rate_to_ddata(&ivideo
->SiS_Pr
, &ivideo
->sishw_ext
,
5516 ivideo
->mode_no
, ivideo
->rate_idx
, &ivideo
->default_var
)) {
5517 if((ivideo
->default_var
.vmode
& FB_VMODE_MASK
) == FB_VMODE_DOUBLE
) {
5518 ivideo
->default_var
.pixclock
<<= 1;
5522 if(ivideo
->sisfb_ypan
) {
5523 /* Maximize regardless of sisfb_max at startup */
5524 ivideo
->default_var
.yres_virtual
= sisfb_calc_maxyres(ivideo
, &ivideo
->default_var
);
5525 if(ivideo
->default_var
.yres_virtual
< ivideo
->default_var
.yres
) {
5526 ivideo
->default_var
.yres_virtual
= ivideo
->default_var
.yres
;
5530 sisfb_calc_pitch(ivideo
, &ivideo
->default_var
);
5533 if(ivideo
->sisfb_accel
) {
5535 #ifdef STUPID_ACCELF_TEXT_SHIT
5536 ivideo
->default_var
.accel_flags
|= FB_ACCELF_TEXT
;
5539 sisfb_initaccel(ivideo
);
5541 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
5542 sis_fb_info
->flags
= FBINFO_DEFAULT
|
5543 FBINFO_HWACCEL_YPAN
|
5544 FBINFO_HWACCEL_XPAN
|
5545 FBINFO_HWACCEL_COPYAREA
|
5546 FBINFO_HWACCEL_FILLRECT
|
5547 ((ivideo
->accel
) ? 0 : FBINFO_HWACCEL_DISABLED
);
5549 sis_fb_info
->flags
= FBINFO_FLAG_DEFAULT
;
5551 sis_fb_info
->var
= ivideo
->default_var
;
5552 sis_fb_info
->fix
= ivideo
->sisfb_fix
;
5553 sis_fb_info
->screen_base
= ivideo
->video_vbase
;
5554 sis_fb_info
->fbops
= &sisfb_ops
;
5556 sisfb_get_fix(&sis_fb_info
->fix
, -1, sis_fb_info
);
5557 sis_fb_info
->pseudo_palette
= ivideo
->pseudo_palette
;
5559 fb_alloc_cmap(&sis_fb_info
->cmap
, 256 , 0);
5562 printk(KERN_DEBUG
"sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo
->vbflags
);
5565 ivideo
->mtrr
= mtrr_add(ivideo
->video_base
, ivideo
->video_size
,
5566 MTRR_TYPE_WRCOMB
, 1);
5568 printk(KERN_DEBUG
"sisfb: Failed to add MTRRs\n");
5572 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5573 vc_resize_con(1, 1, 0);
5576 if(register_framebuffer(sis_fb_info
) < 0) {
5577 printk(KERN_ERR
"sisfb: Fatal error: Failed to register framebuffer\n");
5578 iounmap(ivideo
->video_vbase
);
5579 iounmap(ivideo
->mmio_vbase
);
5580 release_mem_region(ivideo
->video_base
, ivideo
->video_size
);
5581 release_mem_region(ivideo
->mmio_base
, ivideo
->mmio_size
);
5582 if(ivideo
->bios_abase
) vfree(ivideo
->bios_abase
);
5583 if(ivideo
->bios_vbase
) iounmap(ivideo
->bios_vbase
);
5584 pci_set_drvdata(pdev
, NULL
);
5589 ivideo
->registered
= 1;
5592 ivideo
->next
= card_list
;
5595 #ifdef SIS_CONFIG_COMPAT
5598 /* Our ioctls are all "32/64bit compatible" */
5599 if(register_ioctl32_conversion(FBIOGET_VBLANK
, NULL
)) {
5600 printk(KERN_ERR
"sisfb: Error registering FBIOGET_VBLANK ioctl32 translation\n");
5602 ivideo
->ioctl32vblankregistered
= 1;
5604 ret
= register_ioctl32_conversion(FBIO_ALLOC
, NULL
);
5605 ret
|= register_ioctl32_conversion(FBIO_FREE
, NULL
);
5606 ret
|= register_ioctl32_conversion(SISFB_GET_INFO_SIZE
, NULL
);
5607 ret
|= register_ioctl32_conversion(SISFB_GET_INFO
, NULL
);
5608 ret
|= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET
, NULL
);
5609 ret
|= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET
, NULL
);
5610 ret
|= register_ioctl32_conversion(SISFB_SET_LOCK
, NULL
);
5611 ret
|= register_ioctl32_conversion(SISFB_GET_VBRSTATUS
, NULL
);
5612 ret
|= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE
, NULL
);
5613 ret
|= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE
, NULL
);
5614 if(ret
) printk(KERN_ERR
"sisfb: Error registering ioctl32 translations\n");
5615 else ivideo
->ioctl32registered
= 1;
5619 printk(KERN_INFO
"sisfb: 2D acceleration is %s, y-panning %s\n",
5620 ivideo
->sisfb_accel
? "enabled" : "disabled",
5621 ivideo
->sisfb_ypan
?
5622 (ivideo
->sisfb_max
? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
5625 printk(KERN_INFO
"fb%d: %s frame buffer device, Version %d.%d.%d\n",
5626 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5627 GET_FB_IDX(sis_fb_info
->node
),
5631 ivideo
->myid
, VER_MAJOR
, VER_MINOR
, VER_LEVEL
);
5633 printk(KERN_INFO
"sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
5635 } /* if mode = "none" */
5640 /*****************************************************/
5641 /* PCI DEVICE HANDLING */
5642 /*****************************************************/
5644 static void __devexit
sisfb_remove(struct pci_dev
*pdev
)
5646 struct sis_video_info
*ivideo
= pci_get_drvdata(pdev
);
5647 struct fb_info
*sis_fb_info
= ivideo
->memyselfandi
;
5648 int registered
= ivideo
->registered
;
5650 #ifdef SIS_CONFIG_COMPAT
5651 if(ivideo
->ioctl32vblankregistered
) {
5652 if(unregister_ioctl32_conversion(FBIOGET_VBLANK
)) {
5653 printk(KERN_ERR
"sisfb: Error unregistering FBIOGET_VBLANK ioctl32 translation\n");
5656 if(ivideo
->ioctl32registered
) {
5658 ret
= unregister_ioctl32_conversion(FBIO_ALLOC
);
5659 ret
|= unregister_ioctl32_conversion(FBIO_FREE
);
5660 ret
|= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE
);
5661 ret
|= unregister_ioctl32_conversion(SISFB_GET_INFO
);
5662 ret
|= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET
);
5663 ret
|= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET
);
5664 ret
|= unregister_ioctl32_conversion(SISFB_SET_LOCK
);
5665 ret
|= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS
);
5666 ret
|= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE
);
5667 ret
|= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE
);
5668 if(ret
) printk(KERN_ERR
"sisfb: Error unregistering ioctl32 translations\n");
5673 iounmap(ivideo
->video_vbase
);
5674 iounmap(ivideo
->mmio_vbase
);
5675 if(ivideo
->bios_vbase
) iounmap(ivideo
->bios_vbase
);
5676 if(ivideo
->bios_abase
) vfree(ivideo
->bios_abase
);
5678 /* Release mem regions */
5679 release_mem_region(ivideo
->video_base
, ivideo
->video_size
);
5680 release_mem_region(ivideo
->mmio_base
, ivideo
->mmio_size
);
5683 /* Release MTRR region */
5685 mtrr_del(ivideo
->mtrr
, ivideo
->video_base
, ivideo
->video_size
);
5689 /* Unregister the framebuffer */
5690 if(ivideo
->registered
) {
5691 unregister_framebuffer(sis_fb_info
);
5692 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5693 framebuffer_release(sis_fb_info
);
5699 pci_set_drvdata(pdev
, NULL
);
5701 /* TODO: Restore the initial mode
5702 * This sounds easy but is as good as impossible
5703 * on many machines with SiS chip and video bridge
5704 * since text modes are always set up differently
5705 * from machine to machine. Depends on the type
5706 * of integration between chipset and bridge.
5709 printk(KERN_INFO
"sisfb: Restoring of text mode not supported yet\n");
5713 static struct pci_driver sisfb_driver
= {
5715 .id_table
= sisfb_pci_table
,
5716 .probe
= sisfb_probe
,
5717 .remove
= __devexit_p(sisfb_remove
)
5720 int __init
sisfb_init(void)
5722 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5724 char *option
= NULL
;
5726 if (fb_get_options("sisfb", &option
))
5728 sisfb_setup(option
);
5731 return(pci_module_init(&sisfb_driver
));
5734 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5736 module_init(sisfb_init
);
5740 /*****************************************************/
5742 /*****************************************************/
5746 static char *mode
= NULL
;
5747 static int vesa
= -1;
5748 static unsigned int rate
= 0;
5749 static unsigned int crt1off
= 1;
5750 static unsigned int mem
= 0;
5751 static char *forcecrt2type
= NULL
;
5752 static int forcecrt1
= -1;
5753 static int pdc
= -1;
5754 static int pdc1
= -1;
5755 static int noaccel
= -1;
5756 static int noypan
= -1;
5757 static int nomax
= -1;
5758 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5759 static int inverse
= 0;
5761 static int userom
= -1;
5762 static int useoem
= -1;
5763 static char *tvstandard
= NULL
;
5764 static int nocrt2rate
= 0;
5765 static int scalelcd
= -1;
5766 static char *specialtiming
= NULL
;
5767 static int lvdshl
= -1;
5768 static int tvxposoffset
= 0, tvyposoffset
= 0;
5769 static int filter
= -1;
5770 #if !defined(__i386__) && !defined(__x86_64__)
5771 static int resetcard
= 0;
5772 static int videoram
= 0;
5775 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
5776 MODULE_LICENSE("GPL");
5777 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
5779 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5780 MODULE_PARM(mem
, "i");
5781 MODULE_PARM(noaccel
, "i");
5782 MODULE_PARM(noypan
, "i");
5783 MODULE_PARM(nomax
, "i");
5784 MODULE_PARM(userom
, "i");
5785 MODULE_PARM(useoem
, "i");
5786 MODULE_PARM(mode
, "s");
5787 MODULE_PARM(vesa
, "i");
5788 MODULE_PARM(rate
, "i");
5789 MODULE_PARM(forcecrt1
, "i");
5790 MODULE_PARM(forcecrt2type
, "s");
5791 MODULE_PARM(scalelcd
, "i");
5792 MODULE_PARM(pdc
, "i");
5793 MODULE_PARM(pdc1
, "i");
5794 MODULE_PARM(specialtiming
, "s");
5795 MODULE_PARM(lvdshl
, "i");
5796 MODULE_PARM(tvstandard
, "s");
5797 MODULE_PARM(tvxposoffset
, "i");
5798 MODULE_PARM(tvyposoffset
, "i");
5799 MODULE_PARM(filter
, "i");
5800 MODULE_PARM(nocrt2rate
, "i");
5801 MODULE_PARM(inverse
, "i");
5802 #if !defined(__i386__) && !defined(__x86_64__)
5803 MODULE_PARM(resetcard
, "i");
5804 MODULE_PARM(videoram
, "i");
5808 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5809 module_param(mem
, int, 0);
5810 module_param(noaccel
, int, 0);
5811 module_param(noypan
, int, 0);
5812 module_param(nomax
, int, 0);
5813 module_param(userom
, int, 0);
5814 module_param(useoem
, int, 0);
5815 module_param(mode
, charp
, 0);
5816 module_param(vesa
, int, 0);
5817 module_param(rate
, int, 0);
5818 module_param(forcecrt1
, int, 0);
5819 module_param(forcecrt2type
, charp
, 0);
5820 module_param(scalelcd
, int, 0);
5821 module_param(pdc
, int, 0);
5822 module_param(pdc1
, int, 0);
5823 module_param(specialtiming
, charp
, 0);
5824 module_param(lvdshl
, int, 0);
5825 module_param(tvstandard
, charp
, 0);
5826 module_param(tvxposoffset
, int, 0);
5827 module_param(tvyposoffset
, int, 0);
5828 module_param(filter
, int, 0);
5829 module_param(nocrt2rate
, int, 0);
5830 #if !defined(__i386__) && !defined(__x86_64__)
5831 module_param(resetcard
, int, 0);
5832 module_param(videoram
, int, 0);
5836 MODULE_PARM_DESC(mem
,
5837 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
5838 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
5839 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
5840 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
5841 "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
5842 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
5843 "for XFree86 4.x/X.org 6.7 and later.\n");
5845 MODULE_PARM_DESC(noaccel
,
5846 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
5849 MODULE_PARM_DESC(noypan
,
5850 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
5851 "will be performed by redrawing the screen. (default: 0)\n");
5853 MODULE_PARM_DESC(nomax
,
5854 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
5855 "memory for the virtual screen in order to optimize scrolling performance. If\n"
5856 "this is set to anything other than 0, sisfb will not do this and thereby \n"
5857 "enable the user to positively specify a virtual Y size of the screen using\n"
5858 "fbset. (default: 0)\n");
5860 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5861 MODULE_PARM_DESC(mode
,
5862 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
5863 "1024x768x16. Other formats supported include XxY-Depth and\n"
5864 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5865 "number, it will be interpreted as a VESA mode number. (default: none if\n"
5866 "sisfb is a module; this leaves the console untouched and the driver will\n"
5867 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
5868 "is in the kernel)\n");
5869 MODULE_PARM_DESC(vesa
,
5870 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
5871 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
5872 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
5873 "0x0103 if sisfb is in the kernel)\n");
5876 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5877 MODULE_PARM_DESC(mode
,
5878 "\nSelects the desired default display mode in the format XxYxDepth,\n"
5879 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
5880 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5881 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
5883 MODULE_PARM_DESC(vesa
,
5884 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
5885 "0x117 (default: 0x0103)\n");
5888 MODULE_PARM_DESC(rate
,
5889 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
5890 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
5891 "will be ignored (default: 60)\n");
5893 MODULE_PARM_DESC(forcecrt1
,
5894 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
5895 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
5896 "0=CRT1 OFF) (default: [autodetected])\n");
5898 MODULE_PARM_DESC(forcecrt2type
,
5899 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
5900 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
5901 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
5902 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
5903 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
5904 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
5905 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
5906 "depends on the very hardware in use. (default: [autodetected])\n");
5908 MODULE_PARM_DESC(scalelcd
,
5909 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
5910 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
5911 "show black bars around the image, TMDS panels will probably do the scaling\n"
5912 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
5914 MODULE_PARM_DESC(pdc
,
5915 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
5916 "should detect this correctly in most cases; however, sometimes this is not\n"
5917 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
5918 "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
5919 "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
5920 "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
5922 #ifdef CONFIG_FB_SIS_315
5923 MODULE_PARM_DESC(pdc1
,
5924 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
5925 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
5926 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
5927 "implemented yet.\n");
5930 MODULE_PARM_DESC(specialtiming
,
5931 "\nPlease refer to documentation for more information on this option.\n");
5933 MODULE_PARM_DESC(lvdshl
,
5934 "\nPlease refer to documentation for more information on this option.\n");
5936 MODULE_PARM_DESC(tvstandard
,
5937 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
5938 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
5940 MODULE_PARM_DESC(tvxposoffset
,
5941 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
5944 MODULE_PARM_DESC(tvyposoffset
,
5945 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
5948 MODULE_PARM_DESC(filter
,
5949 "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
5950 "(Possible values 0-7, default: [no filter])\n");
5952 MODULE_PARM_DESC(nocrt2rate
,
5953 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
5954 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
5956 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5957 MODULE_PARM_DESC(inverse
,
5958 "\nSetting this to anything but 0 should invert the display colors, but this\n"
5959 "does not seem to work. (default: 0)\n");
5962 #if !defined(__i386__) && !defined(__x86_64__)
5963 #ifdef CONFIG_FB_SIS_300
5964 MODULE_PARM_DESC(resetcard
,
5965 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
5966 "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
5969 MODULE_PARM_DESC(videoram
,
5970 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
5971 "some non-x86 architectures where the memory auto detection fails. Only\n"
5972 "relevant if resetcard is set, too. Default: [auto-detect]\n");
5976 int __init
sisfb_init_module(void)
5978 sisfb_setdefaultparms();
5980 if(rate
) sisfb_parm_rate
= rate
;
5982 if((scalelcd
== 0) || (scalelcd
== 1)) {
5983 sisfb_scalelcd
= scalelcd
^ 1;
5986 /* Need to check crt2 type first for fstn/dstn */
5989 sisfb_search_crt2type(forcecrt2type
);
5992 sisfb_search_tvstd(tvstandard
);
5995 sisfb_search_mode(mode
, FALSE
);
5997 sisfb_search_vesamode(vesa
, FALSE
);
5999 sisfb_crt1off
= (crt1off
== 0) ? 1 : 0;
6001 sisfb_forcecrt1
= forcecrt1
;
6002 if(forcecrt1
== 1) sisfb_crt1off
= 0;
6003 else if(forcecrt1
== 0) sisfb_crt1off
= 1;
6005 if(noaccel
== 1) sisfb_accel
= 0;
6006 else if(noaccel
== 0) sisfb_accel
= 1;
6008 if(noypan
== 1) sisfb_ypan
= 0;
6009 else if(noypan
== 0) sisfb_ypan
= 1;
6011 if(nomax
== 1) sisfb_max
= 0;
6012 else if(nomax
== 0) sisfb_max
= 1;
6014 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6015 if(inverse
) sisfb_inverse
= 1;
6018 if(mem
) sisfb_parm_mem
= mem
;
6020 if(userom
!= -1) sisfb_userom
= userom
;
6021 if(useoem
!= -1) sisfb_useoem
= useoem
;
6023 if(pdc
!= -1) sisfb_pdc
= (pdc
& 0x7f);
6024 if(pdc1
!= -1) sisfb_pdca
= (pdc1
& 0x1f);
6026 sisfb_nocrt2rate
= nocrt2rate
;
6029 sisfb_search_specialtiming(specialtiming
);
6031 if((lvdshl
>= 0) && (lvdshl
<= 3)) sisfb_lvdshl
= lvdshl
;
6033 if(filter
!= -1) sisfb_filter
= filter
;
6035 sisfb_tvxposoffset
= tvxposoffset
;
6036 sisfb_tvyposoffset
= tvyposoffset
;
6038 #if !defined(__i386__) && !defined(__x86_64__)
6039 sisfb_resetcard
= (resetcard
) ? 1 : 0;
6040 if(videoram
) sisfb_videoram
= videoram
;
6043 return(sisfb_init());
6046 static void __exit
sisfb_remove_module(void)
6048 pci_unregister_driver(&sisfb_driver
);
6049 printk(KERN_DEBUG
"sisfb: Module unloaded\n");
6052 module_init(sisfb_init_module
);
6053 module_exit(sisfb_remove_module
);
6055 #endif /* /MODULE */
6057 EXPORT_SYMBOL(sis_malloc
);
6058 EXPORT_SYMBOL(sis_free
);