2 * SiS 300/630/540 frame buffer device For Kernal 2.4.x
4 * This driver is partly based on the VBE 2.0 compliant graphic
5 * boards framebuffer driver, which is
7 * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
14 #include <linux/config.h>
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/errno.h>
18 #include <linux/string.h>
20 #include <linux/tty.h>
21 #include <linux/malloc.h>
22 #include <linux/delay.h>
24 #include <linux/console.h>
25 #include <linux/selection.h>
26 #include <linux/ioport.h>
27 #include <linux/init.h>
28 #include <linux/pci.h>
29 #include <linux/vt_kern.h>
30 #include <linux/capability.h>
31 #include <linux/sisfb.h>
37 #include <video/fbcon.h>
38 #include <video/fbcon-cfb8.h>
39 #include <video/fbcon-cfb16.h>
40 #include <video/fbcon-cfb24.h>
41 #include <video/fbcon-cfb32.h>
48 /* ------------------- Constant Definitions ------------------------- */
51 #define TURBO_QUEUE_CAP 0x80
52 #define HW_CURSOR_CAP 0x40
54 /* VGA register Offsets */
55 #define SEQ_ADR (0x14)
56 #define SEQ_DATA (0x15)
57 #define DAC_ADR (0x18)
58 #define DAC_DATA (0x19)
59 #define CRTC_ADR (0x24)
60 #define CRTC_DATA (0x25)
62 #define DAC2_ADR 0x16 - 0x30
63 #define DAC2_DATA 0x17 - 0x30
66 /* SiS indexed register indexes */
67 #define IND_SIS_PASSWORD (0x05)
68 #define IND_SIS_DRAM_SIZE (0x14)
69 #define IND_SIS_MODULE_ENABLE (0x1E)
70 #define IND_SIS_PCI_ADDRESS_SET (0x20)
71 #define IND_SIS_TURBOQUEUE_ADR (0x26)
72 #define IND_SIS_TURBOQUEUE_SET (0x27)
74 /* Sis register value */
75 #define SIS_PASSWORD (0x86)
77 #define SIS_2D_ENABLE (0x40)
79 #define SIS_MEM_MAP_IO_ENABLE (0x01)
80 #define SIS_PCI_ADDR_ENABLE (0x80)
82 //#define MMIO_SIZE 0x10000 /* 64K MMIO capability */
83 #define MAX_ROM_SCAN 0x10000
85 #define RESERVED_MEM_SIZE_4M 0x400000 /* 4M */
86 #define RESERVED_MEM_SIZE_8M 0x800000 /* 8M */
89 #define DEFAULT_MODE 0 /* 640x480x8 */
90 #define DEFAULT_LCDMODE 9 /* 800x600x8 */
91 #define DEFAULT_TVMODE 9 /* 800x600x8 */
94 #define OH_ALLOC_SIZE 4000
95 #define SENTINEL 0x7fffffff
97 #define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */
98 #define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */
100 /* ------------------- Global Variables ----------------------------- */
102 struct video_info ivideo
;
103 HW_DEVICE_EXTENSION HwExt
={0,0,0,0,0,0};
113 /* Supported SiS Chips list */
114 static struct board
{
118 {PCI_VENDOR_ID_SI
, PCI_DEVICE_ID_SI_300
, "SIS 300"},
119 {PCI_VENDOR_ID_SI
, PCI_DEVICE_ID_SI_540_VGA
, "SIS 540"},
120 {PCI_VENDOR_ID_SI
, PCI_DEVICE_ID_SI_630_VGA
, "SIS 630"},
121 {PCI_VENDOR_ID_SI
, PCI_DEVICE_ID_SI_730_VGA
, "SIS 730"},
125 /* card parameters */
126 unsigned long rom_base
;
127 unsigned long rom_vbase
;
130 static int video_type
= FB_TYPE_PACKED_PIXELS
;
131 static int video_linelength
;
132 static int video_cmap_len
;
133 static int sisfb_off
= 0;
134 static int crt1off
= 0;
136 static struct fb_var_screeninfo default_var
= {
146 FB_ACTIVATE_NOW
, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
148 FB_VMODE_NONINTERLACED
,
152 static struct display disp
;
153 static struct fb_info fb_info
;
155 u16 blue
, green
, red
, pad
;
158 #ifdef FBCON_HAS_CFB16
161 #ifdef FBCON_HAS_CFB24
164 #ifdef FBCON_HAS_CFB32
169 static int inverse
= 0;
170 static int currcon
= 0;
172 static struct display_switch sisfb_sw
;
175 static unsigned long MMIO_SIZE
= 0;
178 unsigned char uDispType
= 0;
183 static const struct _sisbios_mode
{
193 {"640x480x8", 0x2E, 640, 480, 8, 1, 80, 30},
194 {"640x480x16", 0x44, 640, 480, 16, 1, 80, 30},
195 {"640x480x32", 0x62, 640, 480, 32, 1, 80, 30},
196 {"720x480x8", 0x31, 720, 480, 8, 1, 90, 30}, /* NTSC TV */
197 {"720x480x16", 0x33, 720, 480, 16, 1, 90, 30},
198 {"720x480x32", 0x35, 720, 480, 32, 1, 90, 30},
199 {"720x576x8", 0x32, 720, 576, 8, 1, 90, 36}, /* PAL TV */
200 {"720x576x16", 0x34, 720, 576, 16, 1, 90, 36},
201 {"720x576x32", 0x36, 720, 576, 32, 1, 90, 36},
202 {"800x600x8", 0x30, 800, 600, 8, 2, 100, 37},
203 {"800x600x16", 0x47, 800, 600, 16, 2, 100, 37},
204 {"800x600x32", 0x63, 800, 600, 32, 2, 100, 37},
205 {"1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48},
206 {"1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48},
207 {"1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48},
208 {"1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64},
209 {"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64},
210 {"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64},
211 {"1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75},
212 {"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75},
213 {"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75},
214 {"1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75},
215 {"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75},
216 {"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75},
217 {"\0", 0x00, 0, 0, 0, 0, 0, 0}
220 static struct _vrate
{
226 {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85},
227 {5, 640, 480, 100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200},
230 {1, 800, 600, 56}, {2, 800, 600, 60}, {3, 800, 600, 72}, {4, 800, 600, 75},
231 {5, 800, 600, 85}, {6, 800, 600, 100}, {7, 800, 600, 120}, {8, 800, 600, 160},
232 {1, 1024, 768, 43}, {2, 1024, 768, 60}, {3, 1024, 768, 70}, {4, 1024, 768, 75},
233 {5, 1024, 768, 85}, {6, 1024, 768, 100}, {7, 1024, 768, 120},
234 {1, 1280, 1024, 43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85},
235 {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75},
247 unsigned long ulOffset
;
248 unsigned long ulSize
;
252 struct OHALLOC
*pohaNext
;
259 struct OH
*pohFreeList
;
260 struct OHALLOC
*pohaChain
;
262 unsigned long ulMaxFreeSize
;
266 unsigned long heap_start
;
267 unsigned long heap_end
;
268 unsigned long heap_size
;
270 unsigned int tqueue_pos
;
271 unsigned long hwcursor_vbase
;
274 /* -------------------- Macro definitions --------------------------- */
277 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
279 #define DPRINTK(fmt, args...)
282 #define vgawb(reg,data) \
283 (outb(data, ivideo.vga_base+reg))
284 #define vgaww(reg,data) \
285 (outw(data, ivideo.vga_base+reg))
286 #define vgawl(reg,data) \
287 (outl(data, ivideo.vga_base+reg))
289 (inb(ivideo.vga_base+reg))
291 /* ---------------------- Routine Prototype ------------------------- */
293 /* Interface used by the world */
294 int sisfb_setup(char *options
);
295 static int sisfb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
296 struct fb_info
*info
);
297 static int sisfb_get_var(struct fb_var_screeninfo
*var
, int con
,
298 struct fb_info
*info
);
299 static int sisfb_set_var(struct fb_var_screeninfo
*var
, int con
,
300 struct fb_info
*info
);
301 static int sisfb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
302 struct fb_info
*info
);
303 static int sisfb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
304 struct fb_info
*info
);
305 static int sisfb_ioctl(struct inode
*inode
, struct file
*file
,
306 unsigned int cmd
, unsigned long arg
, int con
,
307 struct fb_info
*info
);
309 /* Interface to the low level console driver */
310 int sisfb_init(void);
311 static int sisfb_update_var(int con
, struct fb_info
*info
);
312 static int sisfb_switch(int con
, struct fb_info
*info
);
313 static void sisfb_blank(int blank
, struct fb_info
*info
);
315 /* Internal routines */
316 static void crtc_to_var(struct fb_var_screeninfo
*var
);
317 static void sisfb_set_disp(int con
, struct fb_var_screeninfo
*var
);
318 static int sis_getcolreg(unsigned regno
, unsigned *red
, unsigned *green
,
319 unsigned *blue
, unsigned *transp
,
320 struct fb_info
*fb_info
);
321 static int sis_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
322 unsigned blue
, unsigned transp
,
323 struct fb_info
*fb_info
);
324 static void do_install_cmap(int con
, struct fb_info
*info
);
325 static int do_set_var(struct fb_var_screeninfo
*var
, int isactive
,
326 struct fb_info
*info
);
328 /* set-mode routines */
329 void SetReg1(u16 port
, u16 index
, u16 data
);
330 void SetReg3(u16 port
, u16 data
);
331 void SetReg4(u16 port
, unsigned long data
);
332 u8
GetReg1(u16 port
, u16 index
);
333 u8
GetReg2(u16 port
);
334 u32
GetReg3(u16 port
);
335 extern BOOLEAN
SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension
,
337 extern BOOLEAN
SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension
);
338 static void pre_setmode(void);
339 static void post_setmode(void);
340 static void search_mode(const char *name
);
341 static u8
search_refresh_rate(unsigned int rate
);
344 static int sisfb_heap_init(void);
345 static struct OH
*poh_new_node(void);
346 static struct OH
*poh_allocate(unsigned long size
);
347 static struct OH
*poh_free(unsigned long base
);
348 static void delete_node(struct OH
*poh
);
349 static void insert_node(struct OH
*pohList
, struct OH
*poh
);
350 static void free_node(struct OH
*poh
);
352 /* ---------------------- Internal Routines ------------------------- */
354 inline static u32
RD32(unsigned char *base
, s32 off
)
356 return readl(base
+ off
);
359 inline static void WR32(unsigned char *base
, s32 off
, u32 v
)
361 writel(v
, base
+ off
);
364 inline static void WR16(unsigned char *base
, s32 off
, u16 v
)
366 writew(v
, base
+ off
);
369 inline static void WR8(unsigned char *base
, s32 off
, u8 v
)
371 writeb(v
, base
+ off
);
374 inline static u32
regrl(s32 off
)
376 return RD32(ivideo
.mmio_vbase
, off
);
379 inline static void regwl(s32 off
, u32 v
)
381 WR32(ivideo
.mmio_vbase
, off
, v
);
384 inline static void regww(s32 off
, u16 v
)
386 WR16(ivideo
.mmio_vbase
, off
, v
);
389 inline static void regwb(s32 off
, u8 v
)
391 WR8(ivideo
.mmio_vbase
, off
, v
);
395 * Get CRTC registers to set var
397 static void crtc_to_var(struct fb_var_screeninfo
*var
)
399 u16 VRE
, VBE
, VRS
, VBS
, VDE
, VT
;
400 u16 HRE
, HBE
, HRS
, HBS
, HDE
, HT
;
401 u8 uSRdata
, uCRdata
, uCRdata2
, uCRdata3
, uMRdata
;
402 int A
, B
, C
, D
, E
, F
, temp
;
406 uSRdata
= vgarb(SEQ_DATA
);
409 var
->vmode
= FB_VMODE_INTERLACED
;
411 var
->vmode
= FB_VMODE_NONINTERLACED
;
413 switch ((uSRdata
& 0x1c) >> 2) {
415 var
->bits_per_pixel
= 8;
418 var
->bits_per_pixel
= 16;
421 var
->bits_per_pixel
= 32;
425 switch (var
->bits_per_pixel
) {
428 var
->green
.length
= 6;
429 var
->blue
.length
= 6;
430 video_cmap_len
= 256;
432 case 16: /* RGB 565 */
433 var
->red
.offset
= 11;
435 var
->green
.offset
= 5;
436 var
->green
.length
= 6;
437 var
->blue
.offset
= 0;
438 var
->blue
.length
= 5;
439 var
->transp
.offset
= 0;
440 var
->transp
.length
= 0;
444 case 24: /* RGB 888 */
445 var
->red
.offset
= 16;
447 var
->green
.offset
= 8;
448 var
->green
.length
= 8;
449 var
->blue
.offset
= 0;
450 var
->blue
.length
= 8;
451 var
->transp
.offset
= 0;
452 var
->transp
.length
= 0;
456 var
->red
.offset
= 16;
458 var
->green
.offset
= 8;
459 var
->green
.length
= 8;
460 var
->blue
.offset
= 0;
461 var
->blue
.length
= 8;
462 var
->transp
.offset
= 24;
463 var
->transp
.length
= 8;
469 uSRdata
= vgarb(SEQ_DATA
);
471 vgawb(CRTC_ADR
, 0x6);
472 uCRdata
= vgarb(CRTC_DATA
);
473 vgawb(CRTC_ADR
, 0x7);
474 uCRdata2
= vgarb(CRTC_DATA
);
476 (uCRdata
& 0xff) | ((u16
) (uCRdata2
& 0x01) << 8) |
477 ((u16
) (uCRdata2
& 0x20) << 4) | ((u16
) (uSRdata
& 0x01) <<
481 vgawb(CRTC_ADR
, 0x12);
482 uCRdata
= vgarb(CRTC_DATA
);
484 (uCRdata
& 0xff) | ((u16
) (uCRdata2
& 0x02) << 7) |
485 ((u16
) (uCRdata2
& 0x40) << 3) | ((u16
) (uSRdata
& 0x02) << 9);
488 vgawb(CRTC_ADR
, 0x10);
489 uCRdata
= vgarb(CRTC_DATA
);
491 (uCRdata
& 0xff) | ((u16
) (uCRdata2
& 0x04) << 6) |
492 ((u16
) (uCRdata2
& 0x80) << 2) | ((u16
) (uSRdata
& 0x08) << 7);
495 vgawb(CRTC_ADR
, 0x15);
496 uCRdata
= vgarb(CRTC_DATA
);
497 vgawb(CRTC_ADR
, 0x9);
498 uCRdata3
= vgarb(CRTC_DATA
);
500 (uCRdata
& 0xff) | ((u16
) (uCRdata2
& 0x08) << 5) |
501 ((u16
) (uCRdata3
& 0x20) << 4) | ((u16
) (uSRdata
& 0x04) << 8);
503 vgawb(CRTC_ADR
, 0x16);
504 uCRdata
= vgarb(CRTC_DATA
);
505 VBE
= (uCRdata
& 0xff) | ((u16
) (uSRdata
& 0x10) << 4);
506 temp
= VBE
- ((E
- 1) & 511);
507 B
= (temp
> 0) ? temp
: (temp
+ 512);
509 vgawb(CRTC_ADR
, 0x11);
510 uCRdata
= vgarb(CRTC_DATA
);
511 VRE
= (uCRdata
& 0x0f) | ((uSRdata
& 0x20) >> 1);
512 temp
= VRE
- ((E
+ F
- 1) & 31);
513 C
= (temp
> 0) ? temp
: (temp
+ 32);
517 var
->yres
= var
->yres_virtual
= E
;
518 var
->upper_margin
= D
;
519 var
->lower_margin
= F
;
523 uSRdata
= vgarb(SEQ_DATA
);
525 vgawb(CRTC_ADR
, 0x0);
526 uCRdata
= vgarb(CRTC_DATA
);
527 HT
= (uCRdata
& 0xff) | ((u16
) (uSRdata
& 0x03) << 8);
530 vgawb(CRTC_ADR
, 0x1);
531 uCRdata
= vgarb(CRTC_DATA
);
532 HDE
= (uCRdata
& 0xff) | ((u16
) (uSRdata
& 0x0C) << 6);
535 vgawb(CRTC_ADR
, 0x4);
536 uCRdata
= vgarb(CRTC_DATA
);
537 HRS
= (uCRdata
& 0xff) | ((u16
) (uSRdata
& 0xC0) << 2);
540 vgawb(CRTC_ADR
, 0x2);
541 uCRdata
= vgarb(CRTC_DATA
);
542 HBS
= (uCRdata
& 0xff) | ((u16
) (uSRdata
& 0x30) << 4);
545 uSRdata
= vgarb(SEQ_DATA
);
546 vgawb(CRTC_ADR
, 0x3);
547 uCRdata
= vgarb(CRTC_DATA
);
548 vgawb(CRTC_ADR
, 0x5);
549 uCRdata2
= vgarb(CRTC_DATA
);
551 (uCRdata
& 0x1f) | ((u16
) (uCRdata2
& 0x80) >> 2) |
552 ((u16
) (uSRdata
& 0x03) << 6);
553 HRE
= (uCRdata2
& 0x1f) | ((uSRdata
& 0x04) << 3);
555 temp
= HBE
- ((E
- 1) & 255);
556 B
= (temp
> 0) ? temp
: (temp
+ 256);
558 temp
= HRE
- ((E
+ F
+ 3) & 63);
559 C
= (temp
> 0) ? temp
: (temp
+ 64);
563 var
->xres
= var
->xres_virtual
= E
* 8;
564 var
->left_margin
= D
* 8;
565 var
->right_margin
= F
* 8;
566 var
->hsync_len
= C
* 8;
568 var
->activate
= FB_ACTIVATE_NOW
;
572 uMRdata
= vgarb(0x1C);
574 var
->sync
&= ~FB_SYNC_VERT_HIGH_ACT
;
576 var
->sync
|= FB_SYNC_VERT_HIGH_ACT
;
579 var
->sync
&= ~FB_SYNC_HOR_HIGH_ACT
;
581 var
->sync
|= FB_SYNC_HOR_HIGH_ACT
;
587 hrate
= (double) ivideo
.refresh_rate
* (double) VT
/ 2;
589 var
->pixclock
= (u32
) (1E12
/ drate
);
592 static void sisfb_set_disp(int con
, struct fb_var_screeninfo
*var
)
594 struct fb_fix_screeninfo fix
;
595 struct display
*display
;
596 struct display_switch
*sw
;
600 display
= &fb_display
[con
];
602 display
= &disp
; /* used during initialization */
604 sisfb_get_fix(&fix
, con
, 0);
606 display
->screen_base
= ivideo
.video_vbase
;
607 display
->visual
= fix
.visual
;
608 display
->type
= fix
.type
;
609 display
->type_aux
= fix
.type_aux
;
610 display
->ypanstep
= fix
.ypanstep
;
611 display
->ywrapstep
= fix
.ywrapstep
;
612 display
->line_length
= fix
.line_length
;
613 display
->next_line
= fix
.line_length
;
614 /*display->can_soft_blank = 1; */
615 display
->can_soft_blank
= 0;
616 display
->inverse
= inverse
;
620 switch (ivideo
.video_bpp
) {
621 #ifdef FBCON_HAS_CFB8
626 #ifdef FBCON_HAS_CFB16
630 display
->dispsw_data
= fbcon_cmap
.cfb16
;
633 #ifdef FBCON_HAS_CFB24
636 display
->dispsw_data
= fbcon_cmap
.cfb24
;
639 #ifdef FBCON_HAS_CFB32
642 display
->dispsw_data
= fbcon_cmap
.cfb32
;
649 memcpy(&sisfb_sw
, sw
, sizeof(*sw
));
650 display
->dispsw
= &sisfb_sw
;
651 restore_flags(flags
);
653 display
->scrollmode
= SCROLL_YREDRAW
;
654 sisfb_sw
.bmove
= fbcon_redraw_bmove
;
659 * Read a single color register and split it into colors/transparent.
660 * Return != 0 for invalid regno.
662 static int sis_getcolreg(unsigned regno
, unsigned *red
, unsigned *green
, unsigned *blue
,
663 unsigned *transp
, struct fb_info
*fb_info
)
665 if (regno
>= video_cmap_len
)
668 *red
= palette
[regno
].red
;
669 *green
= palette
[regno
].green
;
670 *blue
= palette
[regno
].blue
;
676 * Set a single color register. The values supplied are already
677 * rounded down to the hardware's capabilities (according to the
678 * entries in the var structure). Return != 0 for invalid regno.
680 static int sis_setcolreg(unsigned regno
, unsigned red
, unsigned green
, unsigned blue
,
681 unsigned transp
, struct fb_info
*fb_info
)
684 if (regno
>= video_cmap_len
)
687 palette
[regno
].red
= red
;
688 palette
[regno
].green
= green
;
689 palette
[regno
].blue
= blue
;
691 switch (ivideo
.video_bpp
) {
692 #ifdef FBCON_HAS_CFB8
694 vgawb(DAC_ADR
, regno
);
695 vgawb(DAC_DATA
, red
>> 10);
696 vgawb(DAC_DATA
, green
>> 10);
697 vgawb(DAC_DATA
, blue
>> 10);
698 if(uDispType
& MASK_DISPTYPE_DISP2
)
701 vgawb(DAC2_ADR
, regno
);
702 vgawb(DAC2_DATA
, red
>> 8);
703 vgawb(DAC2_DATA
, green
>> 8);
704 vgawb(DAC2_DATA
, blue
>> 8);
709 #ifdef FBCON_HAS_CFB16
712 fbcon_cmap
.cfb16
[regno
] =
714 ((green
& 0xfc00) >> 5) | ((blue
& 0xf800) >> 11);
717 #ifdef FBCON_HAS_CFB24
722 fbcon_cmap
.cfb24
[regno
] =
723 (red
<< 16) | (green
<< 8) | (blue
);
726 #ifdef FBCON_HAS_CFB32
731 fbcon_cmap
.cfb32
[regno
] =
732 (red
<< 16) | (green
<< 8) | (blue
);
739 static void do_install_cmap(int con
, struct fb_info
*info
)
744 if (fb_display
[con
].cmap
.len
)
745 fb_set_cmap(&fb_display
[con
].cmap
, 1, sis_setcolreg
, info
);
747 fb_set_cmap(fb_default_cmap(video_cmap_len
), 1,
748 sis_setcolreg
, info
);
751 static int do_set_var(struct fb_var_screeninfo
*var
, int isactive
,
752 struct fb_info
*info
)
754 unsigned int htotal
=
755 var
->left_margin
+ var
->xres
+ var
->right_margin
+
757 unsigned int vtotal
=
758 var
->upper_margin
+ var
->yres
+ var
->lower_margin
+
760 double drate
= 0, hrate
= 0;
764 if ((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_NONINTERLACED
)
766 else if ((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_DOUBLE
)
768 else if ((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_INTERLACED
)
772 if (!htotal
|| !vtotal
) {
773 DPRINTK("Invalid 'var' Information!\n");
777 drate
= 1E12
/ var
->pixclock
;
778 hrate
= drate
/ htotal
;
779 ivideo
.refresh_rate
= (unsigned int) (hrate
/ vtotal
* 2 + 0.5);
784 while ((sisbios_mode
[mode_idx
].mode_no
!= 0)
785 && (sisbios_mode
[mode_idx
].xres
<= var
->xres
)) {
786 if ((sisbios_mode
[mode_idx
].xres
== var
->xres
)
787 && (sisbios_mode
[mode_idx
].yres
== var
->yres
)
788 && (sisbios_mode
[mode_idx
].bpp
== var
->bits_per_pixel
)) {
789 mode_no
= sisbios_mode
[mode_idx
].mode_no
;
798 switch(uDispType
& MASK_DISPTYPE_DISP2
)
800 case MASK_DISPTYPE_LCD
:
801 switch(HwExt
.usLCDType
)
834 if(var
->xres
== 720) /* mode only for TV */
837 case MASK_DISPTYPE_TV
:
844 if(ivideo
.TV_type
== TVMODE_NTSC
)
846 if(sisbios_mode
[mode_idx
].yres
!= 480)
849 else if(ivideo
.TV_type
== TVMODE_PAL
)
851 if(sisbios_mode
[mode_idx
].yres
!= 576)
864 printk("sisfb does not support mode %dx%d-%d\n", var
->xres
,
865 var
->yres
, var
->bits_per_pixel
);
870 if (search_refresh_rate(ivideo
.refresh_rate
) == 0) {
871 /* not supported rate */
872 rate_idx
= sisbios_mode
[mode_idx
].rate_idx
;
873 ivideo
.refresh_rate
= 60;
876 if (((var
->activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) && isactive
) {
879 if (SiSSetMode(&HwExt
, mode_no
)) {
880 DPRINTK("sisfb: set mode[0x%x]: failed\n",
887 printk(KERN_DEBUG
"Current Mode: %dx%dx%d-%d \n", sisbios_mode
[mode_idx
].xres
,
888 sisbios_mode
[mode_idx
].yres
, sisbios_mode
[mode_idx
].bpp
, ivideo
.refresh_rate
);
890 ivideo
.video_bpp
= sisbios_mode
[mode_idx
].bpp
;
891 ivideo
.video_vwidth
= ivideo
.video_width
= sisbios_mode
[mode_idx
].xres
;
892 ivideo
.video_vheight
= ivideo
.video_height
= sisbios_mode
[mode_idx
].yres
;
893 ivideo
.org_x
= ivideo
.org_y
= 0;
895 ivideo
.video_width
* (ivideo
.video_bpp
>> 3);
897 DPRINTK("Current Mode: %dx%d-%d line_length=%d\n",
898 ivideo
.video_width
, ivideo
.video_height
,
899 ivideo
.video_bpp
, video_linelength
);
905 /* ---------------------- Draw Funtions ----------------------------- */
907 static void sis_get_glyph(struct GlyInfo
*gly
)
909 struct display
*p
= &fb_display
[currcon
];
913 u8
*gbuf
= gly
->gmask
;
917 gly
->fontheight
= fontheight(p
);
918 gly
->fontwidth
= fontwidth(p
);
919 widthb
= (fontwidth(p
) + 7) / 8;
921 c
= gly
->ch
& p
->charmask
;
922 if (fontwidth(p
) <= 8)
923 cdat
= p
->fontdata
+ c
* fontheight(p
);
925 cdat
= p
->fontdata
+ (c
* fontheight(p
) << 1);
927 size
= fontheight(p
) * widthb
;
928 memcpy(gbuf
, cdat
, size
);
933 /* ---------------------- HEAP Routines ----------------------------- */
936 * Heap Initialization
939 static int sisfb_heap_init(void)
944 if(ivideo
.video_size
> 0x800000)
945 /* video ram is large than 8M */
946 heap_start
= (unsigned long) ivideo
.video_vbase
+ RESERVED_MEM_SIZE_8M
;
948 heap_start
= (unsigned long) ivideo
.video_vbase
+ RESERVED_MEM_SIZE_4M
;
950 heap_end
= (unsigned long) ivideo
.video_vbase
+ ivideo
.video_size
;
951 heap_size
= heap_end
- heap_start
;
954 /* Setting for Turbo Queue */
955 if (heap_size
>= TURBO_QUEUE_AREA_SIZE
) {
958 TURBO_QUEUE_AREA_SIZE
) / (64 * 1024);
959 jTemp
= (u8
) (tqueue_pos
& 0xff);
960 vgawb(SEQ_ADR
, IND_SIS_TURBOQUEUE_SET
);
961 tq_state
= vgarb(SEQ_DATA
);
964 tq_state
|= (u8
) (tqueue_pos
>> 8);
965 vgawb(SEQ_DATA
, tq_state
);
966 vgawb(SEQ_ADR
, IND_SIS_TURBOQUEUE_ADR
);
967 vgawb(SEQ_DATA
, jTemp
);
969 caps
|= TURBO_QUEUE_CAP
;
971 heap_end
-= TURBO_QUEUE_AREA_SIZE
;
972 heap_size
-= TURBO_QUEUE_AREA_SIZE
;
975 /* Setting for HW cursor(4K) */
976 if (heap_size
>= HW_CURSOR_AREA_SIZE
) {
977 heap_end
-= HW_CURSOR_AREA_SIZE
;
978 heap_size
-= HW_CURSOR_AREA_SIZE
;
979 hwcursor_vbase
= heap_end
;
981 caps
|= HW_CURSOR_CAP
;
984 heap
.pohaChain
= NULL
;
985 heap
.pohFreeList
= NULL
;
987 poh
= poh_new_node();
992 /* The first node describles the entire heap size */
993 poh
->pohNext
= &heap
.ohFree
;
994 poh
->pohPrev
= &heap
.ohFree
;
995 poh
->ulSize
= heap_end
- heap_start
+ 1;
996 poh
->ulOffset
= heap_start
- (unsigned long) ivideo
.video_vbase
;
998 DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n",
999 (char *) heap_start
, (char *) heap_end
,
1000 (unsigned int) poh
->ulSize
/ 1024);
1002 DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n",
1003 (unsigned int) poh
->ulOffset
, (unsigned int) poh
->ulSize
/ 1024);
1005 /* The second node in our free list sentinel */
1006 heap
.ohFree
.pohNext
= poh
;
1007 heap
.ohFree
.pohPrev
= poh
;
1008 heap
.ohFree
.ulSize
= 0;
1009 heap
.ulMaxFreeSize
= poh
->ulSize
;
1011 /* Initialize the discardable list */
1012 heap
.ohUsed
.pohNext
= &heap
.ohUsed
;
1013 heap
.ohUsed
.pohPrev
= &heap
.ohUsed
;
1014 heap
.ohUsed
.ulSize
= SENTINEL
;
1020 * Allocates a basic memory unit in which we'll pack our data structures.
1023 static struct OH
*poh_new_node(void)
1027 struct OHALLOC
*poha
;
1030 if (heap
.pohFreeList
== NULL
) {
1031 poha
= kmalloc(OH_ALLOC_SIZE
, GFP_KERNEL
);
1033 poha
->pohaNext
= heap
.pohaChain
;
1034 heap
.pohaChain
= poha
;
1038 sizeof(struct OHALLOC
)) / sizeof(struct OH
) + 1;
1040 poh
= &poha
->aoh
[0];
1041 for (i
= cOhs
- 1; i
!= 0; i
--) {
1042 poh
->pohNext
= poh
+ 1;
1046 poh
->pohNext
= NULL
;
1047 heap
.pohFreeList
= &poha
->aoh
[0];
1050 poh
= heap
.pohFreeList
;
1051 heap
.pohFreeList
= poh
->pohNext
;
1057 * Allocates space, return NULL when failed
1060 static struct OH
*poh_allocate(unsigned long size
)
1066 if (size
> heap
.ulMaxFreeSize
) {
1067 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
1068 (unsigned int) size
/ 1024);
1072 pohThis
= heap
.ohFree
.pohNext
;
1074 while (pohThis
!= &heap
.ohFree
) {
1075 if (size
<= pohThis
->ulSize
) {
1079 pohThis
= pohThis
->pohNext
;
1083 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
1084 (unsigned int) size
/ 1024);
1088 if (size
== pohThis
->ulSize
) {
1090 delete_node(pohThis
);
1092 pohRoot
= poh_new_node();
1094 if (pohRoot
== NULL
) {
1098 pohRoot
->ulOffset
= pohThis
->ulOffset
;
1099 pohRoot
->ulSize
= size
;
1101 pohThis
->ulOffset
+= size
;
1102 pohThis
->ulSize
-= size
;
1105 heap
.ulMaxFreeSize
-= size
;
1107 pohThis
= &heap
.ohUsed
;
1108 insert_node(pohThis
, pohRoot
);
1114 * To remove a node from a list.
1117 static void delete_node(struct OH
*poh
)
1123 pohPrev
= poh
->pohPrev
;
1124 pohNext
= poh
->pohNext
;
1126 pohPrev
->pohNext
= pohNext
;
1127 pohNext
->pohPrev
= pohPrev
;
1133 * To insert a node into a list.
1136 static void insert_node(struct OH
*pohList
, struct OH
*poh
)
1140 pohTemp
= pohList
->pohNext
;
1142 pohList
->pohNext
= poh
;
1143 pohTemp
->pohPrev
= poh
;
1145 poh
->pohPrev
= pohList
;
1146 poh
->pohNext
= pohTemp
;
1150 * Frees an off-screen heap allocation.
1153 static struct OH
*poh_free(unsigned long base
)
1157 struct OH
*pohFreed
;
1160 unsigned long ulUpper
;
1161 unsigned long ulLower
;
1164 pohFreed
= heap
.ohUsed
.pohNext
;
1166 while (pohFreed
!= &heap
.ohUsed
) {
1167 if (pohFreed
->ulOffset
== base
) {
1172 pohFreed
= pohFreed
->pohNext
;
1178 heap
.ulMaxFreeSize
+= pohFreed
->ulSize
;
1180 pohPrev
= pohNext
= NULL
;
1181 ulUpper
= pohFreed
->ulOffset
+ pohFreed
->ulSize
;
1182 ulLower
= pohFreed
->ulOffset
;
1184 pohThis
= heap
.ohFree
.pohNext
;
1186 while (pohThis
!= &heap
.ohFree
) {
1187 if (pohThis
->ulOffset
== ulUpper
) {
1190 else if ((pohThis
->ulOffset
+ pohThis
->ulSize
) ==
1194 pohThis
= pohThis
->pohNext
;
1197 delete_node(pohFreed
);
1199 if (pohPrev
&& pohNext
) {
1200 pohPrev
->ulSize
+= (pohFreed
->ulSize
+ pohNext
->ulSize
);
1201 delete_node(pohNext
);
1202 free_node(pohFreed
);
1208 pohPrev
->ulSize
+= pohFreed
->ulSize
;
1209 free_node(pohFreed
);
1214 pohNext
->ulSize
+= pohFreed
->ulSize
;
1215 pohNext
->ulOffset
= pohFreed
->ulOffset
;
1216 free_node(pohFreed
);
1220 insert_node(&heap
.ohFree
, pohFreed
);
1226 * Frees our basic data structure allocation unit by adding it to a free
1230 static void free_node(struct OH
*poh
)
1236 poh
->pohNext
= heap
.pohFreeList
;
1237 heap
.pohFreeList
= poh
;
1242 void sis_malloc(struct sis_memreq
*req
)
1246 poh
= poh_allocate(req
->size
);
1251 DPRINTK("sisfb: VMEM Allocation Failed\n");
1253 DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n",
1254 (char *) (poh
->ulOffset
+
1255 (unsigned long) ivideo
.video_vbase
));
1257 req
->offset
= poh
->ulOffset
;
1258 req
->size
= poh
->ulSize
;
1263 void sis_free(unsigned long base
)
1267 poh
= poh_free(base
);
1270 DPRINTK("sisfb: poh_free() failed at base 0x%x\n",
1271 (unsigned int) base
);
1275 void sis_dispinfo(struct ap_data
*rec
)
1277 rec
->minfo
.bpp
= ivideo
.video_bpp
;
1278 rec
->minfo
.xres
= ivideo
.video_width
;
1279 rec
->minfo
.yres
= ivideo
.video_height
;
1280 rec
->minfo
.v_xres
= ivideo
.video_vwidth
;
1281 rec
->minfo
.v_yres
= ivideo
.video_vheight
;
1282 rec
->minfo
.org_x
= ivideo
.org_x
;
1283 rec
->minfo
.org_y
= ivideo
.org_y
;
1284 rec
->minfo
.vrate
= ivideo
.refresh_rate
;
1285 rec
->iobase
= ivideo
.vga_base
- 0x30;
1286 rec
->mem_size
= ivideo
.video_size
;
1287 rec
->disp_state
= ivideo
.disp_state
;
1288 switch(HwExt
.jChipID
)
1291 rec
->chip
= SiS_300
;
1294 if((HwExt
.revision_id
& 0xf0) == 0x30)
1295 rec
->chip
= SiS_630S
;
1297 rec
->chip
= SiS_630
;
1300 rec
->chip
= SiS_540
;
1303 rec
->chip
= SiS_730
;
1306 rec
->chip
= SiS_UNKNOWN
;
1312 /* ---------------------- SetMode Routines -------------------------- */
1314 void SetReg1(u16 port
, u16 index
, u16 data
)
1316 outb((u8
) (index
& 0xff), port
);
1318 outb((u8
) (data
& 0xff), port
);
1321 void SetReg3(u16 port
, u16 data
)
1323 outb((u8
) (data
& 0xff), port
);
1326 void SetReg4(u16 port
, unsigned long data
)
1328 outl((u32
) (data
& 0xffffffff), port
);
1331 u8
GetReg1(u16 port
, u16 index
)
1335 outb((u8
) (index
& 0xff), port
);
1341 u8
GetReg2(u16 port
)
1350 u32
GetReg3(u16 port
)
1358 void ClearDAC(u16 port
)
1362 vgawb(DAC_ADR
, 0x00);
1363 for(i
=0; i
<256; i
++)
1368 void ClearBuffer(PHW_DEVICE_EXTENSION pHwExt
)
1370 memset((char *) ivideo
.video_vbase
, 0,
1371 video_linelength
* ivideo
.video_height
);
1374 static void pre_setmode(void)
1376 unsigned char uCR30
=0, uCR31
=0;
1378 switch(uDispType
& MASK_DISPTYPE_DISP2
)
1380 case MASK_DISPTYPE_CRT2
:
1384 case MASK_DISPTYPE_LCD
:
1388 case MASK_DISPTYPE_TV
:
1389 if(ivideo
.TV_type
== TVMODE_HIVISION
)
1391 else if(ivideo
.TV_plug
== TVPLUG_SVIDEO
)
1393 else if(ivideo
.TV_plug
== TVPLUG_COMPOSITE
)
1395 else if(ivideo
.TV_plug
== TVPLUG_SCART
)
1397 uCR31
= 0x40; /* CR31[0] will be set in setmode() */
1404 vgawb(CRTC_ADR
, 0x30);
1405 vgawb(CRTC_DATA
, uCR30
);
1406 vgawb(CRTC_ADR
, 0x31);
1407 vgawb(CRTC_DATA
, uCR31
);
1408 vgawb(CRTC_ADR
, 0x33);
1409 vgawb(CRTC_DATA
, rate_idx
& 0x0f);
1412 static void post_setmode(void)
1416 vgawb(CRTC_ADR
, 0x17);
1417 uTemp
= vgarb(CRTC_DATA
);
1419 if(crt1off
) /* turn off CRT1 */
1421 else /* turn on CRT1 */
1423 vgawb(CRTC_DATA
, uTemp
);
1425 /* disable 24-bit palette RAM and Gamma correction */
1426 vgawb(SEQ_ADR
, 0x07);
1427 uTemp
= vgarb(SEQ_DATA
);
1429 vgawb(SEQ_DATA
, uTemp
);
1432 static void search_mode(const char *name
)
1439 while (sisbios_mode
[i
].mode_no
!= 0) {
1440 if (!strcmp(name
, sisbios_mode
[i
].name
)) {
1448 DPRINTK("Invalid user mode : %s\n", name
);
1451 static u8
search_refresh_rate(unsigned int rate
)
1456 xres
= sisbios_mode
[mode_idx
].xres
;
1457 yres
= sisbios_mode
[mode_idx
].yres
;
1459 while ((vrate
[i
].idx
!= 0) && (vrate
[i
].xres
<= xres
)) {
1460 if ((vrate
[i
].xres
== xres
) && (vrate
[i
].yres
== yres
)
1461 && (vrate
[i
].refresh
== rate
)) {
1462 rate_idx
= vrate
[i
].idx
;
1468 DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate
, xres
,
1474 /* ------------------ Public Routines ------------------------------- */
1477 * Get the Fixed Part of the Display
1480 static int sisfb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
1481 struct fb_info
*info
)
1483 DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con
);
1485 memset(fix
, 0, sizeof(struct fb_fix_screeninfo
));
1486 strcpy(fix
->id
, fb_info
.modename
);
1488 fix
->smem_start
= ivideo
.video_base
;
1489 if(ivideo
.video_size
> 0x800000)
1490 fix
->smem_len
= RESERVED_MEM_SIZE_8M
; /* reserved for Xserver */
1492 fix
->smem_len
= RESERVED_MEM_SIZE_4M
; /* reserved for Xserver */
1494 fix
->type
= video_type
;
1496 if (ivideo
.video_bpp
== 8)
1497 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
1499 fix
->visual
= FB_VISUAL_TRUECOLOR
;
1503 fix
->line_length
= video_linelength
;
1504 fix
->mmio_start
= ivideo
.mmio_base
;
1505 fix
->mmio_len
= MMIO_SIZE
;
1506 fix
->accel
= FB_ACCEL_SIS_GLAMOUR
;
1507 fix
->reserved
[0] = ivideo
.video_size
& 0xFFFF;
1508 fix
->reserved
[1] = (ivideo
.video_size
>> 16) & 0xFFFF;
1509 fix
->reserved
[2] = caps
; /* capabilities */
1515 * Get the User Defined Part of the Display
1518 static int sisfb_get_var(struct fb_var_screeninfo
*var
, int con
,
1519 struct fb_info
*info
)
1521 DPRINTK("sisfb: sisfb_get_var:[%d]\n", con
);
1524 memcpy(var
, &default_var
, sizeof(struct fb_var_screeninfo
));
1526 *var
= fb_display
[con
].var
;
1531 * Set the User Defined Part of the Display
1534 static int sisfb_set_var(struct fb_var_screeninfo
*var
, int con
,
1535 struct fb_info
*info
)
1538 unsigned int cols
, rows
;
1540 fb_display
[con
].var
.activate
= FB_ACTIVATE_NOW
;
1543 if (do_set_var(var
, con
== currcon
, info
)) {
1544 crtc_to_var(var
); /* return current mode to user */
1548 /* get actual setting value */
1551 /* update display of current console */
1552 sisfb_set_disp(con
, var
);
1554 if (info
->changevar
)
1555 (*info
->changevar
) (con
);
1557 if ((err
= fb_alloc_cmap(&fb_display
[con
].cmap
, 0, 0)))
1560 do_install_cmap(con
, info
);
1562 /* inform console to update struct display */
1563 cols
= sisbios_mode
[mode_idx
].cols
;
1564 rows
= sisbios_mode
[mode_idx
].rows
;
1565 vc_resize_con(rows
, cols
, fb_display
[con
].conp
->vc_num
);
1575 static int sisfb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
1576 struct fb_info
*info
)
1578 DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con
);
1581 return fb_get_cmap(cmap
, kspc
, sis_getcolreg
, info
);
1582 else if (fb_display
[con
].cmap
.len
) /* non default colormap? */
1583 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
1585 fb_copy_cmap(fb_default_cmap(video_cmap_len
), cmap
, kspc
? 0 : 2);
1593 static int sisfb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
1594 struct fb_info
*info
)
1598 if (!fb_display
[con
].cmap
.len
) { /* no colormap allocated */
1599 err
= fb_alloc_cmap(&fb_display
[con
].cmap
, video_cmap_len
, 0);
1603 if (con
== currcon
) /* current console */
1604 return fb_set_cmap(cmap
, kspc
, sis_setcolreg
, info
);
1606 fb_copy_cmap(cmap
, &fb_display
[con
].cmap
, kspc
? 0 : 1);
1610 static int sisfb_ioctl(struct inode
*inode
, struct file
*file
,
1611 unsigned int cmd
, unsigned long arg
, int con
,
1612 struct fb_info
*info
)
1616 if(!capable(CAP_SYS_RAWIO
))
1618 sis_malloc((struct sis_memreq
*) arg
);
1621 if(!capable(CAP_SYS_RAWIO
))
1623 sis_free(*(unsigned long *) arg
);
1626 sis_get_glyph((struct GlyInfo
*) arg
);
1628 case FBIOGET_HWCINFO
:
1630 unsigned long *hwc_offset
= (unsigned long *) arg
;
1632 if (caps
& HW_CURSOR_CAP
)
1633 *hwc_offset
= hwcursor_vbase
-
1634 (unsigned long) ivideo
.video_vbase
;
1640 case FBIOPUT_MODEINFO
:
1642 struct mode_info
*x
= (struct mode_info
*)arg
;
1644 /* Set Mode Parameters by XServer */
1645 ivideo
.video_bpp
= x
->bpp
;
1646 ivideo
.video_width
= x
->xres
;
1647 ivideo
.video_height
= x
->yres
;
1648 ivideo
.video_vwidth
= x
->v_xres
;
1649 ivideo
.video_vheight
= x
->v_yres
;
1650 ivideo
.org_x
= x
->org_x
;
1651 ivideo
.org_y
= x
->org_y
;
1652 ivideo
.refresh_rate
= x
->vrate
;
1656 case FBIOGET_DISPINFO
:
1657 sis_dispinfo((struct ap_data
*)arg
);
1665 static int sisfb_mmap(struct fb_info
*info
, struct file
*file
,
1666 struct vm_area_struct
*vma
)
1668 struct fb_var_screeninfo var
;
1669 unsigned long start
;
1673 if (vma
->vm_pgoff
> (~0UL >> PAGE_SHIFT
))
1675 off
= vma
->vm_pgoff
<< PAGE_SHIFT
;
1677 /* frame buffer memory */
1678 start
= (unsigned long) ivideo
.video_base
;
1679 len
= PAGE_ALIGN((start
& ~PAGE_MASK
) + ivideo
.video_size
);
1682 /* memory mapped io */
1684 sisfb_get_var(&var
, currcon
, info
);
1685 if (var
.accel_flags
)
1687 start
= (unsigned long) ivideo
.mmio_base
;
1688 len
= PAGE_ALIGN((start
& ~PAGE_MASK
) + MMIO_SIZE
);
1692 if ((vma
->vm_end
- vma
->vm_start
+ off
) > len
)
1695 vma
->vm_pgoff
= off
>> PAGE_SHIFT
;
1697 #if defined(__i386__)
1698 if (boot_cpu_data
.x86
> 3)
1699 pgprot_val(vma
->vm_page_prot
) |= _PAGE_PCD
;
1701 if (io_remap_page_range(vma
->vm_start
, off
, vma
->vm_end
- vma
->vm_start
,
1707 static struct fb_ops sisfb_ops
= {
1709 fb_get_fix
: sisfb_get_fix
,
1710 fb_get_var
: sisfb_get_var
,
1711 fb_set_var
: sisfb_set_var
,
1712 fb_get_cmap
: sisfb_get_cmap
,
1713 fb_set_cmap
: sisfb_set_cmap
,
1714 fb_ioctl
: sisfb_ioctl
,
1715 fb_mmap
: sisfb_mmap
,
1718 int sisfb_setup(char *options
)
1722 fb_info
.fontname
[0] = '\0';
1723 ivideo
.refresh_rate
= 0;
1725 if (!options
|| !*options
)
1728 for (this_opt
= strtok(options
, ","); this_opt
;
1729 this_opt
= strtok(NULL
, ",")) {
1733 if (!strcmp(this_opt
, "inverse")) {
1736 } else if (!strncmp(this_opt
, "font:", 5)) {
1737 strcpy(fb_info
.fontname
, this_opt
+ 5);
1738 } else if (!strncmp(this_opt
, "mode:", 5)) {
1739 search_mode(this_opt
+ 5);
1740 } else if (!strncmp(this_opt
, "vrate:", 6)) {
1741 ivideo
.refresh_rate
=
1742 simple_strtoul(this_opt
+ 6, NULL
, 0);
1743 } else if (!strncmp(this_opt
, "off", 3)) {
1745 } else if (!strncmp(this_opt
, "crt1off", 7)) {
1748 DPRINTK("invalid parameter %s\n", this_opt
);
1753 static int sisfb_update_var(int con
, struct fb_info
*info
)
1759 * Switch Console (called by fbcon.c)
1762 static int sisfb_switch(int con
, struct fb_info
*info
)
1766 DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon
, con
);
1768 /* update colormap of current console */
1769 if (fb_display
[currcon
].cmap
.len
)
1770 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, sis_getcolreg
, info
);
1772 fb_display
[con
].var
.activate
= FB_ACTIVATE_NOW
;
1774 /* same mode, needn't change mode actually */
1776 if (!memcmp(&fb_display
[con
].var
, &fb_display
[currcon
].var
, sizeof(struct fb_var_screeninfo
)))
1784 do_set_var(&fb_display
[con
].var
, 1, info
);
1786 sisfb_set_disp(con
, &fb_display
[con
].var
);
1788 /* Install new colormap */
1789 do_install_cmap(con
, info
);
1791 cols
= sisbios_mode
[mode_idx
].cols
;
1792 rows
= sisbios_mode
[mode_idx
].rows
;
1793 vc_resize_con(rows
, cols
, fb_display
[con
].conp
->vc_num
);
1795 sisfb_update_var(con
, info
);
1801 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
1803 static void sisfb_blank(int blank
, struct fb_info
*info
)
1807 vgawb(CRTC_ADR
, 0x17);
1808 CRData
= vgarb(CRTC_DATA
);
1810 if (blank
> 0) /* turn off CRT1 */
1812 else /* turn on CRT1 */
1815 vgawb(CRTC_ADR
, 0x17);
1816 vgawb(CRTC_DATA
, CRData
);
1821 u8 uSR38
, uSR39
, uVBChipID
;
1823 vgawb(SEQ_ADR
, 0x38);
1824 uSR38
= vgarb(SEQ_DATA
);
1825 vgawb(SEQ_ADR
, 0x39);
1826 uSR39
= vgarb(SEQ_DATA
);
1827 vgawb(IND_SIS_CRT2_PORT_14
, 0x0);
1828 uVBChipID
= vgarb(IND_SIS_CRT2_PORT_14
+1);
1831 ( (HwExt
.jChipID
== SIS_Glamour
) && (uSR38
& 0x20) ) /* 300 */
1833 ( (HwExt
.jChipID
>= SIS_Trojan
) && (uSR38
& 0x20) && (!(uSR39
& 0x80)) ) /* 630/540 */
1835 ( (HwExt
.jChipID
== SIS_Trojan
) && ((HwExt
.revision_id
& 0xf0) == 0x30) && (uVBChipID
== 1) ) /* 630s */
1837 ( (HwExt
.jChipID
== SIS_730
) && (uVBChipID
== 1) ) /* 730 */
1840 ivideo
.hasVB
= HASVB_301
;
1845 ivideo
.hasVB
= HASVB_NONE
;
1850 void sis_get301info(void)
1853 unsigned long disp_state
=0;
1855 if (HwExt
.jChipID
>= SIS_Trojan
)
1859 vgawb(CRTC_ADR
, 0x37);
1860 uCRData
= vgarb(CRTC_DATA
);
1862 switch((uCRData
>> 1) & 0x07)
1865 ivideo
.hasVB
= HASVB_LVDS
;
1868 ivideo
.hasVB
= HASVB_LVDS_CHRONTEL
;
1871 ivideo
.hasVB
= HASVB_TRUMPION
;
1883 vgawb(CRTC_ADR
, 0x32);
1884 uCRData
= vgarb(CRTC_DATA
);
1888 case MASK_DISPTYPE_CRT2
:
1889 disp_state
= DISPTYPE_CRT2
;
1891 case MASK_DISPTYPE_LCD
:
1892 disp_state
= DISPTYPE_LCD
;
1894 case MASK_DISPTYPE_TV
:
1895 disp_state
= DISPTYPE_TV
;
1899 if(disp_state
& 0x7)
1902 disp_state
|= DISPMODE_SINGLE
;
1904 disp_state
|= (DISPMODE_MIRROR
| DISPTYPE_CRT1
);
1907 disp_state
= DISPMODE_SINGLE
| DISPTYPE_CRT1
;
1909 ivideo
.disp_state
= disp_state
;
1913 int __init
sisfb_init(void)
1915 struct pci_dev
*pdev
= NULL
;
1918 unsigned char jTemp
;
1919 u8 uSRData
, uCRData
;
1926 pci_for_each_dev(pdev
) {
1927 for (b
= dev_list
; b
->vendor
; b
++)
1929 if ((b
->vendor
== pdev
->vendor
)
1930 && (b
->device
== pdev
->device
))
1933 strcpy(fb_info
.modename
, b
->name
);
1934 ivideo
.chip_id
= pdev
->device
;
1935 pci_read_config_byte(pdev
, PCI_REVISION_ID
, &HwExt
.revision_id
);
1947 switch(ivideo
.chip_id
)
1949 case PCI_DEVICE_ID_SI_300
:
1950 HwExt
.jChipID
= SIS_Glamour
;
1952 case PCI_DEVICE_ID_SI_630_VGA
:
1953 HwExt
.jChipID
= SIS_Trojan
;
1955 case PCI_DEVICE_ID_SI_540_VGA
:
1956 HwExt
.jChipID
= SIS_Spartan
;
1958 case PCI_DEVICE_ID_SI_730_VGA
:
1959 HwExt
.jChipID
= SIS_730
;
1963 ivideo
.video_base
= pci_resource_start(pdev
, 0);
1964 ivideo
.mmio_base
= pci_resource_start(pdev
, 1);
1965 ivideo
.vga_base
= pci_resource_start(pdev
, 2) + 0x30;
1967 HwExt
.IOAddress
= (unsigned short)ivideo
.vga_base
;
1968 rom_base
= 0x000C0000;
1970 MMIO_SIZE
= pci_resource_len(pdev
, 1);
1973 if (pci_enable_device(pdev
))
1975 /* Image file instead of VGA-bios */
1976 HwExt
.VirtualRomBase
= rom_vbase
= (unsigned long) RomData
;
1978 #ifdef CONFIG_FB_SIS_LINUXBIOS
1979 if (pci_enable_device(pdev
))
1981 HwExt
.VirtualRomBase
= rom_vbase
= 0;
1983 request_region(rom_base
, 32, "sisfb");
1984 HwExt
.VirtualRomBase
= rom_vbase
1985 = (unsigned long) ioremap(rom_base
, MAX_ROM_SCAN
);
1989 vgawb(SEQ_ADR
, IND_SIS_PASSWORD
);
1990 vgawb(SEQ_DATA
, SIS_PASSWORD
);
1992 /* Enable MMIO & PCI linear address */
1993 vgawb(SEQ_ADR
, IND_SIS_PCI_ADDRESS_SET
);
1994 jTemp
= vgarb(SEQ_DATA
);
1995 jTemp
|= SIS_PCI_ADDR_ENABLE
;
1996 jTemp
|= SIS_MEM_MAP_IO_ENABLE
;
1997 vgawb(SEQ_DATA
, jTemp
);
1999 #ifdef CONFIG_FB_SIS_LINUXBIOS
2001 pci_for_each_dev(pdev
) {
2004 if ((pdev
->vendor
== PCI_VENDOR_ID_SI
) && (pdev
->device
==0x630))
2006 pci_read_config_byte(pdev
, 0x63, &uPCIData
);
2007 uPCIData
= (uPCIData
& 0x70) >> 4;
2008 ivideo
.video_size
= (unsigned int)(1 << (uPCIData
+21));
2017 vgawb(SEQ_ADR
, IND_SIS_DRAM_SIZE
);
2018 ivideo
.video_size
= ((unsigned int) ((vgarb(SEQ_DATA
) & 0x3f) + 1) << 20);
2022 /* get CRT2 connection state */
2023 vgawb(SEQ_ADR
, 0x17);
2024 uSRData
= vgarb(SEQ_DATA
);
2025 vgawb(CRTC_ADR
, 0x32);
2026 uCRData
= vgarb(CRTC_DATA
);
2028 ivideo
.TV_plug
= ivideo
.TV_type
= 0;
2029 if((uSRData
&0x0F) && (HwExt
.jChipID
>=SIS_Trojan
))
2031 /* CRT1 connect detection */
2032 if((uSRData
& 0x01) && !crt1off
)
2036 if(uSRData
&0x0E) /* DISP2 connected */
2042 /* detection priority : CRT2 > LCD > TV */
2044 uDispType
= MASK_DISPTYPE_CRT2
;
2045 else if(uSRData
& 0x02)
2046 uDispType
= MASK_DISPTYPE_LCD
;
2047 else if(uSRData
& 0x04)
2051 ivideo
.TV_type
= TVMODE_HIVISION
;
2052 ivideo
.TV_plug
= TVPLUG_SVIDEO
;
2054 else if(uSRData
& 0x20)
2055 ivideo
.TV_plug
= TVPLUG_SVIDEO
;
2056 else if(uSRData
& 0x10)
2057 ivideo
.TV_plug
= TVPLUG_COMPOSITE
;
2058 else if(uSRData
& 0x40)
2059 ivideo
.TV_plug
= TVPLUG_SCART
;
2061 if(ivideo
.TV_type
== 0)
2064 vgawb(SEQ_ADR
, 0x16);
2065 uSR16
= vgarb(SEQ_DATA
);
2067 ivideo
.TV_type
= TVMODE_PAL
;
2069 ivideo
.TV_type
= TVMODE_NTSC
;
2072 uDispType
= MASK_DISPTYPE_TV
;
2077 if((uCRData
& 0x20) && !crt1off
)
2081 if(uCRData
&0x5F) /* DISP2 connected */
2088 uDispType
= MASK_DISPTYPE_CRT2
;
2089 else if(uCRData
& 0x08)
2090 uDispType
= MASK_DISPTYPE_LCD
;
2091 else if(uCRData
& 0x47)
2093 uDispType
= MASK_DISPTYPE_TV
;
2097 ivideo
.TV_type
= TVMODE_HIVISION
;
2098 ivideo
.TV_plug
= TVPLUG_SVIDEO
;
2100 else if(uCRData
& 0x02)
2101 ivideo
.TV_plug
= TVPLUG_SVIDEO
;
2102 else if(uCRData
& 0x01)
2103 ivideo
.TV_plug
= TVPLUG_COMPOSITE
;
2104 else if(uCRData
& 0x04)
2105 ivideo
.TV_plug
= TVPLUG_SCART
;
2107 if(ivideo
.TV_type
== 0)
2110 uTemp
= *((u8
*)(HwExt
.VirtualRomBase
+0x52));
2113 uTemp
=*((u8
*)(HwExt
.VirtualRomBase
+0x53));
2117 vgawb(SEQ_ADR
, 0x38);
2118 uTemp
= vgarb(SEQ_DATA
);
2121 ivideo
.TV_type
= TVMODE_PAL
;
2123 ivideo
.TV_type
= TVMODE_NTSC
;
2128 if(uDispType
== MASK_DISPTYPE_LCD
) // LCD conntected
2130 // TODO: set LCDType by EDID
2131 HwExt
.usLCDType
= LCD1024
;
2134 if (HwExt
.jChipID
>= SIS_Trojan
)
2136 vgawb(SEQ_ADR
, 0x1A);
2137 uSRData
= vgarb(SEQ_DATA
);
2139 HwExt
.bIntegratedMMEnabled
= TRUE
;
2141 HwExt
.bIntegratedMMEnabled
= FALSE
;
2144 if(mode_idx
>= 0) /* mode found */
2146 /* Filtering mode for VB */
2147 switch(uDispType
& MASK_DISPTYPE_DISP2
)
2149 case MASK_DISPTYPE_LCD
:
2150 switch(HwExt
.usLCDType
)
2153 if(sisbios_mode
[mode_idx
].xres
> 1024)
2157 if(sisbios_mode
[mode_idx
].xres
> 1280)
2161 if(sisbios_mode
[mode_idx
].xres
> 2048)
2165 if(sisbios_mode
[mode_idx
].xres
> 1920)
2169 if(sisbios_mode
[mode_idx
].xres
> 1600)
2173 if(sisbios_mode
[mode_idx
].xres
> 800)
2177 if(sisbios_mode
[mode_idx
].xres
> 640)
2184 if(sisbios_mode
[mode_idx
].xres
== 720) /* only for TV */
2187 case MASK_DISPTYPE_TV
:
2188 switch(sisbios_mode
[mode_idx
].xres
)
2194 if(ivideo
.TV_type
== TVMODE_NTSC
)
2196 if(sisbios_mode
[mode_idx
].yres
!= 480)
2199 else if(ivideo
.TV_type
== TVMODE_PAL
)
2201 if(sisbios_mode
[mode_idx
].yres
!= 576)
2215 switch(uDispType
& MASK_DISPTYPE_DISP2
)
2217 case MASK_DISPTYPE_LCD
:
2218 mode_idx
= DEFAULT_LCDMODE
;
2220 case MASK_DISPTYPE_TV
:
2221 mode_idx
= DEFAULT_TVMODE
;
2224 mode_idx
= DEFAULT_MODE
;
2228 #ifdef CONFIG_FB_SIS_LINUXBIOS
2229 mode_idx
= DEFAULT_MODE
;
2230 rate_idx
= sisbios_mode
[mode_idx
].rate_idx
;
2231 /* set to default refresh rate 60MHz */
2232 ivideo
.refresh_rate
= 60;
2235 mode_no
= sisbios_mode
[mode_idx
].mode_no
;
2237 if (ivideo
.refresh_rate
!= 0)
2238 search_refresh_rate(ivideo
.refresh_rate
);
2240 if (rate_idx
== 0) {
2241 rate_idx
= sisbios_mode
[mode_idx
].rate_idx
;
2242 /* set to default refresh rate 60MHz */
2243 ivideo
.refresh_rate
= 60;
2246 ivideo
.video_bpp
= sisbios_mode
[mode_idx
].bpp
;
2247 ivideo
.video_vwidth
= ivideo
.video_width
= sisbios_mode
[mode_idx
].xres
;
2248 ivideo
.video_vheight
= ivideo
.video_height
= sisbios_mode
[mode_idx
].yres
;
2249 ivideo
.org_x
= ivideo
.org_y
= 0;
2250 video_linelength
= ivideo
.video_width
* (ivideo
.video_bpp
>> 3);
2252 printk(KERN_DEBUG
"FB base: 0x%lx, size: 0x%dK\n",
2253 ivideo
.video_base
, (unsigned int)ivideo
.video_size
/1024);
2254 printk(KERN_DEBUG
"MMIO base: 0x%lx, size: 0x%dK\n",
2255 ivideo
.mmio_base
, (unsigned int)MMIO_SIZE
/1024);
2258 if (!request_mem_region(ivideo
.video_base
, ivideo
.video_size
, "sisfb FB"))
2260 printk(KERN_ERR
"sisfb: cannot reserve frame buffer memory\n");
2264 if (!request_mem_region(ivideo
.mmio_base
, MMIO_SIZE
, "sisfb MMIO"))
2266 printk(KERN_ERR
"sisfb: cannot reserve MMIO region\n");
2267 release_mem_region(ivideo
.video_base
, ivideo
.video_size
);
2271 HwExt
.VirtualVideoMemoryAddress
= ivideo
.video_vbase
2272 = ioremap(ivideo
.video_base
, ivideo
.video_size
);
2273 ivideo
.mmio_vbase
= ioremap(ivideo
.mmio_base
, MMIO_SIZE
);
2278 #ifdef CONFIG_FB_SIS_LINUXBIOS
2283 "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
2284 ivideo
.video_base
, ivideo
.video_vbase
,
2285 ivideo
.video_size
/ 1024);
2286 printk(KERN_INFO
"sisfb: mode is %dx%dx%d, linelength=%d\n",
2287 ivideo
.video_width
, ivideo
.video_height
, ivideo
.video_bpp
,
2290 /* enable 2D engine */
2291 vgawb(SEQ_ADR
, IND_SIS_MODULE_ENABLE
);
2292 jTemp
= vgarb(SEQ_DATA
);
2293 jTemp
|= SIS_2D_ENABLE
;
2294 vgawb(SEQ_DATA
, jTemp
);
2298 if (SiSSetMode(&HwExt
, mode_no
)) {
2299 DPRINTK("sisfb: set mode[0x%x]: failed\n", mode_no
);
2305 /* Get VB functions */
2308 crtc_to_var(&default_var
);
2310 fb_info
.changevar
= NULL
;
2312 fb_info
.fbops
= &sisfb_ops
;
2313 fb_info
.disp
= &disp
;
2314 fb_info
.switch_con
= &sisfb_switch
;
2315 fb_info
.updatevar
= &sisfb_update_var
;
2316 fb_info
.blank
= &sisfb_blank
;
2317 fb_info
.flags
= FBINFO_FLAG_DEFAULT
;
2319 sisfb_set_disp(-1, &default_var
);
2321 if (sisfb_heap_init()) {
2322 DPRINTK("sisfb: Failed to enable offscreen heap\n");
2325 /* to avoid the inversed bgcolor bug of the initial state */
2326 vc_resize_con(1, 1, 0);
2328 if (register_framebuffer(&fb_info
) < 0)
2331 printk(KERN_INFO
"fb%d: %s frame buffer device\n",
2332 GET_FB_IDX(fb_info
.node
), fb_info
.modename
);
2339 static char *mode
= NULL
;
2340 static unsigned int rate
= 0;
2341 static unsigned int crt1
= 1;
2343 MODULE_PARM(mode
, "s");
2344 MODULE_PARM(rate
, "i");
2345 MODULE_PARM(crt1
, "i"); /* default: CRT1 enable */
2347 int init_module(void)
2352 ivideo
.refresh_rate
= rate
;
2364 void cleanup_module(void)
2366 unregister_framebuffer(&fb_info
);
2371 EXPORT_SYMBOL(sis_malloc
);
2372 EXPORT_SYMBOL(sis_free
);
2374 EXPORT_SYMBOL(ivideo
);