2 * SiS 300/630/540 frame buffer device For Kernal 2.3.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/module.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
19 #include <linux/tty.h>
20 #include <linux/malloc.h>
21 #include <linux/delay.h>
23 #include <linux/console.h>
24 #include <linux/selection.h>
25 #include <linux/ioport.h>
26 #include <linux/init.h>
27 #include <linux/pci.h>
28 #include <linux/vt_kern.h>
29 #include <linux/capability.h>
30 #include <linux/sisfb.h>
35 #include <video/fbcon.h>
36 #include <video/fbcon-cfb8.h>
37 #include <video/fbcon-cfb16.h>
38 #include <video/fbcon-cfb24.h>
39 #include <video/fbcon-cfb32.h>
41 /* ------------------- Constant Definitions ------------------------- */
47 #define FBIOGET_GLYPH 0x4620
48 #define FBIOGET_HWCINFO 0x4621
50 #define BR(x) (0x8200 | (x) << 2)
52 #define BITBLT 0x00000000
53 #define COLOREXP 0x00000001
54 #define ENCOLOREXP 0x00000002
55 #define MULTIPLE_SCANLINE 0x00000003
56 #define LINE 0x00000004
57 #define TRAPAZOID_FILL 0x00000005
58 #define TRANSPARENT_BITBLT 0x00000006
60 #define SRCVIDEO 0x00000000
61 #define SRCSYSTEM 0x00000010
62 #define SRCAGP 0x00000020
64 #define PATFG 0x00000000
65 #define PATPATREG 0x00000040
66 #define PATMONO 0x00000080
68 #define X_INC 0x00010000
69 #define X_DEC 0x00000000
70 #define Y_INC 0x00020000
71 #define Y_DEC 0x00000000
73 #define NOCLIP 0x00000000
74 #define NOMERGECLIP 0x04000000
75 #define CLIPENABLE 0x00040000
76 #define CLIPWITHOUTMERGE 0x04040000
78 #define OPAQUE 0x00000000
79 #define TRANSPARENT 0x00100000
81 #define DSTAGP 0x02000000
82 #define DSTVIDEO 0x02000000
84 #define LINE_STYLE 0x00800000
85 #define NO_RESET_COUNTER 0x00400000
86 #define NO_LAST_PIXEL 0x00200000
89 #define TURBO_QUEUE_CAP 0x80
90 #define HW_CURSOR_CAP 0x40
92 /* VGA register Offsets */
93 #define SEQ_ADR (0x14)
94 #define SEQ_DATA (0x15)
95 #define DAC_ADR (0x18)
96 #define DAC_DATA (0x19)
97 #define CRTC_ADR (0x24)
98 #define CRTC_DATA (0x25)
100 /* SiS indexed register indexes */
101 #define IND_SIS_PASSWORD (0x05)
102 #define IND_SIS_DRAM_SIZE (0x14)
103 #define IND_SIS_MODULE_ENABLE (0x1E)
104 #define IND_SIS_PCI_ADDRESS_SET (0x20)
105 #define IND_SIS_TURBOQUEUE_ADR (0x26)
106 #define IND_SIS_TURBOQUEUE_SET (0x27)
108 /* Sis register value */
109 #define SIS_PASSWORD (0x86)
111 #define SIS_2D_ENABLE (0x40)
113 #define SIS_MEM_MAP_IO_ENABLE (0x01)
114 #define SIS_PCI_ADDR_ENABLE (0x80)
116 #define MMIO_SIZE 0x20000 /* 128K MMIO capability */
117 #define MAX_ROM_SCAN 0x10000
119 #define RESERVED_MEM_SIZE_4M 0x400000 /* 4M */
120 #define RESERVED_MEM_SIZE_8M 0x800000 /* 8M */
123 #define DEFAULT_MODE 0
125 #define ModeInfoFlag 0x07
126 #define MemoryInfoFlag 0x1E0
127 #define MemorySizeShift 0x05
131 #define DoubleScanMode 0x8000
132 #define HalfDCLK 0x1000
134 #define InterlaceMode 0x80
135 #define LineCompareOff 0x400
136 #define DACInfoFlag 0x18
138 #define VCLKStartFreq 25
140 #define SIS_Glamour 0x0300
141 #define SIS_Trojan 0x6300
142 #define SIS_Spartan 0x5300
145 #define OH_ALLOC_SIZE 4000
146 #define SENTINEL 0x7fffffff
148 #define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */
149 #define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */
151 /* video connection status */
152 #define VB_COMPOSITE 0x01
153 #define VB_SVIDEO 0x02
154 #define VB_SCART 0x04
160 /* ------------------- Global Variables ----------------------------- */
162 struct video_info ivideo
;
172 /* Supported SiS Chips list */
173 static struct board
{
178 PCI_VENDOR_ID_SI
, PCI_DEVICE_ID_SI_300
, "SIS 300"}, {
179 PCI_VENDOR_ID_SI
, PCI_DEVICE_ID_SI_540
, "SIS 540"}, {
180 PCI_VENDOR_ID_SI
, PCI_DEVICE_ID_SI_630
, "SIS 630"}, {
184 /* card parameters */
185 unsigned long rom_base
;
186 unsigned long rom_vbase
;
189 int video_type
= FB_TYPE_PACKED_PIXELS
;
190 int video_linelength
;
194 static struct fb_var_screeninfo default_var
= {
195 0, 0, 0, 0, 0, 0, 0, 0,
196 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
197 0, FB_ACTIVATE_NOW
, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
199 FB_VMODE_NONINTERLACED
,
203 static struct display disp
;
204 static struct fb_info fb_info
;
206 u16 blue
, green
, red
, pad
;
209 #ifdef FBCON_HAS_CFB16
212 #ifdef FBCON_HAS_CFB24
215 #ifdef FBCON_HAS_CFB32
220 static int inverse
= 0;
221 static int currcon
= 0;
223 static struct display_switch sisfb_sw
;
229 u16 P3c4
, P3d4
, P3c0
, P3ce
, P3c2
, P3ca
, P3c6
, P3c7
, P3c8
, P3c9
, P3da
;
231 u16 flag_clearbuffer
;
233 int ModeIDOffset
, StandTable
, CRT1Table
, ScreenOffset
, MCLKData
, ECLKData
;
234 int REFIndex
, ModeType
;
242 static const struct _sisbios_mode
{
253 "640x480x8", 0x2E, 640, 480, 8, 1, 80, 30}, {
254 "640x480x16", 0x44, 640, 480, 16, 1, 80, 30}, {
255 "640x480x32", 0x62, 640, 480, 32, 1, 80, 30}, {
256 "800x600x8", 0x30, 800, 600, 8, 2, 100, 37}, {
257 "800x600x16", 0x47, 800, 600, 16, 2, 100, 37}, {
258 "800x600x32", 0x63, 800, 600, 32, 2, 100, 37}, {
259 "1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48}, {
260 "1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48}, {
261 "1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48}, {
262 "1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64}, {
263 "1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64}, {
264 "1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64}, {
265 "1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75}, {
266 "1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75}, {
267 "1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75}, {
268 "1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75}, {
269 "1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75}, {
270 "1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75}, {
271 "\0", 0x00, 0, 0, 0, 0, 0, 0}
274 static struct _vrate
{
302 6, 1024, 768, 100}, {
303 7, 1024, 768, 120}, {
304 1, 1280, 1024, 43}, {
305 2, 1280, 1024, 60}, {
306 3, 1280, 1024, 75}, {
307 4, 1280, 1024, 85}, {
308 1, 1600, 1200, 60}, {
309 2, 1600, 1200, 65}, {
310 3, 1600, 1200, 70}, {
311 4, 1600, 1200, 75}, {
312 5, 1600, 1200, 85}, {
313 1, 1920, 1440, 60}, {
318 u16 DRAMType
[17][5] =
319 { {0x0C, 0x0A, 0x02, 0x40, 0x39}, {0x0D, 0x0A, 0x01, 0x40, 0x48},
320 {0x0C, 0x09, 0x02, 0x20, 0x35}, {0x0D, 0x09, 0x01, 0x20, 0x44},
321 {0x0C, 0x08, 0x02, 0x10, 0x31}, {0x0D, 0x08, 0x01, 0x10, 0x40},
322 {0x0C, 0x0A, 0x01, 0x20, 0x34}, {0x0C, 0x09, 0x01, 0x08, 0x32},
323 {0x0B, 0x08, 0x02, 0x08, 0x21}, {0x0C, 0x08, 0x01, 0x08, 0x30},
324 {0x0A, 0x08, 0x02, 0x04, 0x11}, {0x0B, 0x0A, 0x01, 0x10, 0x28},
325 {0x09, 0x08, 0x02, 0x02, 0x01}, {0x0B, 0x09, 0x01, 0x08, 0x24},
326 {0x0B, 0x08, 0x01, 0x04, 0x20}, {0x0A, 0x08, 0x01, 0x02, 0x10},
327 {0x09, 0x08, 0x01, 0x01, 0x00}
330 u16 MDA_DAC
[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
332 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
333 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
336 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
337 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
340 u16 CGA_DAC
[] = { 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
341 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
342 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
343 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
344 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
345 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
346 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
347 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
350 u16 EGA_DAC
[] = { 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
351 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
352 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
353 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
354 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
355 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
356 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
357 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
360 u16 VGA_DAC
[] = { 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
361 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
362 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
363 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
364 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
365 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
366 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
367 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
368 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
369 0x0B, 0x0C, 0x0D, 0x0F, 0x10
377 unsigned long ulOffset
;
378 unsigned long ulSize
;
382 struct OHALLOC
*pohaNext
;
389 struct OH
*pohFreeList
;
390 struct OHALLOC
*pohaChain
;
392 unsigned long ulMaxFreeSize
;
396 unsigned long heap_start
;
397 unsigned long heap_end
;
398 unsigned long heap_size
;
400 unsigned int tqueue_pos
;
401 unsigned long hwcursor_vbase
;
403 /* Draw Function stuff */
406 /* -------------------- Macro definitions --------------------------- */
409 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
411 #define DPRINTK(fmt, args...)
414 #define vgawb(reg,data) \
415 (outb(data, ivideo.vga_base+reg))
416 #define vgaww(reg,data) \
417 (outw(data, ivideo.vga_base+reg))
418 #define vgawl(reg,data) \
419 (outl(data, ivideo.vga_base+reg))
421 (inb(ivideo.vga_base+reg))
423 /* ---------------------- Routine Prototype ------------------------- */
425 /* Interface used by the world */
426 int sisfb_setup(char *options
);
427 static int sisfb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
428 struct fb_info
*info
);
429 static int sisfb_get_var(struct fb_var_screeninfo
*var
, int con
,
430 struct fb_info
*info
);
431 static int sisfb_set_var(struct fb_var_screeninfo
*var
, int con
,
432 struct fb_info
*info
);
433 static int sisfb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
434 struct fb_info
*info
);
435 static int sisfb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
436 struct fb_info
*info
);
437 static int sisfb_pan_display(struct fb_var_screeninfo
*var
, int con
,
438 struct fb_info
*info
);
439 static int sisfb_ioctl(struct inode
*inode
, struct file
*file
,
440 unsigned int cmd
, unsigned long arg
, int con
,
441 struct fb_info
*info
);
443 /* Interface to the low level console driver */
444 int sisfb_init(void);
445 static int sisfb_update_var(int con
, struct fb_info
*info
);
446 static int sisfb_switch(int con
, struct fb_info
*info
);
447 static void sisfb_blank(int blank
, struct fb_info
*info
);
449 /* Internal routines */
450 static void crtc_to_var(struct fb_var_screeninfo
*var
);
451 static void sisfb_set_disp(int con
, struct fb_var_screeninfo
*var
);
452 static int sis_getcolreg(unsigned regno
, unsigned *red
, unsigned *green
,
453 unsigned *blue
, unsigned *transp
,
454 struct fb_info
*fb_info
);
455 static int sis_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
456 unsigned blue
, unsigned transp
,
457 struct fb_info
*fb_info
);
458 static void do_install_cmap(int con
, struct fb_info
*info
);
459 static int do_set_var(struct fb_var_screeninfo
*var
, int isactive
,
460 struct fb_info
*info
);
462 /* set-mode routines */
463 static void set_reg1(u16 port
, u16 index
, u16 data
);
464 static void set_reg3(u16 port
, u16 data
);
465 static void set_reg4(u16 port
, unsigned long data
);
466 static u8
get_reg1(u16 port
, u16 index
);
467 static u8
get_reg2(u16 port
);
468 static u32
get_reg3(u16 port
);
469 static u16
get_modeID_length(unsigned long ROMAddr
, u16 ModeNo
);
470 static int search_modeID(unsigned long ROMAddr
, u16 ModeNo
);
471 static int check_memory_size(unsigned long ROMAddr
);
472 static void get_mode_ptr(unsigned long ROMAddr
, u16 ModeNo
);
473 static void set_seq_regs(unsigned long ROMAddr
);
474 static void set_misc_regs(unsigned long ROMAddr
);
475 static void set_crtc_regs(unsigned long ROMAddr
);
476 static void set_attregs(unsigned long ROMAddr
);
477 static void set_grc_regs(unsigned long ROMAddr
);
478 static void ClearExt1Regs(void);
479 static u16
GetRefindexLength(unsigned long ROMAddr
, u16 ModeNo
);
480 static int get_rate_ptr(unsigned long ROMAddr
, u16 ModeNo
);
481 static void set_sync(unsigned long ROMAddr
);
482 static void set_crt1_crtc(unsigned long ROMAddr
);
483 static void set_crt1_offset(unsigned long ROMAddr
);
484 static u16
get_vclk_len(unsigned long ROMAddr
);
485 static void set_crt1_vclk(unsigned long ROMAddr
);
486 static void set_vclk_state(unsigned long ROMAddr
, u16 ModeNo
);
487 static u16
calc_delay2(unsigned long ROMAddr
, u16 key
);
488 static u16
calc_delay(unsigned long ROMAddr
, u16 key
);
489 static void set_crt1_FIFO(unsigned long ROMAddr
);
490 static void set_crt1_FIFO2(unsigned long ROMAddr
);
491 static void set_crt1_mode_regs(unsigned long ROMAddr
, u16 ModeNo
);
492 static void set_interlace(unsigned long ROMAddr
, u16 ModeNo
);
493 static void write_DAC(u16 dl
, u16 ah
, u16 al
, u16 dh
);
494 static void load_DAC(unsigned long ROMAddr
);
495 static void display_on(void);
497 static int SiSSetMode(u16 ModeNo
);
498 static void pre_setmode(void);
499 static void post_setmode(void);
500 static void search_mode(const char *name
);
501 static u8
search_refresh_rate(unsigned int rate
);
504 static int sisfb_heap_init(void);
505 static struct OH
*poh_new_node(void);
506 static struct OH
*poh_allocate(unsigned long size
);
507 static struct OH
*poh_free(unsigned long base
);
508 static void delete_node(struct OH
*poh
);
509 static void insert_node(struct OH
*pohList
, struct OH
*poh
);
510 static void free_node(struct OH
*poh
);
512 /* ---------------------- Internal Routines ------------------------- */
514 inline static u32
RD32(unsigned char *base
, s32 off
)
516 return readl(base
+ off
);
519 inline static void WR32(unsigned char *base
, s32 off
, u32 v
)
521 writel(v
, base
+ off
);
524 inline static void WR16(unsigned char *base
, s32 off
, u16 v
)
526 writew(v
, base
+ off
);
529 inline static void WR8(unsigned char *base
, s32 off
, u8 v
)
531 writeb(v
, base
+ off
);
534 inline static u32
regrl(s32 off
)
536 return RD32(ivideo
.mmio_vbase
, off
);
539 inline static void regwl(s32 off
, u32 v
)
541 WR32(ivideo
.mmio_vbase
, off
, v
);
544 inline static void regww(s32 off
, u16 v
)
546 WR16(ivideo
.mmio_vbase
, off
, v
);
549 inline static void regwb(s32 off
, u8 v
)
551 WR8(ivideo
.mmio_vbase
, off
, v
);
555 * Get CRTC registers to set var
557 static void crtc_to_var(struct fb_var_screeninfo
*var
)
559 u16 VRE
, VBE
, VRS
, VBS
, VDE
, VT
;
560 u16 HRE
, HBE
, HRS
, HBS
, HDE
, HT
;
561 u8 uSRdata
, uCRdata
, uCRdata2
, uCRdata3
, uMRdata
;
562 int A
, B
, C
, D
, E
, F
, temp
;
566 uSRdata
= vgarb(SEQ_DATA
);
569 var
->vmode
= FB_VMODE_INTERLACED
;
571 var
->vmode
= FB_VMODE_NONINTERLACED
;
573 switch ((uSRdata
& 0x1c) >> 2) {
575 var
->bits_per_pixel
= 8;
578 var
->bits_per_pixel
= 16;
581 var
->bits_per_pixel
= 32;
585 switch (var
->bits_per_pixel
) {
588 var
->green
.length
= 6;
589 var
->blue
.length
= 6;
590 video_cmap_len
= 256;
592 case 16: /* RGB 565 */
593 var
->red
.offset
= 11;
595 var
->green
.offset
= 5;
596 var
->green
.length
= 6;
597 var
->blue
.offset
= 0;
598 var
->blue
.length
= 5;
599 var
->transp
.offset
= 0;
600 var
->transp
.length
= 0;
604 case 24: /* RGB 888 */
605 var
->red
.offset
= 16;
607 var
->green
.offset
= 8;
608 var
->green
.length
= 8;
609 var
->blue
.offset
= 0;
610 var
->blue
.length
= 8;
611 var
->transp
.offset
= 0;
612 var
->transp
.length
= 0;
616 var
->red
.offset
= 16;
618 var
->green
.offset
= 8;
619 var
->green
.length
= 8;
620 var
->blue
.offset
= 0;
621 var
->blue
.length
= 8;
622 var
->transp
.offset
= 24;
623 var
->transp
.length
= 8;
629 uSRdata
= vgarb(SEQ_DATA
);
631 vgawb(CRTC_ADR
, 0x6);
632 uCRdata
= vgarb(CRTC_DATA
);
633 vgawb(CRTC_ADR
, 0x7);
634 uCRdata2
= vgarb(CRTC_DATA
);
636 (uCRdata
& 0xff) | ((u16
) (uCRdata2
& 0x01) << 8) |
637 ((u16
) (uCRdata2
& 0x20) << 4) | ((u16
) (uSRdata
& 0x01) <<
641 vgawb(CRTC_ADR
, 0x12);
642 uCRdata
= vgarb(CRTC_DATA
);
644 (uCRdata
& 0xff) | ((u16
) (uCRdata2
& 0x02) << 7) |
645 ((u16
) (uCRdata2
& 0x40) << 3) | ((u16
) (uSRdata
& 0x02) << 9);
648 vgawb(CRTC_ADR
, 0x10);
649 uCRdata
= vgarb(CRTC_DATA
);
651 (uCRdata
& 0xff) | ((u16
) (uCRdata2
& 0x04) << 6) |
652 ((u16
) (uCRdata2
& 0x80) << 2) | ((u16
) (uSRdata
& 0x08) << 7);
655 vgawb(CRTC_ADR
, 0x15);
656 uCRdata
= vgarb(CRTC_DATA
);
657 vgawb(CRTC_ADR
, 0x9);
658 uCRdata3
= vgarb(CRTC_DATA
);
660 (uCRdata
& 0xff) | ((u16
) (uCRdata2
& 0x08) << 5) |
661 ((u16
) (uCRdata3
& 0x20) << 4) | ((u16
) (uSRdata
& 0x04) << 8);
663 vgawb(CRTC_ADR
, 0x16);
664 uCRdata
= vgarb(CRTC_DATA
);
665 VBE
= (uCRdata
& 0xff) | ((u16
) (uSRdata
& 0x10) << 4);
666 temp
= VBE
- ((E
- 1) & 511);
667 B
= (temp
> 0) ? temp
: (temp
+ 512);
669 vgawb(CRTC_ADR
, 0x11);
670 uCRdata
= vgarb(CRTC_DATA
);
671 VRE
= (uCRdata
& 0x0f) | ((uSRdata
& 0x20) >> 1);
672 temp
= VRE
- ((E
+ F
- 1) & 31);
673 C
= (temp
> 0) ? temp
: (temp
+ 32);
677 var
->yres
= var
->yres_virtual
= E
;
678 var
->upper_margin
= D
;
679 var
->lower_margin
= F
;
683 uSRdata
= vgarb(SEQ_DATA
);
685 vgawb(CRTC_ADR
, 0x0);
686 uCRdata
= vgarb(CRTC_DATA
);
687 HT
= (uCRdata
& 0xff) | ((u16
) (uSRdata
& 0x03) << 8);
690 vgawb(CRTC_ADR
, 0x1);
691 uCRdata
= vgarb(CRTC_DATA
);
692 HDE
= (uCRdata
& 0xff) | ((u16
) (uSRdata
& 0x0C) << 6);
695 vgawb(CRTC_ADR
, 0x4);
696 uCRdata
= vgarb(CRTC_DATA
);
697 HRS
= (uCRdata
& 0xff) | ((u16
) (uSRdata
& 0xC0) << 2);
700 vgawb(CRTC_ADR
, 0x2);
701 uCRdata
= vgarb(CRTC_DATA
);
702 HBS
= (uCRdata
& 0xff) | ((u16
) (uSRdata
& 0x30) << 4);
705 uSRdata
= vgarb(SEQ_DATA
);
706 vgawb(CRTC_ADR
, 0x3);
707 uCRdata
= vgarb(CRTC_DATA
);
708 vgawb(CRTC_ADR
, 0x5);
709 uCRdata2
= vgarb(CRTC_DATA
);
711 (uCRdata
& 0x1f) | ((u16
) (uCRdata2
& 0x80) >> 2) |
712 ((u16
) (uSRdata
& 0x03) << 6);
713 HRE
= (uCRdata2
& 0x1f) | ((uSRdata
& 0x04) << 3);
715 temp
= HBE
- ((E
- 1) & 255);
716 B
= (temp
> 0) ? temp
: (temp
+ 256);
718 temp
= HRE
- ((E
+ F
+ 3) & 63);
719 C
= (temp
> 0) ? temp
: (temp
+ 64);
723 var
->xres
= var
->xres_virtual
= E
* 8;
724 var
->left_margin
= D
* 8;
725 var
->right_margin
= F
* 8;
726 var
->hsync_len
= C
* 8;
728 var
->activate
= FB_ACTIVATE_NOW
;
732 uMRdata
= vgarb(0x1C);
734 var
->sync
&= ~FB_SYNC_VERT_HIGH_ACT
;
736 var
->sync
|= FB_SYNC_VERT_HIGH_ACT
;
739 var
->sync
&= ~FB_SYNC_HOR_HIGH_ACT
;
741 var
->sync
|= FB_SYNC_HOR_HIGH_ACT
;
747 hrate
= (double) ivideo
.refresh_rate
* (double) VT
/ 2;
749 var
->pixclock
= (u32
) (1E12
/ drate
);
752 static void sisfb_set_disp(int con
, struct fb_var_screeninfo
*var
)
754 struct fb_fix_screeninfo fix
;
755 struct display
*display
;
756 struct display_switch
*sw
;
760 display
= &fb_display
[con
];
762 display
= &disp
; /* used during initialization */
764 sisfb_get_fix(&fix
, con
, 0);
766 display
->screen_base
= ivideo
.video_vbase
;
767 display
->visual
= fix
.visual
;
768 display
->type
= fix
.type
;
769 display
->type_aux
= fix
.type_aux
;
770 display
->ypanstep
= fix
.ypanstep
;
771 display
->ywrapstep
= fix
.ywrapstep
;
772 display
->line_length
= fix
.line_length
;
773 display
->next_line
= fix
.line_length
;
774 /*display->can_soft_blank = 1; */
775 display
->can_soft_blank
= 0;
776 display
->inverse
= inverse
;
780 switch (ivideo
.video_bpp
) {
781 #ifdef FBCON_HAS_CFB8
786 #ifdef FBCON_HAS_CFB16
790 display
->dispsw_data
= fbcon_cmap
.cfb16
;
793 #ifdef FBCON_HAS_CFB24
796 display
->dispsw_data
= fbcon_cmap
.cfb24
;
799 #ifdef FBCON_HAS_CFB32
802 display
->dispsw_data
= fbcon_cmap
.cfb32
;
809 memcpy(&sisfb_sw
, sw
, sizeof(*sw
));
810 display
->dispsw
= &sisfb_sw
;
811 restore_flags(flags
);
813 display
->scrollmode
= SCROLL_YREDRAW
;
814 sisfb_sw
.bmove
= fbcon_redraw_bmove
;
819 * Read a single color register and split it into colors/transparent.
820 * Return != 0 for invalid regno.
823 static int sis_getcolreg(unsigned regno
, unsigned *red
, unsigned *green
,
824 unsigned *blue
, unsigned *transp
,
825 struct fb_info
*fb_info
)
827 if (regno
>= video_cmap_len
)
830 *red
= palette
[regno
].red
;
831 *green
= palette
[regno
].green
;
832 *blue
= palette
[regno
].blue
;
838 * Set a single color register. The values supplied are already
839 * rounded down to the hardware's capabilities (according to the
840 * entries in the var structure). Return != 0 for invalid regno.
843 static int sis_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
844 unsigned blue
, unsigned transp
,
845 struct fb_info
*fb_info
)
848 if (regno
>= video_cmap_len
)
851 palette
[regno
].red
= red
;
852 palette
[regno
].green
= green
;
853 palette
[regno
].blue
= blue
;
855 switch (ivideo
.video_bpp
) {
856 #ifdef FBCON_HAS_CFB8
858 vgawb(DAC_ADR
, regno
);
859 vgawb(DAC_DATA
, red
>> 10);
860 vgawb(DAC_DATA
, green
>> 10);
861 vgawb(DAC_DATA
, blue
>> 10);
864 #ifdef FBCON_HAS_CFB16
867 fbcon_cmap
.cfb16
[regno
] =
869 ((green
& 0xfc00) >> 5) | ((blue
& 0xf800) >> 11);
872 #ifdef FBCON_HAS_CFB24
877 fbcon_cmap
.cfb24
[regno
] =
878 (red
<< 16) | (green
<< 8) | (blue
);
881 #ifdef FBCON_HAS_CFB32
886 fbcon_cmap
.cfb32
[regno
] =
887 (red
<< 16) | (green
<< 8) | (blue
);
894 static void do_install_cmap(int con
, struct fb_info
*info
)
899 if (fb_display
[con
].cmap
.len
)
900 fb_set_cmap(&fb_display
[con
].cmap
, 1, sis_setcolreg
, info
);
902 fb_set_cmap(fb_default_cmap(video_cmap_len
), 1,
903 sis_setcolreg
, info
);
906 static int do_set_var(struct fb_var_screeninfo
*var
, int isactive
,
907 struct fb_info
*info
)
909 unsigned int htotal
=
910 var
->left_margin
+ var
->xres
+ var
->right_margin
+
912 unsigned int vtotal
=
913 var
->upper_margin
+ var
->yres
+ var
->lower_margin
+
915 double drate
= 0, hrate
= 0;
918 if ((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_NONINTERLACED
)
920 else if ((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_DOUBLE
)
922 else if ((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_INTERLACED
)
926 if (!htotal
|| !vtotal
) {
927 DPRINTK("Invalid 'var' Information!\n");
931 drate
= 1E12
/ var
->pixclock
;
932 hrate
= drate
/ htotal
;
933 ivideo
.refresh_rate
= (unsigned int) (hrate
/ vtotal
* 2 + 0.5);
936 while ((sisbios_mode
[mode_idx
].mode_no
!= 0)
937 && (sisbios_mode
[mode_idx
].xres
<= var
->xres
)) {
938 if ((sisbios_mode
[mode_idx
].xres
== var
->xres
)
939 && (sisbios_mode
[mode_idx
].yres
== var
->yres
)
940 && (sisbios_mode
[mode_idx
].bpp
== var
->bits_per_pixel
)) {
941 mode_no
= sisbios_mode
[mode_idx
].mode_no
;
949 printk("sisfb does not support mode %dx%d-%d\n", var
->xres
,
950 var
->yres
, var
->bits_per_pixel
);
954 if (search_refresh_rate(ivideo
.refresh_rate
) == 0) { /* not supported rate */
955 rate_idx
= sisbios_mode
[mode_idx
].rate_idx
;
956 ivideo
.refresh_rate
= 60;
960 if (((var
->activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
)
964 if (SiSSetMode(mode_no
)) {
965 DPRINTK("sisfb: set mode[0x%x]: failed\n",
972 ivideo
.video_bpp
= sisbios_mode
[mode_idx
].bpp
;
973 ivideo
.video_width
= sisbios_mode
[mode_idx
].xres
;
974 ivideo
.video_height
= sisbios_mode
[mode_idx
].yres
;
976 ivideo
.video_width
* (ivideo
.video_bpp
>> 3);
978 DPRINTK("Current Mode: %dx%d-%d line_length=%d\n",
979 ivideo
.video_width
, ivideo
.video_height
,
980 ivideo
.video_bpp
, video_linelength
);
986 /* ---------------------- Draw Funtions ----------------------------- */
988 static void sis_get_glyph(struct GlyInfo
*gly
)
990 struct display
*p
= &fb_display
[currcon
];
994 u8
*gbuf
= gly
->gmask
;
998 gly
->fontheight
= fontheight(p
);
999 gly
->fontwidth
= fontwidth(p
);
1000 widthb
= (fontwidth(p
) + 7) / 8;
1002 c
= gly
->ch
& p
->charmask
;
1003 if (fontwidth(p
) <= 8)
1004 cdat
= p
->fontdata
+ c
* fontheight(p
);
1006 cdat
= p
->fontdata
+ (c
* fontheight(p
) << 1);
1008 size
= fontheight(p
) * widthb
;
1009 memcpy(gbuf
, cdat
, size
);
1014 /* ---------------------- HEAP Routines ----------------------------- */
1017 * Heap Initialization
1020 static int sisfb_heap_init(void)
1025 if(ivideo
.video_size
> 0x800000) /* video ram is large than 8M */
1026 heap_start
= (unsigned long) ivideo
.video_vbase
+ RESERVED_MEM_SIZE_8M
;
1028 heap_start
= (unsigned long) ivideo
.video_vbase
+ RESERVED_MEM_SIZE_4M
;
1030 heap_end
= (unsigned long) ivideo
.video_vbase
+ ivideo
.video_size
;
1031 heap_size
= heap_end
- heap_start
;
1034 /* Setting for Turbo Queue */
1035 if (heap_size
>= TURBO_QUEUE_AREA_SIZE
) {
1037 (ivideo
.video_size
-
1038 TURBO_QUEUE_AREA_SIZE
) / (64 * 1024);
1039 jTemp
= (u8
) (tqueue_pos
& 0xff);
1040 vgawb(SEQ_ADR
, IND_SIS_TURBOQUEUE_SET
);
1041 tq_state
= vgarb(SEQ_DATA
);
1044 tq_state
|= (u8
) (tqueue_pos
>> 8);
1045 vgawb(SEQ_DATA
, tq_state
);
1046 vgawb(SEQ_ADR
, IND_SIS_TURBOQUEUE_ADR
);
1047 vgawb(SEQ_DATA
, jTemp
);
1049 caps
|= TURBO_QUEUE_CAP
;
1051 heap_end
-= TURBO_QUEUE_AREA_SIZE
;
1052 heap_size
-= TURBO_QUEUE_AREA_SIZE
;
1055 /* Setting for HW cursor(4K) */
1056 if (heap_size
>= HW_CURSOR_AREA_SIZE
) {
1057 heap_end
-= HW_CURSOR_AREA_SIZE
;
1058 heap_size
-= HW_CURSOR_AREA_SIZE
;
1059 hwcursor_vbase
= heap_end
;
1061 caps
|= HW_CURSOR_CAP
;
1064 heap
.pohaChain
= NULL
;
1065 heap
.pohFreeList
= NULL
;
1067 poh
= poh_new_node();
1072 /* The first node describles the entire heap size */
1073 poh
->pohNext
= &heap
.ohFree
;
1074 poh
->pohPrev
= &heap
.ohFree
;
1075 poh
->ulSize
= heap_end
- heap_start
+ 1;
1076 poh
->ulOffset
= heap_start
- (unsigned long) ivideo
.video_vbase
;
1078 DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n",
1079 (char *) heap_start
, (char *) heap_end
,
1080 (unsigned int) poh
->ulSize
/ 1024);
1082 DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n",
1083 (unsigned int) poh
->ulOffset
, (unsigned int) poh
->ulSize
/ 1024);
1085 /* The second node in our free list sentinel */
1086 heap
.ohFree
.pohNext
= poh
;
1087 heap
.ohFree
.pohPrev
= poh
;
1088 heap
.ohFree
.ulSize
= 0;
1089 heap
.ulMaxFreeSize
= poh
->ulSize
;
1091 /* Initialize the discardable list */
1092 heap
.ohUsed
.pohNext
= &heap
.ohUsed
;
1093 heap
.ohUsed
.pohPrev
= &heap
.ohUsed
;
1094 heap
.ohUsed
.ulSize
= SENTINEL
;
1100 * Allocates a basic memory unit in which we'll pack our data structures.
1103 static struct OH
*poh_new_node(void)
1107 struct OHALLOC
*poha
;
1110 if (heap
.pohFreeList
== NULL
) {
1111 poha
= kmalloc(OH_ALLOC_SIZE
, GFP_KERNEL
);
1113 poha
->pohaNext
= heap
.pohaChain
;
1114 heap
.pohaChain
= poha
;
1118 sizeof(struct OHALLOC
)) / sizeof(struct OH
) + 1;
1120 poh
= &poha
->aoh
[0];
1121 for (i
= cOhs
- 1; i
!= 0; i
--) {
1122 poh
->pohNext
= poh
+ 1;
1126 poh
->pohNext
= NULL
;
1127 heap
.pohFreeList
= &poha
->aoh
[0];
1130 poh
= heap
.pohFreeList
;
1131 heap
.pohFreeList
= poh
->pohNext
;
1137 * Allocates space, return NULL when failed
1140 static struct OH
*poh_allocate(unsigned long size
)
1146 if (size
> heap
.ulMaxFreeSize
) {
1147 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
1148 (unsigned int) size
/ 1024);
1152 pohThis
= heap
.ohFree
.pohNext
;
1154 while (pohThis
!= &heap
.ohFree
) {
1155 if (size
<= pohThis
->ulSize
) {
1159 pohThis
= pohThis
->pohNext
;
1163 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
1164 (unsigned int) size
/ 1024);
1168 if (size
== pohThis
->ulSize
) {
1170 delete_node(pohThis
);
1172 pohRoot
= poh_new_node();
1174 if (pohRoot
== NULL
) {
1178 pohRoot
->ulOffset
= pohThis
->ulOffset
;
1179 pohRoot
->ulSize
= size
;
1181 pohThis
->ulOffset
+= size
;
1182 pohThis
->ulSize
-= size
;
1185 heap
.ulMaxFreeSize
-= size
;
1187 pohThis
= &heap
.ohUsed
;
1188 insert_node(pohThis
, pohRoot
);
1194 * To remove a node from a list.
1197 static void delete_node(struct OH
*poh
)
1203 pohPrev
= poh
->pohPrev
;
1204 pohNext
= poh
->pohNext
;
1206 pohPrev
->pohNext
= pohNext
;
1207 pohNext
->pohPrev
= pohPrev
;
1213 * To insert a node into a list.
1216 static void insert_node(struct OH
*pohList
, struct OH
*poh
)
1220 pohTemp
= pohList
->pohNext
;
1222 pohList
->pohNext
= poh
;
1223 pohTemp
->pohPrev
= poh
;
1225 poh
->pohPrev
= pohList
;
1226 poh
->pohNext
= pohTemp
;
1230 * Frees an off-screen heap allocation.
1233 static struct OH
*poh_free(unsigned long base
)
1237 struct OH
*pohFreed
;
1240 unsigned long ulUpper
;
1241 unsigned long ulLower
;
1244 pohFreed
= heap
.ohUsed
.pohNext
;
1246 while (pohFreed
!= &heap
.ohUsed
) {
1247 if (pohFreed
->ulOffset
== base
) {
1252 pohFreed
= pohFreed
->pohNext
;
1258 heap
.ulMaxFreeSize
+= pohFreed
->ulSize
;
1260 pohPrev
= pohNext
= NULL
;
1261 ulUpper
= pohFreed
->ulOffset
+ pohFreed
->ulSize
;
1262 ulLower
= pohFreed
->ulOffset
;
1264 pohThis
= heap
.ohFree
.pohNext
;
1266 while (pohThis
!= &heap
.ohFree
) {
1267 if (pohThis
->ulOffset
== ulUpper
) {
1270 else if ((pohThis
->ulOffset
+ pohThis
->ulSize
) ==
1274 pohThis
= pohThis
->pohNext
;
1277 delete_node(pohFreed
);
1279 if (pohPrev
&& pohNext
) {
1280 pohPrev
->ulSize
+= (pohFreed
->ulSize
+ pohNext
->ulSize
);
1281 delete_node(pohNext
);
1282 free_node(pohFreed
);
1288 pohPrev
->ulSize
+= pohFreed
->ulSize
;
1289 free_node(pohFreed
);
1294 pohNext
->ulSize
+= pohFreed
->ulSize
;
1295 pohNext
->ulOffset
= pohFreed
->ulOffset
;
1296 free_node(pohFreed
);
1300 insert_node(&heap
.ohFree
, pohFreed
);
1306 * Frees our basic data structure allocation unit by adding it to a free
1310 static void free_node(struct OH
*poh
)
1316 poh
->pohNext
= heap
.pohFreeList
;
1317 heap
.pohFreeList
= poh
;
1322 void sis_malloc(struct sis_memreq
*req
)
1326 poh
= poh_allocate(req
->size
);
1331 DPRINTK("sisfb: VMEM Allocation Failed\n");
1333 DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n",
1334 (char *) (poh
->ulOffset
+
1335 (unsigned long) ivideo
.video_vbase
));
1337 req
->offset
= poh
->ulOffset
;
1338 req
->size
= poh
->ulSize
;
1343 void sis_free(unsigned long base
)
1347 poh
= poh_free(base
);
1350 DPRINTK("sisfb: poh_free() failed at base 0x%x\n",
1351 (unsigned int) base
);
1358 /* ---------------------- SetMode Routines -------------------------- */
1360 static void set_reg1(u16 port
, u16 index
, u16 data
)
1362 outb((u8
) (index
& 0xff), port
);
1364 outb((u8
) (data
& 0xff), port
);
1367 static void set_reg3(u16 port
, u16 data
)
1369 outb((u8
) (data
& 0xff), port
);
1372 static void set_reg4(u16 port
, unsigned long data
)
1374 outl((u32
) (data
& 0xffffffff), port
);
1377 static u8
get_reg1(u16 port
, u16 index
)
1381 outb((u8
) (index
& 0xff), port
);
1387 static u8
get_reg2(u16 port
)
1396 static u32
get_reg3(u16 port
)
1404 static u16
get_modeID_length(unsigned long ROMAddr
, u16 ModeNo
)
1407 unsigned char ModeID
;
1412 usModeIDOffset
= *((u16
*) (ROMAddr
+ 0x20A));
1413 ModeID
= *((unsigned char *) (ROMAddr
+ usModeIDOffset
));
1414 while (ModeID
!= 0x2E) {
1416 usModeIDOffset
= usModeIDOffset
+ 1;
1417 ModeID
= *((unsigned char *) (ROMAddr
+ usModeIDOffset
));
1419 return (modeidlength
);
1424 static int search_modeID(unsigned long ROMAddr
, u16 ModeNo
)
1426 unsigned char ModeID
;
1428 unsigned int count
= 0;
1430 ModeIDOffset
= *((u16
*) (ROMAddr
+ 0x20A));
1431 ModeID
= *((unsigned char *) (ROMAddr
+ ModeIDOffset
));
1432 usIDLength
= get_modeID_length(ROMAddr
, ModeNo
);
1433 while (ModeID
!= 0xff && ModeID
!= ModeNo
) {
1434 ModeIDOffset
= ModeIDOffset
+ usIDLength
;
1435 ModeID
= *((unsigned char *) (ROMAddr
+ ModeIDOffset
));
1436 if (count
++ >= 0xff)
1445 static int check_memory_size(unsigned long ROMAddr
)
1451 modeflag
= *((u16
*) (ROMAddr
+ ModeIDOffset
+ 0x01));
1452 ModeType
= modeflag
& ModeInfoFlag
;
1454 memorysize
= modeflag
& MemoryInfoFlag
;
1455 memorysize
= memorysize
>> MemorySizeShift
;
1458 temp
= get_reg1(P3c4
, 0x14);
1462 if (temp
< memorysize
)
1468 static void get_mode_ptr(unsigned long ROMAddr
, u16 ModeNo
)
1470 unsigned char index
;
1472 StandTable
= *((u16
*) (ROMAddr
+ 0x202));
1476 *((unsigned char *) (ROMAddr
+ ModeIDOffset
+ 0x03));
1478 if (ModeType
<= 0x02)
1484 StandTable
= StandTable
+ 64 * index
;
1488 static void set_seq_regs(unsigned long ROMAddr
)
1490 unsigned char SRdata
;
1493 set_reg1(P3c4
, 0x00, 0x03);
1494 StandTable
= StandTable
+ 0x05;
1495 SRdata
= *((unsigned char *) (ROMAddr
+ StandTable
));
1496 SRdata
= SRdata
| 0x20;
1497 set_reg1(P3c4
, 0x01, SRdata
);
1499 for (i
= 02; i
<= 04; i
++) {
1501 SRdata
= *((unsigned char *) (ROMAddr
+ StandTable
));
1502 set_reg1(P3c4
, i
, SRdata
);
1506 static void set_misc_regs(unsigned long ROMAddr
)
1508 unsigned char Miscdata
;
1511 Miscdata
= *((unsigned char *) (ROMAddr
+ StandTable
));
1512 set_reg3(P3c2
, Miscdata
);
1515 static void set_crtc_regs(unsigned long ROMAddr
)
1517 unsigned char CRTCdata
;
1520 CRTCdata
= (unsigned char) get_reg1(P3d4
, 0x11);
1521 CRTCdata
= CRTCdata
& 0x7f;
1522 set_reg1(P3d4
, 0x11, CRTCdata
);
1524 for (i
= 0; i
<= 0x18; i
++) {
1526 CRTCdata
= *((unsigned char *) (ROMAddr
+ StandTable
));
1527 set_reg1(P3d4
, i
, CRTCdata
);
1531 static void set_attregs(unsigned long ROMAddr
)
1533 unsigned char ARdata
;
1536 for (i
= 0; i
<= 0x13; i
++) {
1538 ARdata
= *((unsigned char *) (ROMAddr
+ StandTable
));
1542 set_reg3(P3c0
, ARdata
);
1545 set_reg3(P3c0
, 0x14);
1546 set_reg3(P3c0
, 0x00);
1549 set_reg3(P3c0
, 0x20);
1552 static void set_grc_regs(unsigned long ROMAddr
)
1554 unsigned char GRdata
;
1557 for (i
= 0; i
<= 0x08; i
++) {
1559 GRdata
= *((unsigned char *) (ROMAddr
+ StandTable
));
1560 set_reg1(P3ce
, i
, GRdata
);
1562 if (ModeType
> ModeVGA
) {
1563 GRdata
= (unsigned char) get_reg1(P3ce
, 0x05);
1564 GRdata
= GRdata
& 0xBF;
1565 set_reg1(P3ce
, 0x05, GRdata
);
1569 static void ClearExt1Regs(void)
1573 for (i
= 0x0A; i
<= 0x0E; i
++)
1574 set_reg1(P3c4
, i
, 0x00);
1577 static u16
GetRefindexLength(unsigned long ROMAddr
, u16 ModeNo
)
1579 unsigned char ModeID
;
1586 usModeIDOffset
= *((u16
*) (ROMAddr
+ 0x20A));
1587 ModeID
= *((unsigned char *) (ROMAddr
+ usModeIDOffset
));
1588 usIDLength
= get_modeID_length(ROMAddr
, ModeNo
);
1589 while (ModeID
!= 0x40) {
1590 usModeIDOffset
= usModeIDOffset
+ usIDLength
;
1591 ModeID
= *((unsigned char *) (ROMAddr
+ usModeIDOffset
));
1595 usREFIndex
= *((u16
*) (ROMAddr
+ usModeIDOffset
+ 0x04));
1597 temp
= *((unsigned char *) (ROMAddr
+ usREFIndex
));
1598 while (temp
!= 0xFF) {
1601 temp
= *((unsigned char *) (ROMAddr
+ usREFIndex
));
1603 return (refindexlength
);
1606 static int get_rate_ptr(unsigned long ROMAddr
, u16 ModeNo
)
1610 u16 ulRefIndexLength
;
1615 index
= get_reg1(P3d4
, 0x33);
1616 index
= index
& 0x0F;
1620 REFIndex
= *((u16
*) (ROMAddr
+ ModeIDOffset
+ 0x04));
1622 ulRefIndexLength
= GetRefindexLength(ROMAddr
, ModeNo
);
1625 temp
= *((u16
*) (ROMAddr
+ REFIndex
));
1628 temp
= temp
& ModeInfoFlag
;
1629 if (temp
< ModeType
)
1632 REFIndex
= REFIndex
+ ulRefIndexLength
;
1634 } while (index
>= 0);
1636 REFIndex
= REFIndex
- ulRefIndexLength
;
1640 static void set_sync(unsigned long ROMAddr
)
1645 sync
= *((u16
*) (ROMAddr
+ REFIndex
));
1649 set_reg3(P3c2
, temp
);
1652 static void set_crt1_crtc(unsigned long ROMAddr
)
1654 unsigned char index
;
1658 index
= *((unsigned char *) (ROMAddr
+ REFIndex
+ 0x02));
1659 CRT1Table
= *((u16
*) (ROMAddr
+ 0x204));
1660 CRT1Table
= CRT1Table
+ index
* CRT1Len
;
1662 data
= (unsigned char) get_reg1(P3d4
, 0x11);
1664 set_reg1(P3d4
, 0x11, data
);
1667 for (i
= 0; i
<= 0x05; i
++) {
1669 data
= *((unsigned char *) (ROMAddr
+ CRT1Table
));
1670 set_reg1(P3d4
, i
, data
);
1672 for (i
= 0x06; i
<= 0x07; i
++) {
1674 data
= *((unsigned char *) (ROMAddr
+ CRT1Table
));
1675 set_reg1(P3d4
, i
, data
);
1677 for (i
= 0x10; i
<= 0x12; i
++) {
1679 data
= *((unsigned char *) (ROMAddr
+ CRT1Table
));
1680 set_reg1(P3d4
, i
, data
);
1682 for (i
= 0x15; i
<= 0x16; i
++) {
1684 data
= *((unsigned char *) (ROMAddr
+ CRT1Table
));
1685 set_reg1(P3d4
, i
, data
);
1687 for (i
= 0x0A; i
<= 0x0C; i
++) {
1689 data
= *((unsigned char *) (ROMAddr
+ CRT1Table
));
1690 set_reg1(P3c4
, i
, data
);
1694 data
= *((unsigned char *) (ROMAddr
+ CRT1Table
));
1696 set_reg1(P3c4
, 0x0E, data
);
1698 data
= (unsigned char) get_reg1(P3d4
, 0x09);
1700 i
= *((unsigned char *) (ROMAddr
+ CRT1Table
));
1704 i
= *((u16
*) (ROMAddr
+ ModeIDOffset
+ 0x01));
1705 i
= i
& DoubleScanMode
;
1708 set_reg1(P3d4
, 0x09, data
);
1710 if (ModeType
> 0x03)
1711 set_reg1(P3d4
, 0x14, 0x4F);
1714 static void set_crt1_offset(unsigned long ROMAddr
)
1720 temp
= *((unsigned char *) (ROMAddr
+ ModeIDOffset
+ 0x03));
1722 ScreenOffset
= *((u16
*) (ROMAddr
+ 0x206));
1723 temp
= *((unsigned char *) (ROMAddr
+ ScreenOffset
+ temp
));
1725 temp2
= *((u16
*) (ROMAddr
+ REFIndex
+ 0x00));
1726 temp2
= temp2
& InterlaceMode
;
1729 temp2
= ModeType
- ModeEGA
;
1750 temp
= temp
* temp2
;
1756 i
= get_reg1(P3c4
, 0x0E);
1759 set_reg1(P3c4
, 0x0E, i
);
1761 temp
= (unsigned char) temp2
;
1763 set_reg1(P3d4
, 0x13, temp
);
1765 temp2
= *((u16
*) (ROMAddr
+ REFIndex
+ 0x00));
1766 temp2
= temp2
& InterlaceMode
;
1770 DisplayUnit
= DisplayUnit
<< 5;
1771 ah
= (DisplayUnit
& 0xff00) >> 8;
1772 al
= DisplayUnit
& 0x00ff;
1777 set_reg1(P3c4
, 0x10, ah
);
1780 static u16
get_vclk_len(unsigned long ROMAddr
)
1782 u16 VCLKDataStart
, vclklabel
, temp
;
1783 VCLKDataStart
= *((u16
*) (ROMAddr
+ 0x208));
1784 for (temp
= 0;; temp
++) {
1785 vclklabel
= *((u16
*) (ROMAddr
+ VCLKDataStart
+ temp
));
1786 if (vclklabel
== VCLKStartFreq
) {
1794 static void set_crt1_vclk(unsigned long ROMAddr
)
1797 unsigned char index
, data
;
1799 index
= *((unsigned char *) (ROMAddr
+ REFIndex
+ 0x03));
1800 CRT1VCLKLen
= get_vclk_len(ROMAddr
);
1801 data
= index
* CRT1VCLKLen
;
1802 VCLKData
= *((u16
*) (ROMAddr
+ 0x208));
1803 VCLKData
= VCLKData
+ data
;
1805 set_reg1(P3c4
, 0x31, 0);
1807 for (i
= 0x2B; i
<= 0x2C; i
++) {
1808 data
= *((unsigned char *) (ROMAddr
+ VCLKData
));
1809 set_reg1(P3c4
, i
, data
);
1812 set_reg1(P3c4
, 0x2D, 0x80);
1815 static void set_vclk_state(unsigned long ROMAddr
, u16 ModeNo
)
1819 unsigned char index
;
1821 index
= *((unsigned char *) (ROMAddr
+ REFIndex
+ 0x03));
1822 CRT1VCLKLen
= get_vclk_len(ROMAddr
);
1823 data
= index
* CRT1VCLKLen
;
1824 VCLKData
= *((u16
*) (ROMAddr
+ 0x208));
1825 VCLKData
= VCLKData
+ data
+ (CRT1VCLKLen
- 2);
1827 VCLK
= *((u16
*) (ROMAddr
+ VCLKData
));
1831 data
= get_reg1(P3c4
, 0x07);
1835 set_reg1(P3c4
, 0x07, data
);
1837 data
= get_reg1(P3c4
, 0x32);
1841 set_reg1(P3c4
, 0x32, data
);
1850 data
= get_reg1(P3c4
, 0x07);
1852 data
= data
| data2
;
1853 set_reg1(P3c4
, 0x07, data
);
1856 static u16
calc_delay2(unsigned long ROMAddr
, u16 key
)
1859 unsigned char LatencyFactor
[] = {
1860 88, 80, 78, 72, 70, 00,
1861 00, 79, 77, 71, 69, 49,
1862 88, 80, 78, 72, 70, 00,
1863 00, 72, 70, 64, 62, 44
1866 data
= get_reg1(P3c4
, 0x14);
1870 data
= get_reg1(P3c4
, 0x15);
1871 data
= (data
& 0xf0) >> 4;
1876 index
= index
+ data
;
1877 data
= LatencyFactor
[index
];
1882 static u16
calc_delay(unsigned long ROMAddr
, u16 key
)
1884 u16 data
, data2
, temp0
, temp1
;
1885 unsigned char ThLowA
[] = {
1886 61, 3, 52, 5, 68, 7, 100, 11,
1887 43, 3, 42, 5, 54, 7, 78, 11,
1888 34, 3, 37, 5, 47, 7, 67, 11
1890 unsigned char ThLowB
[] = {
1891 81, 4, 72, 6, 88, 8, 120, 12,
1892 55, 4, 54, 6, 66, 8, 90, 12,
1893 42, 4, 45, 6, 55, 8, 75, 12
1895 unsigned char ThTiming
[] = { 1, 2, 2, 3, 0, 1, 1, 2 };
1897 data
= get_reg1(P3c4
, 0x16);
1899 data2
= get_reg1(P3c4
, 0x14);
1900 data2
= (data2
>> 4) & 0x0C;
1901 data
= data
| data2
;
1904 temp0
= (u16
) ThLowA
[data
];
1905 temp1
= (u16
) ThLowA
[data
+ 1];
1907 temp0
= (u16
) ThLowB
[data
];
1908 temp1
= (u16
) ThLowB
[data
+ 1];
1912 data
= get_reg1(P3c4
, 0x18);
1914 data2
= data2
| 0x01;
1916 data2
= data2
| 0x02;
1918 data2
= data2
| 0x04;
1920 data
= temp1
* ThTiming
[data2
] + temp0
;
1925 static void set_crt1_FIFO(unsigned long ROMAddr
)
1927 u16 index
, data
, VCLK
, data2
, MCLKOffset
, MCLK
, colorth
= 1;
1930 index
= *((unsigned char *) (ROMAddr
+ REFIndex
+ 0x03));
1931 CRT1VCLKLen
= get_vclk_len(ROMAddr
);
1932 data
= index
* CRT1VCLKLen
;
1933 VCLKData
= *((u16
*) (ROMAddr
+ 0x208));
1934 VCLKData
= VCLKData
+ data
+ (CRT1VCLKLen
- 2);
1935 VCLK
= *((u16
*) (ROMAddr
+ VCLKData
));
1937 MCLKOffset
= *((u16
*) (ROMAddr
+ 0x20C));
1938 index
= get_reg1(P3c4
, 0x3A);
1940 MCLKOffset
= MCLKOffset
+ index
* 5;
1941 MCLK
= *((unsigned char *) (ROMAddr
+ MCLKOffset
+ 0x03));
1943 data2
= ModeType
- 0x02;
1966 B
= (calc_delay(ROMAddr
, 0) * VCLK
* colorth
);
1967 B
= B
/ (16 * MCLK
);
1970 A
= (calc_delay(ROMAddr
, 1) * VCLK
* colorth
);
1971 A
= A
/ (16 * MCLK
);
1986 data
= get_reg1(P3c4
, 0x16);
1991 data2
= get_reg1(P3c4
, 0x16);
1992 data2
= (data2
& 0x3f) | data
;
1993 set_reg1(P3c4
, 0x16, data2
);
1997 } while (bl
> 0x13);
2002 set_reg1(P3c4
, 0x08, ah
);
2007 data2
= get_reg1(P3c4
, 0x0F);
2008 data2
= data2
& 0x9f;
2009 data2
= data2
| data
;
2010 set_reg1(P3c4
, 0x0F, data2
);
2015 set_reg1(P3c4
, 0x3b, 0x00);
2016 data2
= get_reg1(P3c4
, 0x09);
2017 data2
= data2
& 0xF0;
2018 data2
= data2
| data
;
2019 set_reg1(P3c4
, 0x09, data2
);
2023 static void set_crt1_FIFO2(unsigned long ROMAddr
)
2025 u16 index
, data
, VCLK
, data2
, MCLKOffset
, MCLK
, colorth
= 1;
2029 index
= *((unsigned char *) (ROMAddr
+ REFIndex
+ 0x03));
2030 CRT1VCLKLen
= get_vclk_len(ROMAddr
);
2031 data
= index
* CRT1VCLKLen
;
2032 VCLKData
= *((u16
*) (ROMAddr
+ 0x208));
2033 VCLKData
= VCLKData
+ data
+ (CRT1VCLKLen
- 2);
2034 VCLK
= *((u16
*) (ROMAddr
+ VCLKData
));
2036 MCLKOffset
= *((u16
*) (ROMAddr
+ 0x20C));
2037 index
= get_reg1(P3c4
, 0x1A);
2039 MCLKOffset
= MCLKOffset
+ index
* 5;
2040 MCLK
= *((u16
*) (ROMAddr
+ MCLKOffset
+ 0x03));
2042 data2
= ModeType
- 0x02;
2065 B
= (calc_delay2(ROMAddr
, 0) * VCLK
* colorth
);
2066 if (B
% (16 * MCLK
) == 0) {
2067 B
= B
/ (16 * MCLK
);
2070 B
= B
/ (16 * MCLK
);
2075 data
= get_reg1(P3c4
, 0x15);
2081 data2
= get_reg1(P3c4
, 0x15);
2082 data2
= (data2
& 0x0f) | data
;
2083 set_reg1(P3c4
, 0x15, data2
);
2087 } while (bl
> 0x13);
2089 data2
= get_reg1(P3c4
, 0x15);
2090 data2
= (data2
& 0xf0) >> 4;
2091 data2
= data2
<< 24;
2093 set_reg4(0xcf8, 0x80000050);
2094 eax
= get_reg3(0xcfc);
2095 eax
= eax
& 0x0f0ffffff;
2097 set_reg4(0xcfc, eax
);
2102 set_reg1(P3c4
, 0x08, ah
);
2107 data2
= get_reg1(P3c4
, 0x0F);
2108 data2
= data2
& 0x9f;
2109 data2
= data2
| data
;
2110 set_reg1(P3c4
, 0x0F, data2
);
2115 set_reg1(P3c4
, 0x3b, 0x00);
2116 data2
= get_reg1(P3c4
, 0x09);
2117 data2
= data2
& 0xF0;
2118 data2
= data2
| data
;
2119 set_reg1(P3c4
, 0x09, data2
);
2122 static void set_crt1_mode_regs(unsigned long ROMAddr
, u16 ModeNo
)
2125 u16 data
, data2
, data3
;
2128 data
= *((u16
*) (ROMAddr
+ REFIndex
+ 0x00));
2134 if (ModeType
> 0x02) {
2135 data2
= data2
| 0x02;
2136 data3
= ModeType
- ModeVGA
;
2138 data2
= data2
| data3
;
2141 data
= data
& InterlaceMode
;
2143 data2
= data2
| 0x20;
2144 set_reg1(P3c4
, 0x06, data2
);
2146 data
= get_reg1(P3c4
, 0x01);
2148 data2
= *((u16
*) (ROMAddr
+ ModeIDOffset
+ 0x01));
2149 data2
= data2
& HalfDCLK
;
2152 set_reg1(P3c4
, 0x01, data
);
2154 data
= get_reg1(P3c4
, 0x0F);
2156 data2
= *((u16
*) (ROMAddr
+ ModeIDOffset
+ 0x01));
2157 data2
= data2
& LineCompareOff
;
2160 set_reg1(P3c4
, 0x0F, data
);
2162 data
= get_reg1(P3c4
, 0x21);
2164 if (ModeType
== 0x00)
2166 else if (ModeType
<= 0x02)
2170 set_reg1(P3c4
, 0x21, data
);
2174 static void set_interlace(unsigned long ROMAddr
, u16 ModeNo
)
2179 Temp
= (unsigned long) get_reg1(P3d4
, 0x01);
2185 else if (Temp
== 1280)
2190 Temp2
= *((u16
*) (ROMAddr
+ REFIndex
+ 0x00));
2191 Temp2
&= InterlaceMode
;
2195 set_reg1(P3d4
, 0x19, data
);
2197 Temp
= (unsigned long) get_reg1(P3d4
, 0x1A);
2198 Temp2
= (u16
) (Temp
& 0xFC);
2199 set_reg1(P3d4
, 0x1A, (u16
) Temp
);
2201 Temp
= (unsigned long) get_reg1(P3c4
, 0x0f);
2202 Temp2
= (u16
) Temp
& 0xBF;
2204 Temp2
= Temp2
| 0x40;
2205 set_reg1(P3d4
, 0x1A, (u16
) Temp2
);
2208 static void write_DAC(u16 dl
, u16 ah
, u16 al
, u16 dh
)
2229 set_reg3(P3c9
, (u16
) dh
);
2230 set_reg3(P3c9
, (u16
) bh
);
2231 set_reg3(P3c9
, (u16
) bl
);
2235 static void load_DAC(unsigned long ROMAddr
)
2242 u16
*table
= VGA_DAC
;
2244 data
= *((u16
*) (ROMAddr
+ ModeIDOffset
+ 0x01));
2245 data
= data
& DACInfoFlag
;
2262 set_reg3(P3c6
, 0xFF);
2263 set_reg3(P3c8
, 0x00);
2265 for (i
= 0; i
< j
; i
++) {
2267 for (k
= 0; k
< 3; k
++) {
2272 data2
= data2
+ 0x15;
2273 set_reg3(P3c9
, data2
);
2279 for (i
= 16; i
< 32; i
++) {
2281 for (k
= 0; k
< 3; k
++)
2282 set_reg3(P3c9
, data
);
2285 for (m
= 0; m
< 9; m
++) {
2289 for (n
= 0; n
< 3; n
++) {
2290 for (o
= 0; o
< 5; o
++) {
2295 write_DAC(dl
, ah
, al
, dh
);
2298 for (o
= 0; o
< 3; o
++) {
2303 write_DAC(dl
, ah
, al
, dh
);
2312 static void display_on(void)
2316 data
= get_reg1(P3c4
, 0x01);
2318 set_reg1(P3c4
, 0x01, data
);
2321 static int SiSSetMode(u16 ModeNo
)
2324 u16 cr30flag
, cr31flag
;
2325 unsigned long ROMAddr
= rom_vbase
;
2326 u16 BaseAddr
= (u16
) ivideo
.vga_base
;
2328 P3c4
= BaseAddr
+ 0x14;
2329 P3d4
= BaseAddr
+ 0x24;
2330 P3c0
= BaseAddr
+ 0x10;
2331 P3ce
= BaseAddr
+ 0x1e;
2332 P3c2
= BaseAddr
+ 0x12;
2333 P3ca
= BaseAddr
+ 0x1a;
2334 P3c6
= BaseAddr
+ 0x16;
2335 P3c7
= BaseAddr
+ 0x17;
2336 P3c8
= BaseAddr
+ 0x18;
2337 P3c9
= BaseAddr
+ 0x19;
2338 P3da
= BaseAddr
+ 0x2A;
2340 temp
= search_modeID(ROMAddr
, ModeNo
);
2345 temp
= check_memory_size(ROMAddr
);
2349 cr30flag
= (unsigned char) get_reg1(P3d4
, 0x30);
2350 if (((cr30flag
& 0x01) == 1) || ((cr30flag
& 0x02) == 0)) {
2351 get_mode_ptr(ROMAddr
, ModeNo
);
2352 set_seq_regs(ROMAddr
);
2353 set_misc_regs(ROMAddr
);
2354 set_crtc_regs(ROMAddr
);
2355 set_attregs(ROMAddr
);
2356 set_grc_regs(ROMAddr
);
2358 temp
= get_rate_ptr(ROMAddr
, ModeNo
);
2361 set_crt1_crtc(ROMAddr
);
2362 set_crt1_offset(ROMAddr
);
2363 set_crt1_vclk(ROMAddr
);
2364 set_vclk_state(ROMAddr
, ModeNo
);
2365 if ((ivideo
.chip_id
== SIS_Trojan
)
2366 || (ivideo
.chip_id
== SIS_Spartan
))
2367 set_crt1_FIFO2(ROMAddr
);
2369 set_crt1_FIFO(ROMAddr
);
2371 set_crt1_mode_regs(ROMAddr
, ModeNo
);
2372 if ((ivideo
.chip_id
== SIS_Trojan
)
2373 || (ivideo
.chip_id
==
2374 SIS_Spartan
)) set_interlace(ROMAddr
, ModeNo
);
2377 /* clear OnScreen */
2378 memset((char *) ivideo
.video_vbase
, 0,
2379 video_linelength
* ivideo
.video_height
);
2381 cr31flag
= (unsigned char) get_reg1(P3d4
, 0x31);
2388 static void pre_setmode(void)
2390 vgawb(CRTC_ADR
, 0x30);
2391 vgawb(CRTC_DATA
, 0x00);
2393 vgawb(CRTC_ADR
, 0x31);
2394 vgawb(CRTC_DATA
, 0x60);
2396 DPRINTK("Setting CR33 = 0x%x\n", rate_idx
& 0x0f);
2398 /* set CRT1 refresh rate */
2399 vgawb(CRTC_ADR
, 0x33);
2400 vgawb(CRTC_DATA
, rate_idx
& 0x0f);
2403 static void post_setmode(void)
2408 vgawb(CRTC_ADR
, 0x17);
2409 uTemp
= vgarb(CRTC_DATA
);
2411 vgawb(CRTC_DATA
, uTemp
);
2413 /* disable 24-bit palette RAM and Gamma correction */
2414 vgawb(SEQ_ADR
, 0x07);
2415 uTemp
= vgarb(SEQ_DATA
);
2417 vgawb(SEQ_DATA
, uTemp
);
2420 static void search_mode(const char *name
)
2427 while (sisbios_mode
[i
].mode_no
!= 0) {
2428 if (!strcmp(name
, sisbios_mode
[i
].name
)) {
2435 DPRINTK("Invalid user mode : %s\n", name
);
2438 static u8
search_refresh_rate(unsigned int rate
)
2443 xres
= sisbios_mode
[mode_idx
].xres
;
2444 yres
= sisbios_mode
[mode_idx
].yres
;
2446 while ((vrate
[i
].idx
!= 0) && (vrate
[i
].xres
<= xres
)) {
2447 if ((vrate
[i
].xres
== xres
) && (vrate
[i
].yres
== yres
)
2448 && (vrate
[i
].refresh
== rate
)) {
2449 rate_idx
= vrate
[i
].idx
;
2455 DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate
, xres
,
2463 /* ------------------ Public Routines ------------------------------- */
2466 * Get the Fixed Part of the Display
2469 static int sisfb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
2470 struct fb_info
*info
)
2472 DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con
);
2474 memset(fix
, 0, sizeof(struct fb_fix_screeninfo
));
2475 strcpy(fix
->id
, fb_info
.modename
);
2477 fix
->smem_start
= ivideo
.video_base
;
2478 if(ivideo
.video_size
> 0x800000)
2479 fix
->smem_len
= RESERVED_MEM_SIZE_8M
; /* reserved for Xserver */
2481 fix
->smem_len
= RESERVED_MEM_SIZE_4M
; /* reserved for Xserver */
2483 fix
->type
= video_type
;
2485 if (ivideo
.video_bpp
== 8)
2486 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
2488 fix
->visual
= FB_VISUAL_TRUECOLOR
;
2492 fix
->line_length
= video_linelength
;
2493 fix
->mmio_start
= ivideo
.mmio_base
;
2494 fix
->mmio_len
= MMIO_SIZE
;
2495 fix
->accel
= FB_ACCEL_SIS_GLAMOUR
;
2496 fix
->reserved
[0] = ivideo
.video_size
& 0xFFFF;
2497 fix
->reserved
[1] = (ivideo
.video_size
>> 16) & 0xFFFF;
2498 fix
->reserved
[2] = caps
; /* capabilities */
2504 * Get the User Defined Part of the Display
2507 static int sisfb_get_var(struct fb_var_screeninfo
*var
, int con
,
2508 struct fb_info
*info
)
2510 DPRINTK("sisfb: sisfb_get_var:[%d]\n", con
);
2513 memcpy(var
, &default_var
,
2514 sizeof(struct fb_var_screeninfo
));
2516 *var
= fb_display
[con
].var
;
2521 * Set the User Defined Part of the Display
2524 static int sisfb_set_var(struct fb_var_screeninfo
*var
, int con
,
2525 struct fb_info
*info
)
2528 unsigned int cols
, rows
;
2530 fb_display
[con
].var
.activate
= FB_ACTIVATE_NOW
;
2533 if (do_set_var(var
, con
== currcon
, info
)) {
2534 crtc_to_var(var
); /* return current mode to user */
2538 /* get actual setting value */
2541 /* update display of current console */
2542 sisfb_set_disp(con
, var
);
2544 if (info
->changevar
)
2545 (*info
->changevar
) (con
);
2547 if ((err
= fb_alloc_cmap(&fb_display
[con
].cmap
, 0, 0)))
2550 do_install_cmap(con
, info
);
2552 /* inform console to update struct display */
2553 cols
= sisbios_mode
[mode_idx
].cols
;
2554 rows
= sisbios_mode
[mode_idx
].rows
;
2555 vc_resize_con(rows
, cols
, fb_display
[con
].conp
->vc_num
);
2565 static int sisfb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
2566 struct fb_info
*info
)
2568 DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con
);
2571 return fb_get_cmap(cmap
, kspc
, sis_getcolreg
, info
);
2572 else if (fb_display
[con
].cmap
.len
) /* non default colormap? */
2573 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
2575 fb_copy_cmap(fb_default_cmap(video_cmap_len
),
2576 cmap
, kspc
? 0 : 2);
2584 static int sisfb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
2585 struct fb_info
*info
)
2589 if (!fb_display
[con
].cmap
.len
) { /* no colormap allocated */
2590 err
= fb_alloc_cmap(&fb_display
[con
].cmap
, video_cmap_len
, 0);
2594 if (con
== currcon
) /* current console */
2595 return fb_set_cmap(cmap
, kspc
, sis_setcolreg
, info
);
2597 fb_copy_cmap(cmap
, &fb_display
[con
].cmap
, kspc
? 0 : 1);
2602 * Pan or Wrap the Display
2605 static int sisfb_pan_display(struct fb_var_screeninfo
*var
, int con
,
2606 struct fb_info
*info
)
2608 /* not support virtual screen yet */
2612 static int sisfb_ioctl(struct inode
*inode
, struct file
*file
,
2613 unsigned int cmd
, unsigned long arg
, int con
,
2614 struct fb_info
*info
)
2618 if(!capable(CAP_SYS_RAWIO
))
2620 sis_malloc((struct sis_memreq
*) arg
);
2623 if(!capable(CAP_SYS_RAWIO
))
2625 sis_free(*(unsigned long *) arg
);
2628 sis_get_glyph((struct GlyInfo
*) arg
);
2630 case FBIOGET_HWCINFO
:
2632 unsigned long *hwc_offset
= (unsigned long *) arg
;
2634 if (caps
| HW_CURSOR_CAP
)
2635 *hwc_offset
= hwcursor_vbase
-
2636 (unsigned long) ivideo
.video_vbase
;
2648 static int sisfb_mmap(struct fb_info
*info
, struct file
*file
,
2649 struct vm_area_struct
*vma
)
2651 struct fb_var_screeninfo var
;
2652 unsigned long start
;
2656 if (vma
->vm_pgoff
> (~0UL >> PAGE_SHIFT
))
2658 off
= vma
->vm_pgoff
<< PAGE_SHIFT
;
2660 /* frame buffer memory */
2661 start
= (unsigned long) ivideo
.video_base
;
2662 len
= PAGE_ALIGN((start
& ~PAGE_MASK
) + ivideo
.video_size
);
2665 /* memory mapped io */
2667 sisfb_get_var(&var
, currcon
, info
);
2668 if (var
.accel_flags
)
2670 start
= (unsigned long) ivideo
.mmio_base
;
2671 len
= PAGE_ALIGN((start
& ~PAGE_MASK
) + MMIO_SIZE
);
2675 if ((vma
->vm_end
- vma
->vm_start
+ off
) > len
)
2678 vma
->vm_pgoff
= off
>> PAGE_SHIFT
;
2680 #if defined(__i386__)
2681 if (boot_cpu_data
.x86
> 3)
2682 pgprot_val(vma
->vm_page_prot
) |= _PAGE_PCD
;
2684 if (io_remap_page_range(vma
->vm_start
, off
,
2685 vma
->vm_end
- vma
->vm_start
,
2686 vma
->vm_page_prot
)) return -EAGAIN
;
2690 static struct fb_ops sisfb_ops
= {
2692 fb_get_fix
: sisfb_get_fix
,
2693 fb_get_var
: sisfb_get_var
,
2694 fb_set_var
: sisfb_set_var
,
2695 fb_get_cmap
: sisfb_get_cmap
,
2696 fb_set_cmap
: sisfb_set_cmap
,
2697 fb_pan_display
: sisfb_pan_display
,
2698 fb_ioctl
: sisfb_ioctl
,
2699 fb_mmap
: sisfb_mmap
,
2702 int sisfb_setup(char *options
)
2706 fb_info
.fontname
[0] = '\0';
2707 ivideo
.refresh_rate
= 0;
2709 if (!options
|| !*options
)
2712 for (this_opt
= strtok(options
, ","); this_opt
;
2713 this_opt
= strtok(NULL
, ",")) {
2717 if (!strcmp(this_opt
, "inverse")) {
2720 } else if (!strncmp(this_opt
, "font:", 5)) {
2721 strcpy(fb_info
.fontname
, this_opt
+ 5);
2722 } else if (!strncmp(this_opt
, "mode:", 5)) {
2723 search_mode(this_opt
+ 5);
2724 } else if (!strncmp(this_opt
, "vrate:", 6)) {
2725 ivideo
.refresh_rate
=
2726 simple_strtoul(this_opt
+ 6, NULL
, 0);
2727 } else if (!strncmp(this_opt
, "off", 3)) {
2730 DPRINTK("invalid parameter %s\n", this_opt
);
2735 static int sisfb_update_var(int con
, struct fb_info
*info
)
2741 * Switch Console (called by fbcon.c)
2744 static int sisfb_switch(int con
, struct fb_info
*info
)
2748 DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon
, con
);
2750 /* update colormap of current console */
2751 if (fb_display
[currcon
].cmap
.len
)
2752 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, sis_getcolreg
, info
);
2754 fb_display
[con
].var
.activate
= FB_ACTIVATE_NOW
;
2756 /* same mode, needn't change mode actually */
2758 if (!memcmp(&fb_display
[con
].var
, &fb_display
[currcon
].var
, sizeof(struct fb_var_screeninfo
)))
2766 do_set_var(&fb_display
[con
].var
, 1, info
);
2768 sisfb_set_disp(con
, &fb_display
[con
].var
);
2770 /* Install new colormap */
2771 do_install_cmap(con
, info
);
2773 cols
= sisbios_mode
[mode_idx
].cols
;
2774 rows
= sisbios_mode
[mode_idx
].rows
;
2775 vc_resize_con(rows
, cols
, fb_display
[con
].conp
->vc_num
);
2777 sisfb_update_var(con
, info
);
2783 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
2785 static void sisfb_blank(int blank
, struct fb_info
*info
)
2789 vgawb(CRTC_ADR
, 0x17);
2790 CRData
= vgarb(CRTC_DATA
);
2792 if (blank
> 0) /* turn off CRT1 */
2794 else /* turn on CRT1 */
2797 vgawb(CRTC_ADR
, 0x17);
2798 vgawb(CRTC_DATA
, CRData
);
2801 int __init
sisfb_init(void)
2803 struct pci_dev
*pdev
;
2806 unsigned char jTemp
;
2811 pci_for_each_dev(pdev
) {
2812 for (b
= dev_list
; b
->vendor
; b
++)
2814 if ((b
->vendor
== pdev
->vendor
)
2815 && (b
->device
== pdev
->device
))
2818 strcpy(fb_info
.modename
, b
->name
);
2819 ivideo
.chip_id
= pdev
->device
;
2831 ivideo
.video_base
= pdev
->resource
[0].start
& ~0x7FFFFF;
2832 ivideo
.mmio_base
= pdev
->resource
[1].start
& ~0x3FFF;
2833 ivideo
.vga_base
= (pdev
->resource
[2].start
& 0xFFFFFC) + 0x30;
2834 rom_base
= 0x000C0000;
2836 request_region(rom_base
, 32, "sisfb");
2839 vgawb(SEQ_ADR
, IND_SIS_PASSWORD
);
2840 vgawb(SEQ_DATA
, SIS_PASSWORD
);
2842 /* Enable MMIO & PCI linear address */
2843 vgawb(SEQ_ADR
, IND_SIS_PCI_ADDRESS_SET
);
2844 jTemp
= vgarb(SEQ_DATA
);
2845 jTemp
|= SIS_PCI_ADDR_ENABLE
;
2846 jTemp
|= SIS_MEM_MAP_IO_ENABLE
;
2847 vgawb(SEQ_DATA
, jTemp
);
2849 /* get video ram size by SR14 */
2850 vgawb(SEQ_ADR
, IND_SIS_DRAM_SIZE
);
2851 ivideo
.video_size
= ((int) ((vgarb(SEQ_DATA
) & 0x3f) + 1) << 20);
2854 mode_idx
= DEFAULT_MODE
; /* 0:640x480x8 */
2856 mode_no
= sisbios_mode
[mode_idx
].mode_no
;
2858 if (ivideo
.refresh_rate
!= 0)
2859 search_refresh_rate(ivideo
.refresh_rate
);
2861 if (rate_idx
== 0) {
2862 rate_idx
= sisbios_mode
[mode_idx
].rate_idx
; /* set to default refresh rate 60MHz */
2863 ivideo
.refresh_rate
= 60;
2866 ivideo
.video_bpp
= sisbios_mode
[mode_idx
].bpp
;
2867 ivideo
.video_width
= sisbios_mode
[mode_idx
].xres
;
2868 ivideo
.video_height
= sisbios_mode
[mode_idx
].yres
;
2869 video_linelength
= ivideo
.video_width
* (ivideo
.video_bpp
>> 3);
2871 if (!request_mem_region(ivideo
.video_base
, ivideo
.video_size
, "sisfb FB"))
2874 "sisfb: abort, cannot reserve video memory at 0x%lx\n",
2879 if (!request_mem_region(ivideo
.mmio_base
, MMIO_SIZE
, "sisfb MMIO"))
2882 "sisfb: abort, cannot reserve mmio memory at 0x%lx\n",
2887 ivideo
.video_vbase
= ioremap(ivideo
.video_base
, ivideo
.video_size
);
2888 ivideo
.mmio_vbase
= ioremap(ivideo
.mmio_base
, MMIO_SIZE
);
2889 rom_vbase
= (unsigned long) ioremap(rom_base
, MAX_ROM_SCAN
);
2892 "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
2893 ivideo
.video_base
, ivideo
.video_vbase
,
2894 ivideo
.video_size
/ 1024);
2895 printk(KERN_INFO
"sisfb: mode is %dx%dx%d, linelength=%d\n",
2896 ivideo
.video_width
, ivideo
.video_height
, ivideo
.video_bpp
,
2899 /* enable 2D engine */
2900 vgawb(SEQ_ADR
, IND_SIS_MODULE_ENABLE
);
2901 jTemp
= vgarb(SEQ_DATA
);
2902 jTemp
|= SIS_2D_ENABLE
;
2903 vgawb(SEQ_DATA
, jTemp
);
2907 if (SiSSetMode(mode_no
)) {
2908 DPRINTK("sisfb: set mode[0x%x]: failed\n", 0x30);
2914 crtc_to_var(&default_var
);
2916 fb_info
.changevar
= NULL
;
2918 fb_info
.fbops
= &sisfb_ops
;
2919 fb_info
.disp
= &disp
;
2920 fb_info
.switch_con
= &sisfb_switch
;
2921 fb_info
.updatevar
= &sisfb_update_var
;
2922 fb_info
.blank
= &sisfb_blank
;
2923 fb_info
.flags
= FBINFO_FLAG_DEFAULT
;
2925 sisfb_set_disp(-1, &default_var
);
2927 if (sisfb_heap_init()) {
2928 DPRINTK("sisfb: Failed to enable offscreen heap\n");
2931 /* to avoid the inversed bgcolor bug of the initial state */
2932 vc_resize_con(1, 1, 0);
2934 if (register_framebuffer(&fb_info
) < 0)
2937 ivideo
.status
= CRT1
;
2939 printk(KERN_INFO
"fb%d: %s frame buffer device\n",
2940 GET_FB_IDX(fb_info
.node
), fb_info
.modename
);
2947 static char *mode
= NULL
;
2948 static unsigned int rate
= 0;
2950 MODULE_PARM(mode
, "s");
2951 MODULE_PARM(rate
, "i");
2953 int init_module(void)
2958 ivideo
.refresh_rate
= rate
;
2965 void cleanup_module(void)
2967 unregister_framebuffer(&fb_info
);
2972 EXPORT_SYMBOL(sis_malloc
);
2973 EXPORT_SYMBOL(sis_free
);
2975 EXPORT_SYMBOL(ivideo
);