- pre2
[davej-history.git] / drivers / video / sisfb.c
blob0307995af15324f6f93a4c0d1dd32a48f0ecee7e
1 /*
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
6 *
7 * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
9 */
11 #define EXPORT_SYMTAB
12 #undef SISFBDEBUG
13 #undef CONFIG_FB_SIS_LINUXBIOS
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/errno.h>
18 #include <linux/string.h>
19 #include <linux/mm.h>
20 #include <linux/tty.h>
21 #include <linux/malloc.h>
22 #include <linux/delay.h>
23 #include <linux/fb.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>
33 #include <asm/io.h>
34 #include <asm/mtrr.h>
36 #include <video/fbcon.h>
37 #include <video/fbcon-cfb8.h>
38 #include <video/fbcon-cfb16.h>
39 #include <video/fbcon-cfb24.h>
40 #include <video/fbcon-cfb32.h>
42 /* ------------------- Constant Definitions ------------------------- */
44 #define FALSE 0
45 #define TRUE 1
47 /* Draw Function
48 #define FBIOGET_GLYPH 0x4620
49 #define FBIOGET_HWCINFO 0x4621
51 #define BR(x) (0x8200 | (x) << 2)
53 #define BITBLT 0x00000000
54 #define COLOREXP 0x00000001
55 #define ENCOLOREXP 0x00000002
56 #define MULTIPLE_SCANLINE 0x00000003
57 #define LINE 0x00000004
58 #define TRAPAZOID_FILL 0x00000005
59 #define TRANSPARENT_BITBLT 0x00000006
61 #define SRCVIDEO 0x00000000
62 #define SRCSYSTEM 0x00000010
63 #define SRCAGP 0x00000020
65 #define PATFG 0x00000000
66 #define PATPATREG 0x00000040
67 #define PATMONO 0x00000080
69 #define X_INC 0x00010000
70 #define X_DEC 0x00000000
71 #define Y_INC 0x00020000
72 #define Y_DEC 0x00000000
74 #define NOCLIP 0x00000000
75 #define NOMERGECLIP 0x04000000
76 #define CLIPENABLE 0x00040000
77 #define CLIPWITHOUTMERGE 0x04040000
79 #define OPAQUE 0x00000000
80 #define TRANSPARENT 0x00100000
82 #define DSTAGP 0x02000000
83 #define DSTVIDEO 0x02000000
85 #define LINE_STYLE 0x00800000
86 #define NO_RESET_COUNTER 0x00400000
87 #define NO_LAST_PIXEL 0x00200000
89 /* capabilities */
90 #define TURBO_QUEUE_CAP 0x80
91 #define HW_CURSOR_CAP 0x40
93 /* VGA register Offsets */
94 #define SEQ_ADR (0x14)
95 #define SEQ_DATA (0x15)
96 #define DAC_ADR (0x18)
97 #define DAC_DATA (0x19)
98 #define CRTC_ADR (0x24)
99 #define CRTC_DATA (0x25)
101 /* SiS indexed register indexes */
102 #define IND_SIS_PASSWORD (0x05)
103 #define IND_SIS_DRAM_SIZE (0x14)
104 #define IND_SIS_MODULE_ENABLE (0x1E)
105 #define IND_SIS_PCI_ADDRESS_SET (0x20)
106 #define IND_SIS_TURBOQUEUE_ADR (0x26)
107 #define IND_SIS_TURBOQUEUE_SET (0x27)
109 /* Sis register value */
110 #define SIS_PASSWORD (0x86)
112 #define SIS_2D_ENABLE (0x40)
114 #define SIS_MEM_MAP_IO_ENABLE (0x01)
115 #define SIS_PCI_ADDR_ENABLE (0x80)
117 #define MMIO_SIZE 0x20000 /* 128K MMIO capability */
118 #define MAX_ROM_SCAN 0x10000
120 #define RESERVED_MEM_SIZE_4M 0x400000 /* 4M */
121 #define RESERVED_MEM_SIZE_8M 0x800000 /* 8M */
123 /* Mode set stuff */
124 #define DEFAULT_MODE 0
126 #define ModeInfoFlag 0x07
127 #define MemoryInfoFlag 0x1E0
128 #define MemorySizeShift 0x05
129 #define ModeVGA 0x03
130 #define ModeEGA 0x02
131 #define CRT1Len 17
132 #define DoubleScanMode 0x8000
133 #define HalfDCLK 0x1000
135 #define InterlaceMode 0x80
136 #define LineCompareOff 0x400
137 #define DACInfoFlag 0x18
139 #define VCLKStartFreq 25
141 #define SIS_Glamour 0x0300
142 #define SIS_Trojan 0x6300
143 #define SIS_Spartan 0x5300
145 /* heap stuff */
146 #define OH_ALLOC_SIZE 4000
147 #define SENTINEL 0x7fffffff
149 #define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */
150 #define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */
152 /* video connection status */
153 #define VB_COMPOSITE 0x01
154 #define VB_SVIDEO 0x02
155 #define VB_SCART 0x04
156 #define VB_LCD 0x08
157 #define VB_CRT2 0x10
158 #define CRT1 0x20
159 #define VB_HDTV 0x40
161 /* ------------------- Global Variables ----------------------------- */
163 struct video_info ivideo;
165 struct GlyInfo {
166 unsigned char ch;
167 int fontwidth;
168 int fontheight;
169 u8 gmask[72];
170 int ngmask;
173 /* Supported SiS Chips list */
174 static struct board {
175 u16 vendor, device;
176 const char *name;
177 } dev_list[] = {
178 {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"},
179 {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"},
180 {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"},
181 {0, 0, NULL}
184 /* card parameters */
185 unsigned long rom_base;
186 unsigned long rom_vbase;
188 /* mode */
189 static int video_type = FB_TYPE_PACKED_PIXELS;
190 static int video_linelength;
191 static int video_cmap_len;
192 static int sisfb_off = 0;
194 static struct fb_var_screeninfo default_var = {
195 0, 0, 0, 0,
196 0, 0,
199 {0, 8, 0},
200 {0, 8, 0},
201 {0, 8, 0},
202 {0, 0, 0},
204 FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
206 FB_VMODE_NONINTERLACED,
207 {0, 0, 0, 0, 0, 0}
210 static struct display disp;
211 static struct fb_info fb_info;
213 static struct {
214 u16 blue, green, red, pad;
215 } palette[256];
217 static union {
218 #ifdef FBCON_HAS_CFB16
219 u16 cfb16[16];
220 #endif
221 #ifdef FBCON_HAS_CFB24
222 u32 cfb24[16];
223 #endif
224 #ifdef FBCON_HAS_CFB32
225 u32 cfb32[16];
226 #endif
227 } fbcon_cmap;
229 static int inverse = 0;
230 static int currcon = 0;
232 static struct display_switch sisfb_sw;
234 u8 caps = 0;
236 /* ModeSet stuff */
238 u16 P3c4, P3d4, P3c0, P3ce, P3c2, P3ca, P3c6, P3c7, P3c8, P3c9, P3da;
239 u16 CRT1VCLKLen;
240 u16 flag_clearbuffer;
241 u16 CRT1VCLKLen;
242 int ModeIDOffset, StandTable, CRT1Table, ScreenOffset;
243 int REFIndex, ModeType;
244 int VCLKData;
245 int RAMType;
247 int mode_idx = -1;
248 u8 mode_no = 0;
249 u8 rate_idx = 0;
251 static const struct _sisbios_mode {
252 char name[15];
253 u8 mode_no;
254 u16 xres;
255 u16 yres;
256 u16 bpp;
257 u16 rate_idx;
258 u16 cols;
259 u16 rows;
260 } sisbios_mode[] = {
261 {"640x480x8", 0x2E, 640, 480, 8, 1, 80, 30},
262 {"640x480x16", 0x44, 640, 480, 16, 1, 80, 30},
263 {"640x480x32", 0x62, 640, 480, 32, 1, 80, 30},
264 {"800x600x8", 0x30, 800, 600, 8, 2, 100, 37},
265 {"800x600x16", 0x47, 800, 600, 16, 2, 100, 37},
266 {"800x600x32", 0x63, 800, 600, 32, 2, 100, 37},
267 {"1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48},
268 {"1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48},
269 {"1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48},
270 {"1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64},
271 {"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64},
272 {"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64},
273 {"1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75},
274 {"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75},
275 {"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75},
276 {"1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75},
277 {"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75},
278 {"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75},
279 {"\0", 0x00, 0, 0, 0, 0, 0, 0}
282 static struct _vrate {
283 u16 idx;
284 u16 xres;
285 u16 yres;
286 u16 refresh;
287 } vrate[] = {
288 {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85},
289 {5, 640, 480, 100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200},
290 {1, 800, 600, 56}, {2, 800, 600, 60}, {3, 800, 600, 72}, {4, 800, 600, 75},
291 {5, 800, 600, 85}, {6, 800, 600, 100}, {7, 800, 600, 120}, {8, 800, 600, 160},
292 {1, 1024, 768, 43}, {2, 1024, 768, 60}, {3, 1024, 768, 70}, {4, 1024, 768, 75},
293 {5, 1024, 768, 85}, {6, 1024, 768, 100}, {7, 1024, 768, 120},
294 {1, 1280, 1024, 43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85},
295 {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75},
296 {5, 1600, 1200, 85},
297 {1, 1920, 1440, 60},
298 {0, 0, 0, 0}
301 u16 DRAMType[17][5] = {
302 {0x0C, 0x0A, 0x02, 0x40, 0x39}, {0x0D, 0x0A, 0x01, 0x40, 0x48},
303 {0x0C, 0x09, 0x02, 0x20, 0x35}, {0x0D, 0x09, 0x01, 0x20, 0x44},
304 {0x0C, 0x08, 0x02, 0x10, 0x31}, {0x0D, 0x08, 0x01, 0x10, 0x40},
305 {0x0C, 0x0A, 0x01, 0x20, 0x34}, {0x0C, 0x09, 0x01, 0x08, 0x32},
306 {0x0B, 0x08, 0x02, 0x08, 0x21}, {0x0C, 0x08, 0x01, 0x08, 0x30},
307 {0x0A, 0x08, 0x02, 0x04, 0x11}, {0x0B, 0x0A, 0x01, 0x10, 0x28},
308 {0x09, 0x08, 0x02, 0x02, 0x01}, {0x0B, 0x09, 0x01, 0x08, 0x24},
309 {0x0B, 0x08, 0x01, 0x04, 0x20}, {0x0A, 0x08, 0x01, 0x02, 0x10},
310 {0x09, 0x08, 0x01, 0x01, 0x00}
313 u16 MDA_DAC[] = {
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
316 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
317 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
320 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
321 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
324 u16 CGA_DAC[] = {
325 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
326 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
327 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
328 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
329 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
330 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
331 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
332 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
335 u16 EGA_DAC[] = {
336 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
337 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
338 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
339 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
340 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
341 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
342 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
343 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
346 u16 VGA_DAC[] = {
347 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
348 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
349 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
350 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
351 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
352 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
353 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
354 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
355 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
356 0x0B, 0x0C, 0x0D, 0x0F, 0x10
359 #ifdef CONFIG_FB_SIS_LINUXBIOS
361 #define Monitor1Sense 0x20
363 unsigned char SRegsInit[] = {
364 0x03, 0x00, 0x03, 0x00, 0x02, 0xa1, 0x00, 0x13,
365 0x2f, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x0f, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00,
367 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
368 0xa1, 0x76, 0xb2, 0xf6, 0x0d, 0x00, 0x00, 0x00,
369 0x37, 0x61, 0x80, 0x1b, 0xe1, 0x01, 0x55, 0x43,
370 0x80, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff,
371 0x8e, 0x40, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff
374 unsigned char SRegs[] = {
375 0x03, 0x01, 0x0F, 0x00, 0x0E, 0xA1, 0x02, 0x13,
376 0x3F, 0x86, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
377 0x0B, 0x0F, 0x00, 0x00, 0x4F, 0x01, 0x00, 0x00,
378 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x40, 0x00,
379 0xA1, 0xB6, 0xB2, 0xF6, 0x0D, 0x00, 0xF8, 0xF0,
380 0x37, 0x61, 0x80, 0x1B, 0xE1, 0x80, 0x55, 0x43,
381 0x80, 0x00, 0x11, 0xFF, 0x00, 0x00, 0x00, 0xFF,
382 0x8E, 0x40, 0x00, 0x00, 0x08, 0x00, 0xFF, 0xFF
385 unsigned char CRegs[] = {
386 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e,
387 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 0xe9, 0x0b, 0xdf, 0x50, 0x40, 0xe7, 0x04, 0xa3,
389 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff
390 }; // clear CR11[7]
392 unsigned char GRegs[] = {
393 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, 0x00
396 unsigned char ARegs[] = {
397 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
398 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
403 unsigned char MReg = 0x6f;
405 #endif
408 /* HEAP stuff */
410 struct OH {
411 struct OH *pohNext;
412 struct OH *pohPrev;
413 unsigned long ulOffset;
414 unsigned long ulSize;
417 struct OHALLOC {
418 struct OHALLOC *pohaNext;
419 struct OH aoh[1];
422 struct HEAP {
423 struct OH ohFree;
424 struct OH ohUsed;
425 struct OH *pohFreeList;
426 struct OHALLOC *pohaChain;
428 unsigned long ulMaxFreeSize;
431 struct HEAP heap;
432 unsigned long heap_start;
433 unsigned long heap_end;
434 unsigned long heap_size;
436 unsigned int tqueue_pos;
437 unsigned long hwcursor_vbase;
439 /* Draw Function stuff */
440 u32 command_reg;
442 /* -------------------- Macro definitions --------------------------- */
444 #ifdef SISFBDEBUG
445 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
446 #else
447 #define DPRINTK(fmt, args...)
448 #endif
450 #define vgawb(reg,data) \
451 (outb(data, ivideo.vga_base+reg))
452 #define vgaww(reg,data) \
453 (outw(data, ivideo.vga_base+reg))
454 #define vgawl(reg,data) \
455 (outl(data, ivideo.vga_base+reg))
456 #define vgarb(reg) \
457 (inb(ivideo.vga_base+reg))
459 /* ---------------------- Routine Prototype ------------------------- */
461 /* Interface used by the world */
462 int sisfb_setup(char *options);
463 static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
464 struct fb_info *info);
465 static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
466 struct fb_info *info);
467 static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
468 struct fb_info *info);
469 static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
470 struct fb_info *info);
471 static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
472 struct fb_info *info);
473 static int sisfb_ioctl(struct inode *inode, struct file *file,
474 unsigned int cmd, unsigned long arg, int con,
475 struct fb_info *info);
477 /* Interface to the low level console driver */
478 int sisfb_init(void);
479 static int sisfb_update_var(int con, struct fb_info *info);
480 static int sisfb_switch(int con, struct fb_info *info);
481 static void sisfb_blank(int blank, struct fb_info *info);
483 /* Internal routines */
484 static void crtc_to_var(struct fb_var_screeninfo *var);
485 static void sisfb_set_disp(int con, struct fb_var_screeninfo *var);
486 static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
487 unsigned *blue, unsigned *transp,
488 struct fb_info *fb_info);
489 static int sis_setcolreg(unsigned regno, unsigned red, unsigned green,
490 unsigned blue, unsigned transp,
491 struct fb_info *fb_info);
492 static void do_install_cmap(int con, struct fb_info *info);
493 static int do_set_var(struct fb_var_screeninfo *var, int isactive,
494 struct fb_info *info);
496 /* set-mode routines */
497 static void set_reg1(u16 port, u16 index, u16 data);
498 static void set_reg3(u16 port, u16 data);
499 static void set_reg4(u16 port, unsigned long data);
500 static u8 get_reg1(u16 port, u16 index);
501 static u8 get_reg2(u16 port);
502 //#ifndef CONFIG_FB_SIS_LINUXBIOS
503 static u32 get_reg3(u16 port);
504 static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo);
505 static int search_modeID(unsigned long ROMAddr, u16 ModeNo);
506 static int check_memory_size(unsigned long ROMAddr);
507 static void get_mode_ptr(unsigned long ROMAddr, u16 ModeNo);
508 static void set_seq_regs(unsigned long ROMAddr);
509 static void set_misc_regs(unsigned long ROMAddr);
510 static void set_crtc_regs(unsigned long ROMAddr);
511 static void set_attregs(unsigned long ROMAddr);
512 static void set_grc_regs(unsigned long ROMAddr);
513 static void ClearExt1Regs(void);
514 static u16 GetRefindexLength(unsigned long ROMAddr, u16 ModeNo);
515 static int get_rate_ptr(unsigned long ROMAddr, u16 ModeNo);
516 static void set_sync(unsigned long ROMAddr);
517 static void set_crt1_crtc(unsigned long ROMAddr);
518 static void set_crt1_offset(unsigned long ROMAddr);
519 static u16 get_vclk_len(unsigned long ROMAddr);
520 static void set_crt1_vclk(unsigned long ROMAddr);
521 static void set_vclk_state(unsigned long ROMAddr, u16 ModeNo);
522 static u16 calc_delay2(unsigned long ROMAddr, u16 key);
523 static u16 calc_delay(unsigned long ROMAddr, u16 key);
524 static void set_crt1_FIFO(unsigned long ROMAddr);
525 static void set_crt1_FIFO2(unsigned long ROMAddr);
526 static void set_crt1_mode_regs(unsigned long ROMAddr, u16 ModeNo);
527 static void set_interlace(unsigned long ROMAddr, u16 ModeNo);
528 //#endif
529 static void write_DAC(u16 dl, u16 ah, u16 al, u16 dh);
530 static void load_DAC(unsigned long ROMAddr);
531 static void display_on(void);
533 static int SiSSetMode(u16 ModeNo);
534 static void pre_setmode(void);
535 static void post_setmode(void);
536 static void search_mode(const char *name);
537 static u8 search_refresh_rate(unsigned int rate);
539 /* heap routines */
540 static int sisfb_heap_init(void);
541 static struct OH *poh_new_node(void);
542 static struct OH *poh_allocate(unsigned long size);
543 static struct OH *poh_free(unsigned long base);
544 static void delete_node(struct OH *poh);
545 static void insert_node(struct OH *pohList, struct OH *poh);
546 static void free_node(struct OH *poh);
548 /* ---------------------- Internal Routines ------------------------- */
550 inline static u32 RD32(unsigned char *base, s32 off)
552 return readl(base + off);
555 inline static void WR32(unsigned char *base, s32 off, u32 v)
557 writel(v, base + off);
560 inline static void WR16(unsigned char *base, s32 off, u16 v)
562 writew(v, base + off);
565 inline static void WR8(unsigned char *base, s32 off, u8 v)
567 writeb(v, base + off);
570 inline static u32 regrl(s32 off)
572 return RD32(ivideo.mmio_vbase, off);
575 inline static void regwl(s32 off, u32 v)
577 WR32(ivideo.mmio_vbase, off, v);
580 inline static void regww(s32 off, u16 v)
582 WR16(ivideo.mmio_vbase, off, v);
585 inline static void regwb(s32 off, u8 v)
587 WR8(ivideo.mmio_vbase, off, v);
591 * Get CRTC registers to set var
593 static void crtc_to_var(struct fb_var_screeninfo *var)
595 u16 VRE, VBE, VRS, VBS, VDE, VT;
596 u16 HRE, HBE, HRS, HBS, HDE, HT;
597 u8 uSRdata, uCRdata, uCRdata2, uCRdata3, uMRdata;
598 int A, B, C, D, E, F, temp;
599 double hrate, drate;
601 vgawb(SEQ_ADR, 0x6);
602 uSRdata = vgarb(SEQ_DATA);
604 if (uSRdata & 0x20)
605 var->vmode = FB_VMODE_INTERLACED;
606 else
607 var->vmode = FB_VMODE_NONINTERLACED;
609 switch ((uSRdata & 0x1c) >> 2) {
610 case 0:
611 var->bits_per_pixel = 8;
612 break;
613 case 2:
614 var->bits_per_pixel = 16;
615 break;
616 case 4:
617 var->bits_per_pixel = 32;
618 break;
621 switch (var->bits_per_pixel) {
622 case 8:
623 var->red.length = 6;
624 var->green.length = 6;
625 var->blue.length = 6;
626 video_cmap_len = 256;
627 break;
628 case 16: /* RGB 565 */
629 var->red.offset = 11;
630 var->red.length = 5;
631 var->green.offset = 5;
632 var->green.length = 6;
633 var->blue.offset = 0;
634 var->blue.length = 5;
635 var->transp.offset = 0;
636 var->transp.length = 0;
637 video_cmap_len = 16;
639 break;
640 case 24: /* RGB 888 */
641 var->red.offset = 16;
642 var->red.length = 8;
643 var->green.offset = 8;
644 var->green.length = 8;
645 var->blue.offset = 0;
646 var->blue.length = 8;
647 var->transp.offset = 0;
648 var->transp.length = 0;
649 video_cmap_len = 16;
650 break;
651 case 32:
652 var->red.offset = 16;
653 var->red.length = 8;
654 var->green.offset = 8;
655 var->green.length = 8;
656 var->blue.offset = 0;
657 var->blue.length = 8;
658 var->transp.offset = 24;
659 var->transp.length = 8;
660 video_cmap_len = 16;
661 break;
664 vgawb(SEQ_ADR, 0xa);
665 uSRdata = vgarb(SEQ_DATA);
667 vgawb(CRTC_ADR, 0x6);
668 uCRdata = vgarb(CRTC_DATA);
669 vgawb(CRTC_ADR, 0x7);
670 uCRdata2 = vgarb(CRTC_DATA);
671 VT =
672 (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x01) << 8) |
673 ((u16) (uCRdata2 & 0x20) << 4) | ((u16) (uSRdata & 0x01) <<
674 10);
675 A = VT + 2;
677 vgawb(CRTC_ADR, 0x12);
678 uCRdata = vgarb(CRTC_DATA);
679 VDE =
680 (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x02) << 7) |
681 ((u16) (uCRdata2 & 0x40) << 3) | ((u16) (uSRdata & 0x02) << 9);
682 E = VDE + 1;
684 vgawb(CRTC_ADR, 0x10);
685 uCRdata = vgarb(CRTC_DATA);
686 VRS =
687 (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x04) << 6) |
688 ((u16) (uCRdata2 & 0x80) << 2) | ((u16) (uSRdata & 0x08) << 7);
689 F = VRS + 1 - E;
691 vgawb(CRTC_ADR, 0x15);
692 uCRdata = vgarb(CRTC_DATA);
693 vgawb(CRTC_ADR, 0x9);
694 uCRdata3 = vgarb(CRTC_DATA);
695 VBS =
696 (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x08) << 5) |
697 ((u16) (uCRdata3 & 0x20) << 4) | ((u16) (uSRdata & 0x04) << 8);
699 vgawb(CRTC_ADR, 0x16);
700 uCRdata = vgarb(CRTC_DATA);
701 VBE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x10) << 4);
702 temp = VBE - ((E - 1) & 511);
703 B = (temp > 0) ? temp : (temp + 512);
705 vgawb(CRTC_ADR, 0x11);
706 uCRdata = vgarb(CRTC_DATA);
707 VRE = (uCRdata & 0x0f) | ((uSRdata & 0x20) >> 1);
708 temp = VRE - ((E + F - 1) & 31);
709 C = (temp > 0) ? temp : (temp + 32);
711 D = B - F - C;
713 var->yres = var->yres_virtual = E;
714 var->upper_margin = D;
715 var->lower_margin = F;
716 var->vsync_len = C;
718 vgawb(SEQ_ADR, 0xb);
719 uSRdata = vgarb(SEQ_DATA);
721 vgawb(CRTC_ADR, 0x0);
722 uCRdata = vgarb(CRTC_DATA);
723 HT = (uCRdata & 0xff) | ((u16) (uSRdata & 0x03) << 8);
724 A = HT + 5;
726 vgawb(CRTC_ADR, 0x1);
727 uCRdata = vgarb(CRTC_DATA);
728 HDE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x0C) << 6);
729 E = HDE + 1;
731 vgawb(CRTC_ADR, 0x4);
732 uCRdata = vgarb(CRTC_DATA);
733 HRS = (uCRdata & 0xff) | ((u16) (uSRdata & 0xC0) << 2);
734 F = HRS - E - 3;
736 vgawb(CRTC_ADR, 0x2);
737 uCRdata = vgarb(CRTC_DATA);
738 HBS = (uCRdata & 0xff) | ((u16) (uSRdata & 0x30) << 4);
740 vgawb(SEQ_ADR, 0xc);
741 uSRdata = vgarb(SEQ_DATA);
742 vgawb(CRTC_ADR, 0x3);
743 uCRdata = vgarb(CRTC_DATA);
744 vgawb(CRTC_ADR, 0x5);
745 uCRdata2 = vgarb(CRTC_DATA);
746 HBE =
747 (uCRdata & 0x1f) | ((u16) (uCRdata2 & 0x80) >> 2) |
748 ((u16) (uSRdata & 0x03) << 6);
749 HRE = (uCRdata2 & 0x1f) | ((uSRdata & 0x04) << 3);
751 temp = HBE - ((E - 1) & 255);
752 B = (temp > 0) ? temp : (temp + 256);
754 temp = HRE - ((E + F + 3) & 63);
755 C = (temp > 0) ? temp : (temp + 64);
757 D = B - F - C;
759 var->xres = var->xres_virtual = E * 8;
760 var->left_margin = D * 8;
761 var->right_margin = F * 8;
762 var->hsync_len = C * 8;
764 var->activate = FB_ACTIVATE_NOW;
766 var->sync = 0;
768 uMRdata = vgarb(0x1C);
769 if (uMRdata & 0x80)
770 var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
771 else
772 var->sync |= FB_SYNC_VERT_HIGH_ACT;
774 if (uMRdata & 0x40)
775 var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
776 else
777 var->sync |= FB_SYNC_HOR_HIGH_ACT;
779 VT += 2;
780 VT <<= 1;
781 HT = (HT + 5) * 8;
783 hrate = (double) ivideo.refresh_rate * (double) VT / 2;
784 drate = hrate * HT;
785 var->pixclock = (u32) (1E12 / drate);
788 static void sisfb_set_disp(int con, struct fb_var_screeninfo *var)
790 struct fb_fix_screeninfo fix;
791 struct display *display;
792 struct display_switch *sw;
793 u32 flags;
795 if (con >= 0)
796 display = &fb_display[con];
797 else
798 display = &disp; /* used during initialization */
800 sisfb_get_fix(&fix, con, 0);
802 display->screen_base = ivideo.video_vbase;
803 display->visual = fix.visual;
804 display->type = fix.type;
805 display->type_aux = fix.type_aux;
806 display->ypanstep = fix.ypanstep;
807 display->ywrapstep = fix.ywrapstep;
808 display->line_length = fix.line_length;
809 display->next_line = fix.line_length;
810 /*display->can_soft_blank = 1; */
811 display->can_soft_blank = 0;
812 display->inverse = inverse;
813 display->var = *var;
815 save_flags(flags);
816 switch (ivideo.video_bpp) {
817 #ifdef FBCON_HAS_CFB8
818 case 8:
819 sw = &fbcon_cfb8;
820 break;
821 #endif
823 #ifdef FBCON_HAS_CFB16
824 case 15:
825 case 16:
826 sw = &fbcon_cfb16;
827 display->dispsw_data = fbcon_cmap.cfb16;
828 break;
829 #endif
831 #ifdef FBCON_HAS_CFB24
832 case 24:
833 sw = &fbcon_cfb24;
834 display->dispsw_data = fbcon_cmap.cfb24;
835 break;
836 #endif
838 #ifdef FBCON_HAS_CFB32
839 case 32:
840 sw = &fbcon_cfb32;
841 display->dispsw_data = fbcon_cmap.cfb32;
842 break;
843 #endif
845 default:
846 sw = &fbcon_dummy;
847 return;
849 memcpy(&sisfb_sw, sw, sizeof(*sw));
850 display->dispsw = &sisfb_sw;
851 restore_flags(flags);
853 display->scrollmode = SCROLL_YREDRAW;
854 sisfb_sw.bmove = fbcon_redraw_bmove;
858 * Read a single color register and split it into colors/transparent.
859 * Return != 0 for invalid regno.
862 static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
863 unsigned *transp, struct fb_info *fb_info)
865 if (regno >= video_cmap_len)
866 return 1;
868 *red = palette[regno].red;
869 *green = palette[regno].green;
870 *blue = palette[regno].blue;
871 *transp = 0;
872 return 0;
876 * Set a single color register. The values supplied are already
877 * rounded down to the hardware's capabilities (according to the
878 * entries in the var structure). Return != 0 for invalid regno.
881 static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
882 unsigned transp, struct fb_info *fb_info)
885 if (regno >= video_cmap_len)
886 return 1;
888 palette[regno].red = red;
889 palette[regno].green = green;
890 palette[regno].blue = blue;
892 switch (ivideo.video_bpp) {
893 #ifdef FBCON_HAS_CFB8
894 case 8:
895 vgawb(DAC_ADR, regno);
896 vgawb(DAC_DATA, red >> 10);
897 vgawb(DAC_DATA, green >> 10);
898 vgawb(DAC_DATA, blue >> 10);
899 break;
900 #endif
901 #ifdef FBCON_HAS_CFB16
902 case 15:
903 case 16:
904 fbcon_cmap.cfb16[regno] =
905 ((red & 0xf800)) |
906 ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
907 break;
908 #endif
909 #ifdef FBCON_HAS_CFB24
910 case 24:
911 red >>= 8;
912 green >>= 8;
913 blue >>= 8;
914 fbcon_cmap.cfb24[regno] =
915 (red << 16) | (green << 8) | (blue);
916 break;
917 #endif
918 #ifdef FBCON_HAS_CFB32
919 case 32:
920 red >>= 8;
921 green >>= 8;
922 blue >>= 8;
923 fbcon_cmap.cfb32[regno] =
924 (red << 16) | (green << 8) | (blue);
925 break;
926 #endif
928 return 0;
931 static void do_install_cmap(int con, struct fb_info *info)
933 if (con != currcon)
934 return;
936 if (fb_display[con].cmap.len)
937 fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info);
938 else
939 fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
940 sis_setcolreg, info);
943 static int do_set_var(struct fb_var_screeninfo *var, int isactive,
944 struct fb_info *info)
946 unsigned int htotal =
947 var->left_margin + var->xres + var->right_margin +
948 var->hsync_len;
949 unsigned int vtotal =
950 var->upper_margin + var->yres + var->lower_margin +
951 var->vsync_len;
952 double drate = 0, hrate = 0;
953 int found_mode = 0;
955 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
956 vtotal <<= 1;
957 else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
958 vtotal <<= 2;
959 else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
960 var->yres <<= 1;
963 if (!htotal || !vtotal) {
964 DPRINTK("Invalid 'var' Information!\n");
965 return 1;
968 drate = 1E12 / var->pixclock;
969 hrate = drate / htotal;
970 ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
972 mode_idx = 0;
973 while ((sisbios_mode[mode_idx].mode_no != 0)
974 && (sisbios_mode[mode_idx].xres <= var->xres)) {
975 if ((sisbios_mode[mode_idx].xres == var->xres)
976 && (sisbios_mode[mode_idx].yres == var->yres)
977 && (sisbios_mode[mode_idx].bpp == var->bits_per_pixel)) {
978 mode_no = sisbios_mode[mode_idx].mode_no;
979 found_mode = 1;
980 break;
982 mode_idx++;
985 if (!found_mode) {
986 printk("sisfb does not support mode %dx%d-%d\n", var->xres,
987 var->yres, var->bits_per_pixel);
988 return 1;
991 if (search_refresh_rate(ivideo.refresh_rate) == 0) {
992 /* not supported rate */
993 rate_idx = sisbios_mode[mode_idx].rate_idx;
994 ivideo.refresh_rate = 60;
997 if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
998 pre_setmode();
1000 if (SiSSetMode(mode_no)) {
1001 DPRINTK("sisfb: set mode[0x%x]: failed\n",
1002 mode_no);
1003 return 1;
1006 post_setmode();
1008 ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
1009 ivideo.video_width = sisbios_mode[mode_idx].xres;
1010 ivideo.video_height = sisbios_mode[mode_idx].yres;
1011 video_linelength =
1012 ivideo.video_width * (ivideo.video_bpp >> 3);
1014 DPRINTK("Current Mode: %dx%d-%d line_length=%d\n",
1015 ivideo.video_width, ivideo.video_height,
1016 ivideo.video_bpp, video_linelength);
1019 return 0;
1022 /* ---------------------- Draw Funtions ----------------------------- */
1024 static void sis_get_glyph(struct GlyInfo *gly)
1026 struct display *p = &fb_display[currcon];
1027 u16 c;
1028 u8 *cdat;
1029 int widthb;
1030 u8 *gbuf = gly->gmask;
1031 int size;
1034 gly->fontheight = fontheight(p);
1035 gly->fontwidth = fontwidth(p);
1036 widthb = (fontwidth(p) + 7) / 8;
1038 c = gly->ch & p->charmask;
1039 if (fontwidth(p) <= 8)
1040 cdat = p->fontdata + c * fontheight(p);
1041 else
1042 cdat = p->fontdata + (c * fontheight(p) << 1);
1044 size = fontheight(p) * widthb;
1045 memcpy(gbuf, cdat, size);
1046 gly->ngmask = size;
1050 /* ---------------------- HEAP Routines ----------------------------- */
1053 * Heap Initialization
1056 static int sisfb_heap_init(void)
1058 struct OH *poh;
1059 u8 jTemp, tq_state;
1061 if (ivideo.video_size > 0x800000)
1062 /* video ram is large than 8M */
1063 heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M;
1064 else
1065 heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M;
1067 heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
1068 heap_size = heap_end - heap_start;
1071 /* Setting for Turbo Queue */
1072 if (heap_size >= TURBO_QUEUE_AREA_SIZE) {
1073 tqueue_pos =
1074 (ivideo.video_size -
1075 TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
1076 jTemp = (u8) (tqueue_pos & 0xff);
1077 vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET);
1078 tq_state = vgarb(SEQ_DATA);
1079 tq_state |= 0xf0;
1080 tq_state &= 0xfc;
1081 tq_state |= (u8) (tqueue_pos >> 8);
1082 vgawb(SEQ_DATA, tq_state);
1083 vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR);
1084 vgawb(SEQ_DATA, jTemp);
1086 caps |= TURBO_QUEUE_CAP;
1088 heap_end -= TURBO_QUEUE_AREA_SIZE;
1089 heap_size -= TURBO_QUEUE_AREA_SIZE;
1092 /* Setting for HW cursor(4K) */
1093 if (heap_size >= HW_CURSOR_AREA_SIZE) {
1094 heap_end -= HW_CURSOR_AREA_SIZE;
1095 heap_size -= HW_CURSOR_AREA_SIZE;
1096 hwcursor_vbase = heap_end;
1098 caps |= HW_CURSOR_CAP;
1101 heap.pohaChain = NULL;
1102 heap.pohFreeList = NULL;
1104 poh = poh_new_node();
1106 if (poh == NULL)
1107 return 1;
1109 /* The first node describles the entire heap size */
1110 poh->pohNext = &heap.ohFree;
1111 poh->pohPrev = &heap.ohFree;
1112 poh->ulSize = heap_end - heap_start + 1;
1113 poh->ulOffset = heap_start - (unsigned long) ivideo.video_vbase;
1115 DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n",
1116 (char *) heap_start, (char *) heap_end,
1117 (unsigned int) poh->ulSize / 1024);
1119 DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n",
1120 (unsigned int) poh->ulOffset, (unsigned int) poh->ulSize / 1024);
1122 /* The second node in our free list sentinel */
1123 heap.ohFree.pohNext = poh;
1124 heap.ohFree.pohPrev = poh;
1125 heap.ohFree.ulSize = 0;
1126 heap.ulMaxFreeSize = poh->ulSize;
1128 /* Initialize the discardable list */
1129 heap.ohUsed.pohNext = &heap.ohUsed;
1130 heap.ohUsed.pohPrev = &heap.ohUsed;
1131 heap.ohUsed.ulSize = SENTINEL;
1133 return 0;
1137 * Allocates a basic memory unit in which we'll pack our data structures.
1140 static struct OH *poh_new_node(void)
1142 int i;
1143 unsigned long cOhs;
1144 struct OHALLOC *poha;
1145 struct OH *poh;
1147 if (heap.pohFreeList == NULL) {
1148 poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
1150 poha->pohaNext = heap.pohaChain;
1151 heap.pohaChain = poha;
1153 cOhs =
1154 (OH_ALLOC_SIZE -
1155 sizeof(struct OHALLOC)) / sizeof(struct OH) + 1;
1157 poh = &poha->aoh[0];
1158 for (i = cOhs - 1; i != 0; i--) {
1159 poh->pohNext = poh + 1;
1160 poh = poh + 1;
1163 poh->pohNext = NULL;
1164 heap.pohFreeList = &poha->aoh[0];
1167 poh = heap.pohFreeList;
1168 heap.pohFreeList = poh->pohNext;
1170 return (poh);
1174 * Allocates space, return NULL when failed
1177 static struct OH *poh_allocate(unsigned long size)
1179 struct OH *pohThis;
1180 struct OH *pohRoot;
1181 int bAllocated = 0;
1183 if (size > heap.ulMaxFreeSize) {
1184 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
1185 (unsigned int) size / 1024);
1186 return (NULL);
1189 pohThis = heap.ohFree.pohNext;
1191 while (pohThis != &heap.ohFree) {
1192 if (size <= pohThis->ulSize) {
1193 bAllocated = 1;
1194 break;
1196 pohThis = pohThis->pohNext;
1199 if (!bAllocated) {
1200 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
1201 (unsigned int) size / 1024);
1202 return (NULL);
1205 if (size == pohThis->ulSize) {
1206 pohRoot = pohThis;
1207 delete_node(pohThis);
1208 } else {
1209 pohRoot = poh_new_node();
1211 if (pohRoot == NULL) {
1212 return (NULL);
1215 pohRoot->ulOffset = pohThis->ulOffset;
1216 pohRoot->ulSize = size;
1218 pohThis->ulOffset += size;
1219 pohThis->ulSize -= size;
1222 heap.ulMaxFreeSize -= size;
1224 pohThis = &heap.ohUsed;
1225 insert_node(pohThis, pohRoot);
1227 return (pohRoot);
1231 * To remove a node from a list.
1234 static void delete_node(struct OH *poh)
1236 struct OH *pohPrev;
1237 struct OH *pohNext;
1240 pohPrev = poh->pohPrev;
1241 pohNext = poh->pohNext;
1243 pohPrev->pohNext = pohNext;
1244 pohNext->pohPrev = pohPrev;
1246 return;
1250 * To insert a node into a list.
1253 static void insert_node(struct OH *pohList, struct OH *poh)
1255 struct OH *pohTemp;
1257 pohTemp = pohList->pohNext;
1259 pohList->pohNext = poh;
1260 pohTemp->pohPrev = poh;
1262 poh->pohPrev = pohList;
1263 poh->pohNext = pohTemp;
1267 * Frees an off-screen heap allocation.
1270 static struct OH *poh_free(unsigned long base)
1273 struct OH *pohThis;
1274 struct OH *pohFreed;
1275 struct OH *pohPrev;
1276 struct OH *pohNext;
1277 unsigned long ulUpper;
1278 unsigned long ulLower;
1279 int foundNode = 0;
1281 pohFreed = heap.ohUsed.pohNext;
1283 while (pohFreed != &heap.ohUsed) {
1284 if (pohFreed->ulOffset == base) {
1285 foundNode = 1;
1286 break;
1289 pohFreed = pohFreed->pohNext;
1292 if (!foundNode)
1293 return (NULL);
1295 heap.ulMaxFreeSize += pohFreed->ulSize;
1297 pohPrev = pohNext = NULL;
1298 ulUpper = pohFreed->ulOffset + pohFreed->ulSize;
1299 ulLower = pohFreed->ulOffset;
1301 pohThis = heap.ohFree.pohNext;
1303 while (pohThis != &heap.ohFree) {
1304 if (pohThis->ulOffset == ulUpper) {
1305 pohNext = pohThis;
1307 else if ((pohThis->ulOffset + pohThis->ulSize) ==
1308 ulLower) {
1309 pohPrev = pohThis;
1311 pohThis = pohThis->pohNext;
1314 delete_node(pohFreed);
1316 if (pohPrev && pohNext) {
1317 pohPrev->ulSize += (pohFreed->ulSize + pohNext->ulSize);
1318 delete_node(pohNext);
1319 free_node(pohFreed);
1320 free_node(pohNext);
1321 return (pohPrev);
1324 if (pohPrev) {
1325 pohPrev->ulSize += pohFreed->ulSize;
1326 free_node(pohFreed);
1327 return (pohPrev);
1330 if (pohNext) {
1331 pohNext->ulSize += pohFreed->ulSize;
1332 pohNext->ulOffset = pohFreed->ulOffset;
1333 free_node(pohFreed);
1334 return (pohNext);
1337 insert_node(&heap.ohFree, pohFreed);
1339 return (pohFreed);
1343 * Frees our basic data structure allocation unit by adding it to a free
1344 * list.
1347 static void free_node(struct OH *poh)
1349 if (poh == NULL) {
1350 return;
1353 poh->pohNext = heap.pohFreeList;
1354 heap.pohFreeList = poh;
1356 return;
1359 void sis_malloc(struct sis_memreq *req)
1361 struct OH *poh;
1363 poh = poh_allocate(req->size);
1365 if (poh == NULL) {
1366 req->offset = 0;
1367 req->size = 0;
1368 DPRINTK("sisfb: VMEM Allocation Failed\n");
1369 } else {
1370 DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n",
1371 (char *) (poh->ulOffset +
1372 (unsigned long) ivideo.video_vbase));
1374 req->offset = poh->ulOffset;
1375 req->size = poh->ulSize;
1380 void sis_free(unsigned long base)
1382 struct OH *poh;
1384 poh = poh_free(base);
1386 if (poh == NULL) {
1387 DPRINTK("sisfb: poh_free() failed at base 0x%x\n",
1388 (unsigned int) base);
1395 /* ---------------------- SetMode Routines -------------------------- */
1397 static void set_reg1(u16 port, u16 index, u16 data)
1399 outb((u8) (index & 0xff), port);
1400 port++;
1401 outb((u8) (data & 0xff), port);
1404 static void set_reg3(u16 port, u16 data)
1406 outb((u8) (data & 0xff), port);
1409 static void set_reg4(u16 port, unsigned long data)
1411 outl((u32) (data & 0xffffffff), port);
1414 static u8 get_reg1(u16 port, u16 index)
1416 u8 data;
1418 outb((u8) (index & 0xff), port);
1419 port += 1;
1420 data = inb(port);
1421 return (data);
1424 static u8 get_reg2(u16 port)
1426 u8 data;
1428 data = inb(port);
1430 return (data);
1433 static u32 get_reg3(u16 port)
1435 u32 data;
1437 data = inl(port);
1438 return (data);
1441 static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo)
1443 unsigned char ModeID;
1444 u16 modeidlength;
1445 u16 usModeIDOffset;
1446 unsigned short PreviousWord,CurrentWord;
1448 return(10);
1450 modeidlength=0;
1451 usModeIDOffset=*((unsigned short *)(ROMAddr+0x20A)); // Get EModeIDTable
1453 CurrentWord=*((unsigned short *)(ROMAddr+usModeIDOffset)); // Offset 0x20A
1454 PreviousWord=*((unsigned short *)(ROMAddr+usModeIDOffset-2)); // Offset 0x20A
1455 while((CurrentWord!=0x2E07)||(PreviousWord!=0x0801))
1457 modeidlength++;
1458 usModeIDOffset=usModeIDOffset+1; // 10 <= ExtStructSize
1459 CurrentWord=*((unsigned short *)(ROMAddr+usModeIDOffset));
1460 PreviousWord=*((unsigned short *)(ROMAddr+usModeIDOffset-2));
1462 modeidlength++;
1464 return(modeidlength);
1467 static int search_modeID(unsigned long ROMAddr, u16 ModeNo)
1469 unsigned char ModeID;
1470 u16 usIDLength;
1471 unsigned int count = 0;
1473 ModeIDOffset = *((u16 *) (ROMAddr + 0x20A));
1474 ModeID = *((unsigned char *) (ROMAddr + ModeIDOffset));
1475 usIDLength = get_modeID_length(ROMAddr, ModeNo);
1476 while (ModeID != 0xff && ModeID != ModeNo) {
1477 ModeIDOffset = ModeIDOffset + usIDLength;
1478 ModeID = *((unsigned char *) (ROMAddr + ModeIDOffset));
1479 if (count++ >= 0xff)
1480 break;
1482 if (ModeID == 0xff)
1483 return (FALSE);
1484 else
1485 return (TRUE);
1488 static int check_memory_size(unsigned long ROMAddr)
1490 u16 memorysize;
1491 u16 modeflag;
1492 u16 temp;
1494 modeflag = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
1495 ModeType = modeflag & ModeInfoFlag;
1497 memorysize = modeflag & MemoryInfoFlag;
1498 memorysize = memorysize >> MemorySizeShift;
1499 memorysize++;
1501 temp = get_reg1(P3c4, 0x14);
1502 temp = temp & 0x3F;
1503 temp++;
1505 if (temp < memorysize)
1506 return (FALSE);
1507 else
1508 return (TRUE);
1511 static void get_mode_ptr(unsigned long ROMAddr, u16 ModeNo)
1513 unsigned char index;
1515 StandTable = *((u16 *) (ROMAddr + 0x202));
1517 if (ModeNo <= 13)
1518 index = *((unsigned char *) (ROMAddr + ModeIDOffset + 0x03));
1519 else {
1520 if (ModeType <= 0x02)
1521 index = 0x1B;
1522 else
1523 index = 0x0F;
1526 StandTable = StandTable + 64 * index;
1530 static void set_seq_regs(unsigned long ROMAddr)
1532 unsigned char SRdata;
1533 u16 i;
1535 #ifdef CONFIG_FB_SIS_LINUXBIOS
1536 SRdata = SRegs[0x01];
1537 #else
1538 set_reg1(P3c4, 0x00, 0x03);
1539 StandTable = StandTable + 0x05;
1540 SRdata = *((unsigned char *) (ROMAddr + StandTable));
1541 #endif
1543 SRdata = SRdata | 0x20;
1544 set_reg1(P3c4, 0x01, SRdata);
1547 for (i = 02; i <= 04; i++) {
1548 #ifdef CONFIG_FB_SIS_LINUXBIOS
1549 SRdata = SRegs[i];
1550 #else
1551 StandTable++;
1552 SRdata = *((unsigned char *) (ROMAddr + StandTable));
1553 #endif
1554 set_reg1(P3c4, i, SRdata);
1558 static void set_misc_regs(unsigned long ROMAddr)
1560 #ifdef CONFIG_FB_SIS_LINUXBIOS
1561 set_reg3(P3c2, 0x23);
1562 #else
1563 unsigned char Miscdata;
1565 StandTable++;
1566 Miscdata = *((unsigned char *) (ROMAddr + StandTable));
1567 set_reg3(P3c2, Miscdata);
1568 #endif
1571 static void set_crtc_regs(unsigned long ROMAddr)
1573 unsigned char CRTCdata;
1574 u16 i;
1576 CRTCdata = (unsigned char) get_reg1(P3d4, 0x11);
1577 #ifndef CONFIG_FB_SIS_LINUXBIOS
1578 CRTCdata = CRTCdata & 0x7f;
1579 #endif
1580 set_reg1(P3d4, 0x11, CRTCdata);
1582 for (i = 0; i <= 0x18; i++) {
1583 #ifdef CONFIG_FB_SIS_LINUXBIOS
1584 set_reg1(P3d4, i, CRegs[i]);
1585 #else
1586 StandTable++;
1587 CRTCdata = *((unsigned char *) (ROMAddr + StandTable));
1588 set_reg1(P3d4, i, CRTCdata);
1589 #endif
1593 static void set_attregs(unsigned long ROMAddr)
1595 unsigned char ARdata;
1596 u16 i;
1598 for (i = 0; i <= 0x13; i++) {
1599 #ifdef CONFIG_FB_SIS_LINUXBIOS
1600 get_reg2(P3da);
1601 set_reg3(P3c0, i);
1602 set_reg3(P3c0, ARegs[i]);
1603 #else
1604 StandTable++;
1605 ARdata = *((unsigned char *) (ROMAddr + StandTable));
1607 get_reg2(P3da);
1608 set_reg3(P3c0, i);
1609 set_reg3(P3c0, ARdata);
1610 #endif
1613 get_reg2(P3da);
1614 set_reg3(P3c0, 0x14);
1615 set_reg3(P3c0, 0x00);
1616 get_reg2(P3da);
1617 set_reg3(P3c0, 0x20);
1620 static void set_grc_regs(unsigned long ROMAddr)
1622 unsigned char GRdata;
1623 u16 i;
1625 for (i = 0; i <= 0x08; i++) {
1626 #ifdef CONFIG_FB_SIS_LINUXBIOS
1627 set_reg1(P3ce, i, GRegs[i]);
1628 #else
1629 StandTable++;
1630 GRdata = *((unsigned char *) (ROMAddr + StandTable));
1631 set_reg1(P3ce, i, GRdata);
1632 #endif
1635 #ifndef CONFIG_FB_SIS_LINUXBIOS
1636 if (ModeType > ModeVGA) {
1637 GRdata = (unsigned char) get_reg1(P3ce, 0x05);
1638 GRdata = GRdata & 0xBF;
1639 set_reg1(P3ce, 0x05, GRdata);
1641 #endif
1644 static void ClearExt1Regs(void)
1646 u16 i;
1648 for (i = 0x0A; i <= 0x0E; i++)
1649 set_reg1(P3c4, i, 0x00);
1652 static u16 GetRefindexLength(unsigned long ROMAddr, u16 ModeNo)
1654 unsigned char ModeID;
1655 unsigned char temp;
1656 u16 refindexlength;
1657 u16 usModeIDOffset;
1658 u16 usREFIndex;
1659 u16 usIDLength;
1661 usModeIDOffset = *((u16 *) (ROMAddr + 0x20A));
1662 ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset));
1663 usIDLength = get_modeID_length(ROMAddr, ModeNo);
1664 while (ModeID != 0x40) {
1665 usModeIDOffset = usModeIDOffset + usIDLength;
1666 ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset));
1669 refindexlength = 1;
1670 usREFIndex = *((u16 *) (ROMAddr + usModeIDOffset + 0x04));
1671 usREFIndex++;
1672 temp = *((unsigned char *) (ROMAddr + usREFIndex));
1673 while (temp != 0xFF) {
1674 refindexlength++;
1675 usREFIndex++;
1676 temp = *((unsigned char *) (ROMAddr + usREFIndex));
1678 return (refindexlength);
1681 static int get_rate_ptr(unsigned long ROMAddr, u16 ModeNo)
1683 short index;
1684 u16 temp;
1685 u16 ulRefIndexLength;
1687 if (ModeNo < 0x14)
1688 return (FALSE);
1690 index = get_reg1(P3d4, 0x33);
1691 index = index & 0x0F;
1692 if (index != 0)
1693 index--;
1695 REFIndex = *((u16 *) (ROMAddr + ModeIDOffset + 0x04));
1697 ulRefIndexLength = GetRefindexLength(ROMAddr, ModeNo);
1699 do {
1700 temp = *((u16 *) (ROMAddr + REFIndex));
1701 if (temp == 0xFFFF)
1702 break;
1703 temp = temp & ModeInfoFlag;
1704 if (temp < ModeType)
1705 break;
1707 REFIndex = REFIndex + ulRefIndexLength;
1708 index--;
1709 } while (index >= 0);
1711 REFIndex = REFIndex - ulRefIndexLength;
1712 return (TRUE);
1715 static void set_sync(unsigned long ROMAddr)
1717 #ifdef CONFIG_FB_SIS_LINUXBIOS
1718 set_reg3(P3c2, MReg);
1719 #else
1720 u16 sync;
1721 u16 temp;
1723 sync = *((u16 *) (ROMAddr + REFIndex));
1724 sync = sync & 0xC0;
1725 temp = 0x2F;
1726 temp = temp | sync;
1727 set_reg3(P3c2, temp);
1728 #endif
1731 static void set_crt1_crtc(unsigned long ROMAddr)
1733 #ifdef CONFIG_FB_SIS_LINUXBIOS
1734 unsigned char data;
1735 u16 i;
1737 data = (unsigned char) get_reg1(P3d4, 0x11);
1738 data = data & 0x7F;
1739 set_reg1(P3d4, 0x11, data);
1741 for (i = 0; i <= 0x07; i++)
1742 set_reg1(P3d4, i, CRegs[i]);
1743 for (i = 0x10; i <= 0x12; i++)
1744 set_reg1(P3d4, i, CRegs[i]);
1745 for (i = 0x15; i <= 0x16; i++)
1746 set_reg1(P3d4, i, CRegs[i]);
1747 for (i = 0x0A; i <= 0x0C; i++)
1748 set_reg1(P3c4, i, SRegs[i]);
1750 data = SRegs[0x0E] & 0xE0;
1751 set_reg1(P3c4, 0x0E, data);
1753 set_reg1(P3d4, 0x09, CRegs[0x09]);
1754 #else
1755 unsigned char index;
1756 unsigned char data;
1757 u16 i;
1759 index = *((unsigned char *) (ROMAddr + REFIndex + 0x02));
1760 CRT1Table = *((u16 *) (ROMAddr + 0x204));
1761 CRT1Table = CRT1Table + index * CRT1Len;
1763 data = (unsigned char) get_reg1(P3d4, 0x11);
1764 data = data & 0x7F;
1765 set_reg1(P3d4, 0x11, data);
1767 CRT1Table--;
1768 for (i = 0; i <= 0x05; i++) {
1769 CRT1Table++;
1770 data = *((unsigned char *) (ROMAddr + CRT1Table));
1771 set_reg1(P3d4, i, data);
1773 for (i = 0x06; i <= 0x07; i++) {
1774 CRT1Table++;
1775 data = *((unsigned char *) (ROMAddr + CRT1Table));
1776 set_reg1(P3d4, i, data);
1778 for (i = 0x10; i <= 0x12; i++) {
1779 CRT1Table++;
1780 data = *((unsigned char *) (ROMAddr + CRT1Table));
1781 set_reg1(P3d4, i, data);
1783 for (i = 0x15; i <= 0x16; i++) {
1784 CRT1Table++;
1785 data = *((unsigned char *) (ROMAddr + CRT1Table));
1786 set_reg1(P3d4, i, data);
1788 for (i = 0x0A; i <= 0x0C; i++) {
1789 CRT1Table++;
1790 data = *((unsigned char *) (ROMAddr + CRT1Table));
1791 set_reg1(P3c4, i, data);
1794 CRT1Table++;
1795 data = *((unsigned char *) (ROMAddr + CRT1Table));
1796 data = data & 0xE0;
1797 set_reg1(P3c4, 0x0E, data);
1799 data = (unsigned char) get_reg1(P3d4, 0x09);
1800 data = data & 0xDF;
1801 i = *((unsigned char *) (ROMAddr + CRT1Table));
1802 i = i & 0x01;
1803 i = i << 5;
1804 data = data | i;
1805 i = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
1806 i = i & DoubleScanMode;
1807 if (i)
1808 data = data | 0x80;
1809 set_reg1(P3d4, 0x09, data);
1811 if (ModeType > 0x03)
1812 set_reg1(P3d4, 0x14, 0x4F);
1813 #endif
1817 static void set_crt1_offset(unsigned long ROMAddr)
1819 #ifdef CONFIG_FB_SIS_LINUXBIOS
1820 set_reg1(P3c4, 0x0E, SRegs[0x0E]);
1821 set_reg1(P3c4, 0x10, SRegs[0x10]);
1822 #else
1823 u16 temp, ah, al;
1824 u16 temp2, i;
1825 u16 DisplayUnit;
1827 temp = *((unsigned char *) (ROMAddr + ModeIDOffset + 0x03));
1828 temp = temp >> 4;
1829 ScreenOffset = *((u16 *) (ROMAddr + 0x206));
1830 temp = *((unsigned char *) (ROMAddr + ScreenOffset + temp));
1832 temp2 = *((u16 *) (ROMAddr + REFIndex + 0x00));
1833 temp2 = temp2 & InterlaceMode;
1834 if (temp2)
1835 temp = temp << 1;
1836 temp2 = ModeType - ModeEGA;
1837 switch (temp2) {
1838 case 0:
1839 temp2 = 1;
1840 break;
1841 case 1:
1842 temp2 = 2;
1843 break;
1844 case 2:
1845 temp2 = 4;
1846 break;
1847 case 3:
1848 temp2 = 4;
1849 break;
1850 case 4:
1851 temp2 = 6;
1852 break;
1853 case 5:
1854 temp2 = 8;
1855 break;
1857 temp = temp * temp2;
1858 DisplayUnit = temp;
1860 temp2 = temp;
1861 temp = temp >> 8;
1862 temp = temp & 0x0F;
1863 i = get_reg1(P3c4, 0x0E);
1864 i = i & 0xF0;
1865 i = i | temp;
1866 set_reg1(P3c4, 0x0E, i);
1868 temp = (unsigned char) temp2;
1869 temp = temp & 0xFF;
1870 set_reg1(P3d4, 0x13, temp);
1872 temp2 = *((u16 *) (ROMAddr + REFIndex + 0x00));
1873 temp2 = temp2 & InterlaceMode;
1874 if (temp2)
1875 DisplayUnit >>= 1;
1877 DisplayUnit = DisplayUnit << 5;
1878 ah = (DisplayUnit & 0xff00) >> 8;
1879 al = DisplayUnit & 0x00ff;
1880 if (al == 0)
1881 ah = ah + 1;
1882 else
1883 ah = ah + 2;
1884 set_reg1(P3c4, 0x10, ah);
1885 #endif
1888 static u16 get_vclk_len(unsigned long ROMAddr)
1890 u16 VCLKDataStart, vclklabel, temp;
1891 VCLKDataStart = *((u16 *) (ROMAddr + 0x208));
1892 for (temp = 0;; temp++) {
1893 vclklabel = *((u16 *) (ROMAddr + VCLKDataStart + temp));
1894 if (vclklabel == VCLKStartFreq) {
1895 temp = temp + 2;
1896 return (temp);
1899 return (0);
1902 static void set_crt1_vclk(unsigned long ROMAddr)
1904 u16 i;
1906 #ifndef CONFIG_FB_SIS_LINUXBIOS
1907 unsigned char index, data;
1909 index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
1910 index &= 0x03F;
1911 CRT1VCLKLen = get_vclk_len(ROMAddr);
1912 data = index * CRT1VCLKLen;
1913 VCLKData = *((u16 *) (ROMAddr + 0x208));
1914 VCLKData = VCLKData + data;
1915 #endif
1917 set_reg1(P3c4, 0x31, 0);
1919 for (i = 0x2B; i <= 0x2C; i++) {
1920 #ifdef CONFIG_FB_SIS_LINUXBIOS
1921 set_reg1(P3c4, i, SRegs[i]);
1922 #else
1923 data = *((unsigned char *) (ROMAddr + VCLKData));
1924 set_reg1(P3c4, i, data);
1925 VCLKData++;
1926 #endif
1928 set_reg1(P3c4, 0x2D, 0x80);
1930 static void set_vclk_state(unsigned long ROMAddr, u16 ModeNo)
1932 #ifdef CONFIG_FB_SIS_LINUXBIOS
1933 set_reg1(P3c4, 0x32, SRegs[0x32]);
1934 set_reg1(P3c4, 0x07, SRegs[0x07]);
1935 #else
1937 u16 data, data2;
1938 u16 VCLK;
1939 unsigned char index;
1941 index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
1942 index &= 0x3F;
1943 CRT1VCLKLen = get_vclk_len(ROMAddr);
1944 data = index * CRT1VCLKLen;
1945 VCLKData = *((u16 *) (ROMAddr + 0x208));
1946 VCLKData = VCLKData + data + (CRT1VCLKLen - 2);
1948 VCLK = *((u16 *) (ROMAddr + VCLKData));
1949 if (ModeNo <= 0x13)
1950 VCLK = 0;
1952 data = get_reg1(P3c4, 0x07);
1953 data = data & 0x7B;
1954 if (VCLK >= 150)
1955 data = data | 0x80;
1956 set_reg1(P3c4, 0x07, data);
1958 data = get_reg1(P3c4, 0x32);
1959 data = data & 0xD7;
1960 if (VCLK >= 150)
1961 data = data | 0x08;
1962 set_reg1(P3c4, 0x32, data);
1964 data2 = 0x03;
1965 if (VCLK > 135)
1966 data2 = 0x02;
1967 if (VCLK > 160)
1968 data2 = 0x01;
1969 if (VCLK > 260)
1970 data2 = 0x00;
1971 data = get_reg1(P3c4, 0x07);
1972 data = data & 0xFC;
1973 data = data | data2;
1974 set_reg1(P3c4, 0x07, data);
1975 #endif
1978 static u16 calc_delay2(unsigned long ROMAddr, u16 key)
1980 u16 data, index;
1981 unsigned char LatencyFactor[] = {
1982 88, 80, 78, 72, 70, 00,
1983 00, 79, 77, 71, 69, 49,
1984 88, 80, 78, 72, 70, 00,
1985 00, 72, 70, 64, 62, 44
1987 index = 0;
1988 data = get_reg1(P3c4, 0x14);
1989 if (data & 0x80)
1990 index = index + 12;
1992 data = get_reg1(P3c4, 0x15);
1993 data = (data & 0xf0) >> 4;
1994 if (data & 0x01)
1995 index = index + 6;
1997 data = data >> 1;
1998 index = index + data;
1999 data = LatencyFactor[index];
2001 return (data);
2004 static u16 calc_delay(unsigned long ROMAddr, u16 key)
2006 u16 data, data2, temp0, temp1;
2007 unsigned char ThLowA[] = {
2008 61, 3, 52, 5, 68, 7, 100, 11,
2009 43, 3, 42, 5, 54, 7, 78, 11,
2010 34, 3, 37, 5, 47, 7, 67, 11
2012 unsigned char ThLowB[] = {
2013 81, 4, 72, 6, 88, 8, 120, 12,
2014 55, 4, 54, 6, 66, 8, 90, 12,
2015 42, 4, 45, 6, 55, 8, 75, 12
2017 unsigned char ThTiming[] = { 1, 2, 2, 3, 0, 1, 1, 2 };
2019 data = get_reg1(P3c4, 0x16);
2020 data = data >> 6;
2021 data2 = get_reg1(P3c4, 0x14);
2022 data2 = (data2 >> 4) & 0x0C;
2023 data = data | data2;
2024 data = data < 1;
2025 if (key == 0) {
2026 temp0 = (u16) ThLowA[data];
2027 temp1 = (u16) ThLowA[data + 1];
2028 } else {
2029 temp0 = (u16) ThLowB[data];
2030 temp1 = (u16) ThLowB[data + 1];
2033 data2 = 0;
2034 data = get_reg1(P3c4, 0x18);
2035 if (data & 0x02)
2036 data2 = data2 | 0x01;
2037 if (data & 0x20)
2038 data2 = data2 | 0x02;
2039 if (data & 0x40)
2040 data2 = data2 | 0x04;
2042 data = temp1 * ThTiming[data2] + temp0;
2043 return (data);
2047 static void set_crt1_FIFO(unsigned long ROMAddr)
2049 u16 index, data, VCLK, data2, MCLKOffset, MCLK, colorth = 1;
2050 u16 ah, bl, A, B;
2052 index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
2053 index &= 0x3F;
2054 CRT1VCLKLen = get_vclk_len(ROMAddr);
2055 data = index * CRT1VCLKLen;
2056 VCLKData = *((u16 *) (ROMAddr + 0x208));
2057 VCLKData = VCLKData + data + (CRT1VCLKLen - 2);
2058 VCLK = *((u16 *) (ROMAddr + VCLKData));
2060 MCLKOffset = *((u16 *) (ROMAddr + 0x20C));
2061 index = get_reg1(P3c4, 0x3A);
2062 index = index & 07;
2063 MCLKOffset = MCLKOffset + index * 5;
2064 MCLK = *((unsigned char *) (ROMAddr + MCLKOffset + 0x03));
2066 data2 = ModeType - 0x02;
2067 switch (data2) {
2068 case 0:
2069 colorth = 1;
2070 break;
2071 case 1:
2072 colorth = 2;
2073 break;
2074 case 2:
2075 colorth = 4;
2076 break;
2077 case 3:
2078 colorth = 4;
2079 break;
2080 case 4:
2081 colorth = 6;
2082 break;
2083 case 5:
2084 colorth = 8;
2085 break;
2088 do {
2089 B = (calc_delay(ROMAddr, 0) * VCLK * colorth);
2090 B = B / (16 * MCLK);
2091 B++;
2093 A = (calc_delay(ROMAddr, 1) * VCLK * colorth);
2094 A = A / (16 * MCLK);
2095 A++;
2097 if (A < 4)
2098 A = 0;
2099 else
2100 A = A - 4;
2102 if (A > B)
2103 bl = A;
2104 else
2105 bl = B;
2107 bl++;
2108 if (bl > 0x13) {
2109 data = get_reg1(P3c4, 0x16);
2110 data = data >> 6;
2111 if (data != 0) {
2112 data--;
2113 data = data << 6;
2114 data2 = get_reg1(P3c4, 0x16);
2115 data2 = (data2 & 0x3f) | data;
2116 set_reg1(P3c4, 0x16, data2);
2117 } else
2118 bl = 0x13;
2120 } while (bl > 0x13);
2122 ah = bl;
2123 ah = ah << 4;
2124 ah = ah | 0x0f;
2125 set_reg1(P3c4, 0x08, ah);
2127 data = bl;
2128 data = data & 0x10;
2129 data = data << 1;
2130 data2 = get_reg1(P3c4, 0x0F);
2131 data2 = data2 & 0x9f;
2132 data2 = data2 | data;
2133 set_reg1(P3c4, 0x0F, data2);
2135 data = bl + 3;
2136 if (data > 0x0f)
2137 data = 0x0f;
2138 set_reg1(P3c4, 0x3b, 0x00);
2139 data2 = get_reg1(P3c4, 0x09);
2140 data2 = data2 & 0xF0;
2141 data2 = data2 | data;
2142 set_reg1(P3c4, 0x09, data2);
2145 static void set_crt1_FIFO2(unsigned long ROMAddr)
2147 #ifdef CONFIG_FB_SIS_LINUXBIOS
2148 set_reg1(P3c4, 0x15, SRegs[0x15]);
2150 set_reg4(0xcf8, 0x80000050);
2151 set_reg4(0xcfc, 0xc5041e04);
2153 set_reg1(P3c4, 0x08, SRegs[0x08]);
2154 set_reg1(P3c4, 0x0F, SRegs[0x0F]);
2155 set_reg1(P3c4, 0x3b, 0x00);
2156 set_reg1(P3c4, 0x09, SRegs[0x09]);
2157 #else
2159 u16 index, data, VCLK, data2, MCLKOffset, MCLK, colorth = 1;
2160 u16 ah, bl, B;
2161 unsigned long eax;
2163 index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
2164 index &= 0x3F;
2165 CRT1VCLKLen = get_vclk_len(ROMAddr);
2166 data = index * CRT1VCLKLen;
2167 VCLKData = *((u16 *) (ROMAddr + 0x208));
2168 VCLKData = VCLKData + data + (CRT1VCLKLen - 2);
2169 VCLK = *((u16 *) (ROMAddr + VCLKData));
2171 MCLKOffset = *((u16 *) (ROMAddr + 0x20C));
2172 index = get_reg1(P3c4, 0x1A);
2173 index = index & 07;
2174 MCLKOffset = MCLKOffset + index * 5;
2175 MCLK = *((u16 *) (ROMAddr + MCLKOffset + 0x03));
2177 data2 = ModeType - 0x02;
2178 switch (data2) {
2179 case 0:
2180 colorth = 1;
2181 break;
2182 case 1:
2183 colorth = 1;
2184 break;
2185 case 2:
2186 colorth = 2;
2187 break;
2188 case 3:
2189 colorth = 2;
2190 break;
2191 case 4:
2192 colorth = 3;
2193 break;
2194 case 5:
2195 colorth = 4;
2196 break;
2199 do {
2200 B = (calc_delay2(ROMAddr, 0) * VCLK * colorth);
2201 if (B % (16 * MCLK) == 0) {
2202 B = B / (16 * MCLK);
2203 bl = B + 1;
2204 } else {
2205 B = B / (16 * MCLK);
2206 bl = B + 2;
2209 if (bl > 0x13) {
2210 data = get_reg1(P3c4, 0x15);
2211 data = data & 0xf0;
2212 if (data != 0xb0) {
2213 data = data + 0x20;
2214 if (data == 0xa0)
2215 data = 0x30;
2216 data2 = get_reg1(P3c4, 0x15);
2217 data2 = (data2 & 0x0f) | data;
2218 set_reg1(P3c4, 0x15, data2);
2219 } else
2220 bl = 0x13;
2222 } while (bl > 0x13);
2224 data2 = get_reg1(P3c4, 0x15);
2225 data2 = (data2 & 0xf0) >> 4;
2226 data2 = data2 << 24;
2228 set_reg4(0xcf8, 0x80000050);
2229 eax = get_reg3(0xcfc);
2230 eax = eax & 0x0f0ffffff;
2231 eax = eax | data2;
2232 set_reg4(0xcfc, eax);
2234 ah = bl;
2235 ah = ah << 4;
2236 ah = ah | 0x0f;
2237 set_reg1(P3c4, 0x08, ah);
2239 data = bl;
2240 data = data & 0x10;
2241 data = data << 1;
2242 data2 = get_reg1(P3c4, 0x0F);
2243 data2 = data2 & 0x9f;
2244 data2 = data2 | data;
2245 set_reg1(P3c4, 0x0F, data2);
2247 data = bl + 3;
2248 if (data > 0x0f)
2249 data = 0x0f;
2250 set_reg1(P3c4, 0x3b, 0x00);
2251 data2 = get_reg1(P3c4, 0x09);
2252 data2 = data2 & 0xF0;
2253 data2 = data2 | data;
2254 set_reg1(P3c4, 0x09, data2);
2255 #endif
2258 static void set_crt1_mode_regs(unsigned long ROMAddr, u16 ModeNo)
2260 #ifdef CONFIG_FB_SIS_LINUXBIOS
2261 set_reg1(P3c4, 0x06, SRegs[0x06]);
2262 set_reg1(P3c4, 0x01, SRegs[0x01]);
2263 set_reg1(P3c4, 0x0F, SRegs[0x0F]);
2264 set_reg1(P3c4, 0x21, SRegs[0x21]);
2265 #else
2267 u16 data, data2, data3;
2269 if (ModeNo > 0x13)
2270 data = *((u16 *) (ROMAddr + REFIndex + 0x00));
2271 else
2272 data = 0;
2274 data2 = 0;
2275 if (ModeNo > 0x13)
2276 if (ModeType > 0x02) {
2277 data2 = data2 | 0x02;
2278 data3 = ModeType - ModeVGA;
2279 data3 = data3 << 2;
2280 data2 = data2 | data3;
2283 data = data & InterlaceMode;
2284 if (data)
2285 data2 = data2 | 0x20;
2286 set_reg1(P3c4, 0x06, data2);
2288 data = get_reg1(P3c4, 0x01);
2289 data = data & 0xF7;
2290 data2 = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
2291 data2 = data2 & HalfDCLK;
2292 if (data2)
2293 data = data | 0x08;
2294 set_reg1(P3c4, 0x01, data);
2296 data = get_reg1(P3c4, 0x0F);
2297 data = data & 0xF7;
2298 data2 = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
2299 data2 = data2 & LineCompareOff;
2300 if (data2)
2301 data = data | 0x08;
2302 set_reg1(P3c4, 0x0F, data);
2304 data = get_reg1(P3c4, 0x21);
2305 data = data & 0x1F;
2306 if (ModeType == 0x00)
2307 data = data | 0x60;
2308 else if (ModeType <= 0x02)
2309 data = data | 0x00;
2310 else
2311 data = data | 0xA0;
2312 set_reg1(P3c4, 0x21, data);
2313 #endif
2316 static void set_interlace(unsigned long ROMAddr, u16 ModeNo)
2318 #ifdef CONFIG_FB_SIS_LINUXBIOS
2319 set_reg1(P3d4, 0x19, CRegs[0x19]);
2320 set_reg1(P3d4, 0x1A, CRegs[0x1A]);
2321 #else
2323 unsigned long Temp;
2324 u16 data, Temp2;
2326 Temp = (unsigned long) get_reg1(P3d4, 0x01);
2327 Temp++;
2328 Temp = Temp * 8;
2330 if (Temp == 1024)
2331 data = 0x0035;
2332 else if (Temp == 1280)
2333 data = 0x0048;
2334 else
2335 data = 0x0000;
2337 Temp2 = *((u16 *) (ROMAddr + REFIndex + 0x00));
2338 Temp2 &= InterlaceMode;
2339 if (Temp2 == 0)
2340 data = 0x0000;
2342 set_reg1(P3d4, 0x19, data);
2344 Temp = (unsigned long) get_reg1(P3d4, 0x1A);
2345 Temp2 = (u16) (Temp & 0xFC);
2346 set_reg1(P3d4, 0x1A, (u16) Temp);
2348 Temp = (unsigned long) get_reg1(P3c4, 0x0f);
2349 Temp2 = (u16) Temp & 0xBF;
2350 if (ModeNo == 0x37)
2351 Temp2 = Temp2 | 0x40;
2352 set_reg1(P3d4, 0x1A, (u16) Temp2);
2353 #endif
2356 static void write_DAC(u16 dl, u16 ah, u16 al, u16 dh)
2358 u16 temp;
2359 u16 bh, bl;
2361 bh = ah;
2362 bl = al;
2363 if (dl != 0) {
2364 temp = bh;
2365 bh = dh;
2366 dh = temp;
2367 if (dl == 1) {
2368 temp = bl;
2369 bl = dh;
2370 dh = temp;
2371 } else {
2372 temp = bl;
2373 bl = bh;
2374 bh = temp;
2377 set_reg3(P3c9, (u16) dh);
2378 set_reg3(P3c9, (u16) bh);
2379 set_reg3(P3c9, (u16) bl);
2383 static void load_DAC(unsigned long ROMAddr)
2385 u16 data, data2;
2386 u16 time, i, j, k;
2387 u16 m, n, o;
2388 u16 si, di, bx, dl;
2389 u16 al, ah, dh;
2390 u16 *table = VGA_DAC;
2392 #ifndef CONFIG_FB_SIS_LINUXBIOS
2393 data = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
2394 data = data & DACInfoFlag;
2395 time = 64;
2396 if (data == 0x00)
2397 table = MDA_DAC;
2398 if (data == 0x08)
2399 table = CGA_DAC;
2400 if (data == 0x10)
2401 table = EGA_DAC;
2402 if (data == 0x18) {
2403 time = 256;
2404 table = VGA_DAC;
2406 #else
2407 time = 256;
2408 table = VGA_DAC;
2409 #endif
2411 if (time == 256)
2412 j = 16;
2413 else
2414 j = time;
2416 set_reg3(P3c6, 0xFF);
2417 set_reg3(P3c8, 0x00);
2419 for (i = 0; i < j; i++) {
2420 data = table[i];
2421 for (k = 0; k < 3; k++) {
2422 data2 = 0;
2423 if (data & 0x01)
2424 data2 = 0x2A;
2425 if (data & 0x02)
2426 data2 = data2 + 0x15;
2427 set_reg3(P3c9, data2);
2428 data = data >> 2;
2432 if (time == 256) {
2433 for (i = 16; i < 32; i++) {
2434 data = table[i];
2435 for (k = 0; k < 3; k++)
2436 set_reg3(P3c9, data);
2438 si = 32;
2439 for (m = 0; m < 9; m++) {
2440 di = si;
2441 bx = si + 0x04;
2442 dl = 0;
2443 for (n = 0; n < 3; n++) {
2444 for (o = 0; o < 5; o++) {
2445 dh = table[si];
2446 ah = table[di];
2447 al = table[bx];
2448 si++;
2449 write_DAC(dl, ah, al, dh);
2451 si = si - 2;
2452 for (o = 0; o < 3; o++) {
2453 dh = table[bx];
2454 ah = table[di];
2455 al = table[si];
2456 si--;
2457 write_DAC(dl, ah, al, dh);
2459 dl++;
2461 si = si + 5;
2466 static void display_on(void)
2468 u16 data;
2470 data = get_reg1(P3c4, 0x01);
2471 data = data & 0xDF;
2472 set_reg1(P3c4, 0x01, data);
2475 void SetMemoryClock(void)
2477 unsigned char i;
2478 int idx;
2480 u8 MCLK[] = {
2481 0x5A, 0x64, 0x80, 0x66, 0x00, // SDRAM
2482 0xB3, 0x45, 0x80, 0x83, 0x00, // SGRAM
2483 0x37, 0x61, 0x80, 0x00, 0x01, // ESDRAM
2484 0x37, 0x22, 0x80, 0x33, 0x01,
2485 0x37, 0x61, 0x80, 0x00, 0x01,
2486 0x37, 0x61, 0x80, 0x00, 0x01,
2487 0x37, 0x61, 0x80, 0x00, 0x01,
2488 0x37, 0x61, 0x80, 0x00, 0x01
2491 u8 ECLK[] = {
2492 0x54, 0x43, 0x80, 0x00, 0x01,
2493 0x53, 0x43, 0x80, 0x00, 0x01,
2494 0x55, 0x43, 0x80, 0x00, 0x01,
2495 0x52, 0x43, 0x80, 0x00, 0x01,
2496 0x3f, 0x42, 0x80, 0x00, 0x01,
2497 0x54, 0x43, 0x80, 0x00, 0x01,
2498 0x54, 0x43, 0x80, 0x00, 0x01,
2499 0x54, 0x43, 0x80, 0x00, 0x01
2502 idx = RAMType * 5;
2504 for (i = 0x28; i <= 0x2A; i++) { // Set MCLK
2505 set_reg1(P3c4, i, MCLK[idx]);
2506 idx++;
2509 idx = RAMType * 5;
2510 for (i = 0x2E; i <= 0x30; i++) { // Set ECLK
2511 set_reg1(P3c4, i, ECLK[idx]);
2512 idx++;
2516 void ClearDAC(u16 port)
2518 int i;
2520 set_reg3(P3c8, 0x00);
2521 for (i = 0; i < (256 * 3); i++)
2522 set_reg3(P3c9, 0x00);
2525 void ClearALLBuffer(void)
2527 unsigned long AdapterMemorySize;
2529 AdapterMemorySize = get_reg1(P3c4, 0x14);
2530 AdapterMemorySize = AdapterMemorySize & 0x3F;
2531 AdapterMemorySize++;
2533 memset((char *) ivideo.video_vbase, 0, AdapterMemorySize);
2536 void LongWait(void)
2538 unsigned long temp;
2540 for (temp = 1; temp > 0;) {
2541 temp = get_reg2(P3da);
2542 temp = temp & 0x08;
2544 for (; temp == 0;) {
2545 temp = get_reg2(P3da);
2546 temp = temp & 0x08;
2550 void WaitDisplay(void)
2552 unsigned short temp;
2554 for (temp = 0; temp == 0;) {
2555 temp = get_reg2(P3da);
2556 temp = temp & 0x01;
2558 for (; temp == 1;) {
2559 temp = get_reg2(P3da);
2560 temp = temp & 0x01;
2564 int TestMonitorType(unsigned short d1, unsigned short d2, unsigned short d3)
2566 unsigned short temp;
2567 set_reg3(P3c6, 0xFF);
2568 set_reg3(P3c8, 0x00);
2569 set_reg3(P3c9, d1);
2570 set_reg3(P3c9, d2);
2571 set_reg3(P3c9, d3);
2572 WaitDisplay(); //wait horizontal retrace
2573 temp = get_reg2(P3c2);
2574 if (temp & 0x10)
2575 return 1;
2576 else
2577 return 0;
2580 void SetRegANDOR(unsigned short Port, unsigned short Index,
2581 unsigned short DataAND, unsigned short DataOR)
2583 unsigned short temp1;
2584 temp1 = get_reg1(Port, Index); //part1port index 02
2585 temp1 = (temp1 & (DataAND)) | DataOR;
2586 set_reg1(Port, Index, temp1);
2590 int DetectMonitor(void)
2592 unsigned short flag1;
2593 unsigned short DAC_TEST_PARMS[3] = { 0x0F, 0x0F, 0x0F };
2594 unsigned short DAC_CLR_PARMS[3] = { 0x00, 0x00, 0x00 };
2596 flag1 = get_reg1(P3c4, 0x38); //call BridgeisOn
2597 if ((flag1 & 0x20)) {
2598 set_reg1(P3d4, 0x30, 0x41);
2601 SiSSetMode(0x2E); //set mode to 0x2E instead of 0x3
2603 ClearDAC(P3c8);
2604 ClearALLBuffer();
2606 LongWait();
2607 LongWait();
2609 flag1 = TestMonitorType(DAC_TEST_PARMS[0], DAC_TEST_PARMS[1],
2610 DAC_TEST_PARMS[2]);
2611 if (flag1 == 0) {
2612 flag1 = TestMonitorType(DAC_TEST_PARMS[0], DAC_TEST_PARMS[1],
2613 DAC_TEST_PARMS[2]);
2616 if (flag1 == 1) {
2617 SetRegANDOR(P3d4, 0x32, ~Monitor1Sense, Monitor1Sense);
2618 } else {
2619 SetRegANDOR(P3d4, 0x32, ~Monitor1Sense, 0x0);
2622 TestMonitorType(DAC_CLR_PARMS[0], DAC_CLR_PARMS[1],
2623 DAC_CLR_PARMS[2]);
2625 set_reg1(P3d4, 0x34, 0x4A);
2627 return 1;
2630 int SiSInit300(void)
2632 //unsigned long ROMAddr = rom_vbase;
2633 u16 BaseAddr = (u16) ivideo.vga_base;
2634 unsigned char i, temp, AGP;
2635 unsigned long j, k, ulTemp;
2636 unsigned char SR11, SR19, SR1A, SR21, SR22;
2637 unsigned char SR14;
2638 unsigned long Temp;
2640 P3c4 = BaseAddr + 0x14;
2641 P3d4 = BaseAddr + 0x24;
2642 P3c0 = BaseAddr + 0x10;
2643 P3ce = BaseAddr + 0x1e;
2644 P3c2 = BaseAddr + 0x12;
2645 P3ca = BaseAddr + 0x1a;
2646 P3c6 = BaseAddr + 0x16;
2647 P3c7 = BaseAddr + 0x17;
2648 P3c8 = BaseAddr + 0x18;
2649 P3c9 = BaseAddr + 0x19;
2650 P3da = BaseAddr + 0x2A;
2652 set_reg1(P3c4, 0x05, 0x86); // 1.Openkey
2654 SR14 = (unsigned char) get_reg1(P3c4, 0x14);
2655 SR19 = (unsigned char) get_reg1(P3c4, 0x19);
2656 SR1A = (unsigned char) get_reg1(P3c4, 0x1A);
2658 for (i = 0x06; i < 0x20; i++)
2659 set_reg1(P3c4, i, 0); // 2.Reset Extended register
2660 for (i = 0x21; i <= 0x27; i++)
2661 set_reg1(P3c4, i, 0); // Reset Extended register
2662 for (i = 0x31; i <= 0x3D; i++)
2663 set_reg1(P3c4, i, 0);
2664 for (i = 0x30; i <= 0x37; i++)
2665 set_reg1(P3d4, i, 0);
2667 #if 0
2668 if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan))
2669 // 3.Set Define Extended register
2670 temp = (unsigned char) SR1A;
2671 else {
2672 temp = *((unsigned char *) (ROMAddr + SoftSettingAddr));
2673 if ((temp & SoftDRAMType) == 0) {
2674 // 3.Set Define Extended register
2675 temp = (unsigned char) get_reg1(P3c4, 0x3A);
2678 #endif
2680 // 3.Set Define Extended register
2681 temp = (unsigned char) SR1A;
2683 RAMType = temp & 0x07;
2684 SetMemoryClock();
2685 for (k = 0; k < 5; k++)
2686 for (j = 0; j < 0xffff; j++)
2687 ulTemp = (unsigned long) get_reg1(P3c4, 0x05);
2689 Temp = (unsigned long) get_reg1(P3c4, 0x3C);
2690 Temp = Temp | 0x01;
2691 set_reg1(P3c4, 0x3C, (unsigned short) Temp);
2692 for (k = 0; k < 5; k++)
2693 for (j = 0; j < 0xffff; j++)
2694 Temp = (unsigned long) get_reg1(P3c4, 0x05);
2696 Temp = (unsigned long) get_reg1(P3c4, 0x3C);
2697 Temp = Temp & 0xFE;
2698 set_reg1(P3c4, 0x3C, (unsigned short) Temp);
2699 for (k = 0; k < 5; k++)
2700 for (j = 0; j < 0xffff; j++)
2701 Temp = (unsigned long) get_reg1(P3c4, 0x05);
2703 //SR07=*((unsigned char *)(ROMAddr+0xA4)); // todo
2704 set_reg1(P3c4, 0x07, SRegsInit[0x07]);
2705 #if 0
2706 if (HwDeviceExtension->jChipID == SIS_Glamour)
2707 for (i = 0x15; i <= 0x1C; i++) {
2708 temp = *((unsigned char *) (ROMAddr + 0xA5 + ((i - 0x15) * 8) + RAMType));
2709 set_reg1(P3c4, i, temp);
2711 #endif
2713 //SR1F=*((unsigned char *)(ROMAddr+0xE5));
2714 set_reg1(P3c4, 0x1F, SRegsInit[0x1F]);
2716 // Get AGP
2717 AGP = 1;
2718 temp = (unsigned char) get_reg1(P3c4, 0x3A);
2719 temp = temp & 0x30;
2720 if (temp == 0x30)
2721 // PCI
2722 AGP = 0;
2724 //SR21=*((unsigned char *)(ROMAddr+0xE6));
2725 SR21 = SRegsInit[0x21];
2726 if (AGP == 0)
2727 SR21 = SR21 & 0xEF; // PCI
2728 set_reg1(P3c4, 0x21, SR21);
2730 //SR22=*((unsigned char *)(ROMAddr+0xE7));
2731 SR22 = SRegsInit[0x22];
2732 if (AGP == 1)
2733 SR22 = SR22 & 0x20; // AGP
2734 set_reg1(P3c4, 0x22, SR22);
2736 //SR23=*((unsigned char *)(ROMAddr+0xE8));
2737 set_reg1(P3c4, 0x23, SRegsInit[0x23]);
2739 //SR24=*((unsigned char *)(ROMAddr+0xE9));
2740 set_reg1(P3c4, 0x24, SRegsInit[0x24]);
2742 //SR25=*((unsigned char *)(ROMAddr+0xEA));
2743 set_reg1(P3c4, 0x25, SRegsInit[0x25]);
2745 //SR32=*((unsigned char *)(ROMAddr+0xEB));
2746 set_reg1(P3c4, 0x32, SRegsInit[0x32]);
2748 SR11 = 0x0F;
2749 set_reg1(P3c4, 0x11, SR11);
2751 #if 0
2752 if (IF_DEF_LVDS == 1) {
2753 //LVDS
2754 temp = ExtChipLVDS;
2755 } else if (IF_DEF_TRUMPION == 1) {
2756 //Trumpion
2757 temp = ExtChipTrumpion;
2758 } else {
2759 //301
2760 temp = ExtChip301;
2762 #endif
2764 // 301;
2765 temp = 0x02;
2766 set_reg1(P3d4, 0x37, temp);
2768 #if 0
2769 //09/07/99 modify by domao for 630/540 MM
2770 if (HwDeviceExtension->jChipID == SIS_Glamour) {
2771 //For SiS 300 Chip
2772 SetDRAMSize(HwDeviceExtension);
2773 SetDRAMSize(HwDeviceExtension);
2774 } else {
2775 //For SiS 630/540 Chip
2776 //Restore SR14, SR19 and SR1A
2777 set_reg1(P3c4, 0x14, SR14);
2778 set_reg1(P3c4, 0x19, SR19);
2779 set_reg1(P3c4, 0x1A, SR1A);
2781 #endif
2783 set_reg1(P3c4, 0x14, SR14);
2784 set_reg1(P3c4, 0x19, SR19);
2785 set_reg1(P3c4, 0x1A, SR1A);
2786 set_reg3(P3c6, 0xff);
2787 ClearDAC(P3c8);
2788 DetectMonitor();
2790 #if 0
2791 //sense CRT2
2792 GetSenseStatus(HwDeviceExtension, BaseAddr, ROMAddr);
2793 #endif
2795 return (TRUE);
2798 static int SiSSetMode(u16 ModeNo)
2800 //#ifndef CONFIG_FB_SIS_LINUXBIOS
2801 unsigned long temp;
2802 //#endif
2804 u16 cr30flag, cr31flag;
2805 unsigned long ROMAddr = rom_vbase;
2806 u16 BaseAddr = (u16) ivideo.vga_base;
2807 u_short i;
2809 P3c4 = BaseAddr + 0x14;
2810 P3d4 = BaseAddr + 0x24;
2811 P3c0 = BaseAddr + 0x10;
2812 P3ce = BaseAddr + 0x1e;
2813 P3c2 = BaseAddr + 0x12;
2814 P3ca = BaseAddr + 0x1a;
2815 P3c6 = BaseAddr + 0x16;
2816 P3c7 = BaseAddr + 0x17;
2817 P3c8 = BaseAddr + 0x18;
2818 P3c9 = BaseAddr + 0x19;
2819 P3da = BaseAddr + 0x2A;
2821 #ifndef CONFIG_FB_SIS_LINUXBIOS
2822 temp = search_modeID(ROMAddr, ModeNo);
2824 if (temp == 0)
2825 return (0);
2827 temp = check_memory_size(ROMAddr);
2828 if (temp == 0)
2829 return (0);
2830 #endif
2832 #if 1
2833 cr30flag = (unsigned char) get_reg1(P3d4, 0x30);
2834 if (((cr30flag & 0x01) == 1) || ((cr30flag & 0x02) == 0)) {
2835 #ifndef CONFIG_FB_SIS_LINUXBIOS
2836 get_mode_ptr(ROMAddr, ModeNo);
2837 #endif
2838 set_seq_regs(ROMAddr);
2839 set_misc_regs(ROMAddr);
2840 set_crtc_regs(ROMAddr);
2841 set_attregs(ROMAddr);
2842 set_grc_regs(ROMAddr);
2843 ClearExt1Regs();
2845 #ifndef CONFIG_FB_SIS_LINUXBIOS
2846 temp = get_rate_ptr(ROMAddr, ModeNo);
2847 if (temp) {
2848 #endif
2849 set_sync(ROMAddr);
2850 set_crt1_crtc(ROMAddr);
2851 set_crt1_offset(ROMAddr);
2852 set_crt1_vclk(ROMAddr);
2853 set_vclk_state(ROMAddr, ModeNo);
2855 if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan))
2856 set_crt1_FIFO2(ROMAddr);
2857 else /* SiS 300 */
2858 set_crt1_FIFO(ROMAddr);
2859 #ifndef CONFIG_FB_SIS_LINUXBIOS
2861 #endif
2862 set_crt1_mode_regs(ROMAddr, ModeNo);
2863 if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan))
2864 set_interlace(ROMAddr, ModeNo);
2865 load_DAC(ROMAddr);
2867 /* clear OnScreen */
2868 memset((char *) ivideo.video_vbase, 0,
2869 video_linelength * ivideo.video_height);
2871 #else
2872 cr30flag = (unsigned char) get_reg1(P3d4, 0x30);
2873 if (((cr30flag & 0x01) == 1) || ((cr30flag & 0x02) == 0)) {
2874 //set_seq_regs(ROMAddr);
2876 unsigned char SRdata;
2877 SRdata = SRegs[0x01] | 0x20;
2878 set_reg1(P3c4, 0x01, SRdata);
2880 for (i = 02; i <= 04; i++)
2881 set_reg1(P3c4, i, SRegs[i]);
2884 //set_misc_regs(ROMAddr);
2886 set_reg3(P3c2, 0x23);
2889 //set_crtc_regs(ROMAddr);
2891 unsigned char CRTCdata;
2893 CRTCdata = (unsigned char) get_reg1(P3d4, 0x11);
2894 set_reg1(P3d4, 0x11, CRTCdata);
2896 for (i = 0; i <= 0x18; i++)
2897 set_reg1(P3d4, i, CRegs[i]);
2900 //set_attregs(ROMAddr);
2902 for (i = 0; i <= 0x13; i++) {
2903 get_reg2(P3da);
2904 set_reg3(P3c0, i);
2905 set_reg3(P3c0, ARegs[i]);
2907 get_reg2(P3da);
2908 set_reg3(P3c0, 0x14);
2909 set_reg3(P3c0, 0x00);
2910 get_reg2(P3da);
2911 set_reg3(P3c0, 0x20);
2914 //set_grc_regs(ROMAddr);
2916 for (i = 0; i <= 0x08; i++)
2917 set_reg1(P3ce, i, GRegs[i]);
2920 //ClearExt1Regs();
2922 for (i = 0x0A; i <= 0x0E; i++)
2923 set_reg1(P3c4, i, 0x00);
2926 //set_sync(ROMAddr);
2928 set_reg3(P3c2, MReg);
2931 //set_crt1_crtc(ROMAddr);
2933 unsigned char data;
2935 data = (unsigned char) get_reg1(P3d4, 0x11);
2936 data = data & 0x7F;
2937 set_reg1(P3d4, 0x11, data);
2939 for (i = 0; i <= 0x07; i++)
2940 set_reg1(P3d4, i, CRegs[i]);
2941 for (i = 0x10; i <= 0x12; i++)
2942 set_reg1(P3d4, i, CRegs[i]);
2943 for (i = 0x15; i <= 0x16; i++)
2944 set_reg1(P3d4, i, CRegs[i]);
2945 for (i = 0x0A; i <= 0x0C; i++)
2946 set_reg1(P3c4, i, SRegs[i]);
2948 data = SRegs[0x0E] & 0xE0;
2949 set_reg1(P3c4, 0x0E, data);
2951 set_reg1(P3d4, 0x09, CRegs[0x09]);
2955 //set_crt1_offset(ROMAddr);
2957 set_reg1(P3c4, 0x0E, SRegs[0x0E]);
2958 set_reg1(P3c4, 0x10, SRegs[0x10]);
2961 //set_crt1_vclk(ROMAddr);
2963 set_reg1(P3c4, 0x31, 0);
2965 for (i = 0x2B; i <= 0x2C; i++)
2966 set_reg1(P3c4, i, SRegs[i]);
2967 set_reg1(P3c4, 0x2D, 0x80);
2970 //set_vclk_state(ROMAddr, ModeNo);
2972 set_reg1(P3c4, 0x32, SRegs[0x32]);
2973 set_reg1(P3c4, 0x07, SRegs[0x07]);
2976 if ((ivideo.chip_id == SIS_Trojan)
2977 || (ivideo.chip_id == SIS_Spartan)) {
2978 //set_crt1_FIFO2(ROMAddr);
2979 set_reg1(P3c4, 0x15, SRegs[0x15]);
2981 set_reg4(0xcf8, 0x80000050);
2982 set_reg4(0xcfc, 0xc5041e04);
2984 set_reg1(P3c4, 0x08, SRegs[0x08]);
2985 set_reg1(P3c4, 0x0F, SRegs[0x0F]);
2986 set_reg1(P3c4, 0x3b, 0x00);
2987 set_reg1(P3c4, 0x09, SRegs[0x09]);
2990 //set_crt1_mode_regs(ROMAddr, ModeNo);
2992 set_reg1(P3c4, 0x06, SRegs[0x06]);
2993 set_reg1(P3c4, 0x01, SRegs[0x01]);
2994 set_reg1(P3c4, 0x0F, SRegs[0x0F]);
2995 set_reg1(P3c4, 0x21, SRegs[0x21]);
2998 if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan)) {
2999 //set_interlace(ROMAddr, ModeNo);
3000 set_reg1(P3d4, 0x19, CRegs[0x19]);
3001 set_reg1(P3d4, 0x1A, CRegs[0x1A]);
3003 load_DAC(ROMAddr);
3005 /* clear OnScreen */
3006 memset((char *) ivideo.video_vbase, 0,
3007 video_linelength * ivideo.video_height);
3009 #endif
3010 cr31flag = (unsigned char) get_reg1(P3d4, 0x31);
3012 display_on();
3014 return (0);
3017 static void pre_setmode(void)
3019 vgawb(CRTC_ADR, 0x30);
3020 vgawb(CRTC_DATA, 0x00);
3022 vgawb(CRTC_ADR, 0x31);
3023 vgawb(CRTC_DATA, 0x60);
3025 DPRINTK("Setting CR33 = 0x%x\n", rate_idx & 0x0f);
3027 /* set CRT1 refresh rate */
3028 vgawb(CRTC_ADR, 0x33);
3029 vgawb(CRTC_DATA, rate_idx & 0x0f);
3032 static void post_setmode(void)
3034 u8 uTemp;
3036 /* turn on CRT1 */
3037 vgawb(CRTC_ADR, 0x17);
3038 uTemp = vgarb(CRTC_DATA);
3039 uTemp |= 0x80;
3040 vgawb(CRTC_DATA, uTemp);
3042 /* disable 24-bit palette RAM and Gamma correction */
3043 vgawb(SEQ_ADR, 0x07);
3044 uTemp = vgarb(SEQ_DATA);
3045 uTemp &= ~0x04;
3046 vgawb(SEQ_DATA, uTemp);
3049 static void search_mode(const char *name)
3051 int i = 0;
3053 if (name == NULL)
3054 return;
3056 while (sisbios_mode[i].mode_no != 0) {
3057 if (!strcmp(name, sisbios_mode[i].name)) {
3058 mode_idx = i;
3059 break;
3061 i++;
3063 if (mode_idx < 0)
3064 DPRINTK("Invalid user mode : %s\n", name);
3067 static u8 search_refresh_rate(unsigned int rate)
3069 u16 xres, yres;
3070 int i = 0;
3072 xres = sisbios_mode[mode_idx].xres;
3073 yres = sisbios_mode[mode_idx].yres;
3075 while ((vrate[i].idx != 0) && (vrate[i].xres <= xres)) {
3076 if ((vrate[i].xres == xres) && (vrate[i].yres == yres)
3077 && (vrate[i].refresh == rate)) {
3078 rate_idx = vrate[i].idx;
3079 return rate_idx;
3081 i++;
3084 DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate, xres,
3085 yres);
3087 return 0;
3092 /* ------------------ Public Routines ------------------------------- */
3095 * Get the Fixed Part of the Display
3098 static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
3099 struct fb_info *info)
3101 DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con);
3103 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
3104 strcpy(fix->id, fb_info.modename);
3106 fix->smem_start = ivideo.video_base;
3107 if(ivideo.video_size > 0x800000)
3108 fix->smem_len = RESERVED_MEM_SIZE_8M; /* reserved for Xserver */
3109 else
3110 fix->smem_len = RESERVED_MEM_SIZE_4M; /* reserved for Xserver */
3112 fix->type = video_type;
3113 fix->type_aux = 0;
3114 if (ivideo.video_bpp == 8)
3115 fix->visual = FB_VISUAL_PSEUDOCOLOR;
3116 else
3117 fix->visual = FB_VISUAL_TRUECOLOR;
3118 fix->xpanstep = 0;
3119 fix->ypanstep = 0;
3120 fix->ywrapstep = 0;
3121 fix->line_length = video_linelength;
3122 fix->mmio_start = ivideo.mmio_base;
3123 fix->mmio_len = MMIO_SIZE;
3124 fix->accel = FB_ACCEL_SIS_GLAMOUR;
3125 fix->reserved[0] = ivideo.video_size & 0xFFFF;
3126 fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
3127 fix->reserved[2] = caps; /* capabilities */
3129 return 0;
3133 * Get the User Defined Part of the Display
3136 static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
3137 struct fb_info *info)
3139 DPRINTK("sisfb: sisfb_get_var:[%d]\n", con);
3141 if (con == -1)
3142 memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
3143 else
3144 *var = fb_display[con].var;
3145 return 0;
3149 * Set the User Defined Part of the Display
3152 static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
3153 struct fb_info *info)
3155 int err;
3156 unsigned int cols, rows;
3158 fb_display[con].var.activate = FB_ACTIVATE_NOW;
3160 /* Set mode */
3161 if (do_set_var(var, con == currcon, info)) {
3162 crtc_to_var(var); /* return current mode to user */
3163 return -EINVAL;
3166 /* get actual setting value */
3167 crtc_to_var(var);
3169 /* update display of current console */
3170 sisfb_set_disp(con, var);
3172 if (info->changevar)
3173 (*info->changevar) (con);
3175 if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
3176 return err;
3178 do_install_cmap(con, info);
3180 /* inform console to update struct display */
3181 cols = sisbios_mode[mode_idx].cols;
3182 rows = sisbios_mode[mode_idx].rows;
3183 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
3185 return 0;
3190 * Get the Colormap
3193 static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
3194 struct fb_info *info)
3196 DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con);
3198 if (con == currcon)
3199 return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
3200 else if (fb_display[con].cmap.len) /* non default colormap? */
3201 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
3202 else
3203 fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2);
3205 return 0;
3209 * Set the Colormap
3212 static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
3213 struct fb_info *info)
3215 int err;
3217 if (!fb_display[con].cmap.len) { /* no colormap allocated */
3218 err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0);
3219 if (err)
3220 return err;
3222 if (con == currcon) /* current console */
3223 return fb_set_cmap(cmap, kspc, sis_setcolreg, info);
3224 else
3225 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
3226 return 0;
3229 static int sisfb_ioctl(struct inode *inode, struct file *file,
3230 unsigned int cmd, unsigned long arg, int con,
3231 struct fb_info *info)
3233 switch (cmd) {
3234 case FBIO_ALLOC:
3235 if (!capable(CAP_SYS_RAWIO))
3236 return -EPERM;
3237 sis_malloc((struct sis_memreq *) arg);
3238 break;
3239 case FBIO_FREE:
3240 if (!capable(CAP_SYS_RAWIO))
3241 return -EPERM;
3242 sis_free(*(unsigned long *) arg);
3243 break;
3244 case FBIOGET_GLYPH:
3245 sis_get_glyph((struct GlyInfo *) arg);
3246 break;
3247 case FBIOGET_HWCINFO:
3249 unsigned long *hwc_offset = (unsigned long *) arg;
3251 if (caps | HW_CURSOR_CAP)
3252 *hwc_offset = hwcursor_vbase -
3253 (unsigned long) ivideo.video_vbase;
3254 else
3255 *hwc_offset = 0;
3257 break;
3259 default:
3260 return -EINVAL;
3262 return 0;
3265 static int sisfb_mmap(struct fb_info *info, struct file *file,
3266 struct vm_area_struct *vma)
3268 struct fb_var_screeninfo var;
3269 unsigned long start;
3270 unsigned long off;
3271 u32 len;
3273 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
3274 return -EINVAL;
3275 off = vma->vm_pgoff << PAGE_SHIFT;
3277 /* frame buffer memory */
3278 start = (unsigned long) ivideo.video_base;
3279 len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
3281 if (off >= len) {
3282 /* memory mapped io */
3283 off -= len;
3284 sisfb_get_var(&var, currcon, info);
3285 if (var.accel_flags)
3286 return -EINVAL;
3287 start = (unsigned long) ivideo.mmio_base;
3288 len = PAGE_ALIGN((start & ~PAGE_MASK) + MMIO_SIZE);
3291 start &= PAGE_MASK;
3292 if ((vma->vm_end - vma->vm_start + off) > len)
3293 return -EINVAL;
3294 off += start;
3295 vma->vm_pgoff = off >> PAGE_SHIFT;
3297 #if defined(__i386__)
3298 if (boot_cpu_data.x86 > 3)
3299 pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
3300 #endif
3301 if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
3302 vma->vm_page_prot))
3303 return -EAGAIN;
3304 return 0;
3307 static struct fb_ops sisfb_ops = {
3308 owner: THIS_MODULE,
3309 fb_get_fix: sisfb_get_fix,
3310 fb_get_var: sisfb_get_var,
3311 fb_set_var: sisfb_set_var,
3312 fb_get_cmap: sisfb_get_cmap,
3313 fb_set_cmap: sisfb_set_cmap,
3314 fb_ioctl: sisfb_ioctl,
3315 fb_mmap: sisfb_mmap,
3318 int sisfb_setup(char *options)
3320 char *this_opt;
3322 fb_info.fontname[0] = '\0';
3323 ivideo.refresh_rate = 0;
3325 if (!options || !*options)
3326 return 0;
3328 for (this_opt = strtok(options, ","); this_opt;
3329 this_opt = strtok(NULL, ",")) {
3330 if (!*this_opt)
3331 continue;
3333 if (!strcmp(this_opt, "inverse")) {
3334 inverse = 1;
3335 fb_invert_cmaps();
3336 } else if (!strncmp(this_opt, "font:", 5)) {
3337 strcpy(fb_info.fontname, this_opt + 5);
3338 } else if (!strncmp(this_opt, "mode:", 5)) {
3339 search_mode(this_opt + 5);
3340 } else if (!strncmp(this_opt, "vrate:", 6)) {
3341 ivideo.refresh_rate =
3342 simple_strtoul(this_opt + 6, NULL, 0);
3343 } else if (!strncmp(this_opt, "off", 3)) {
3344 sisfb_off = 1;
3345 } else
3346 DPRINTK("invalid parameter %s\n", this_opt);
3348 return 0;
3351 static int sisfb_update_var(int con, struct fb_info *info)
3353 return 0;
3357 * Switch Console (called by fbcon.c)
3360 static int sisfb_switch(int con, struct fb_info *info)
3362 int cols, rows;
3364 DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon, con);
3366 /* update colormap of current console */
3367 if (fb_display[currcon].cmap.len)
3368 fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
3370 fb_display[con].var.activate = FB_ACTIVATE_NOW;
3372 /* same mode, needn't change mode actually */
3374 if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof(struct fb_var_screeninfo)))
3376 currcon = con;
3377 return 1;
3380 currcon = con;
3382 do_set_var(&fb_display[con].var, 1, info);
3384 sisfb_set_disp(con, &fb_display[con].var);
3386 /* Install new colormap */
3387 do_install_cmap(con, info);
3389 cols = sisbios_mode[mode_idx].cols;
3390 rows = sisbios_mode[mode_idx].rows;
3391 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
3393 sisfb_update_var(con, info);
3395 return 1;
3399 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
3401 static void sisfb_blank(int blank, struct fb_info *info)
3403 u8 CRData;
3405 vgawb(CRTC_ADR, 0x17);
3406 CRData = vgarb(CRTC_DATA);
3408 if (blank > 0) /* turn off CRT1 */
3409 CRData &= 0x7f;
3410 else /* turn on CRT1 */
3411 CRData |= 0x80;
3413 vgawb(CRTC_ADR, 0x17);
3414 vgawb(CRTC_DATA, CRData);
3417 int __init sisfb_init(void)
3419 struct pci_dev *pdev = NULL;
3420 struct board *b;
3421 int pdev_valid = 0;
3422 unsigned char jTemp;
3423 u32 cmd;
3425 outb(0x77, 0x80);
3427 if (sisfb_off)
3428 return -ENXIO;
3430 pci_for_each_dev(pdev) {
3431 for (b = dev_list; b->vendor; b++)
3433 if ((b->vendor == pdev->vendor)
3434 && (b->device == pdev->device))
3436 pdev_valid = 1;
3437 strcpy(fb_info.modename, b->name);
3438 ivideo.chip_id = pdev->device;
3439 break;
3443 if (pdev_valid)
3444 break;
3447 if (!pdev_valid)
3448 return -1;
3450 #ifdef CONFIG_FB_SIS_LINUXBIOS
3451 pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
3452 cmd |= PCI_COMMAND_IO;
3453 cmd |= PCI_COMMAND_MEMORY;
3454 pci_write_config_dword(pdev, PCI_COMMAND, cmd);
3455 #endif
3457 ivideo.video_base = pci_resource_start(pdev, 0);
3458 if (!request_mem_region(ivideo.video_base, pci_resource_len(pdev, 0),
3459 "sisfb FB")) {
3460 printk(KERN_ERR "sisfb: cannot reserve frame buffer memory\n");
3461 return -ENODEV;
3463 ivideo.mmio_base = pci_resource_start(pdev, 1);
3464 if (!request_mem_region(ivideo.mmio_base, pci_resource_len(pdev, 1),
3465 "sisfb MMIO")) {
3466 printk(KERN_ERR "sisfb: cannot reserve MMIO region\n");
3467 release_mem_region(pci_resource_start(pdev, 1),
3468 pci_resource_len(pdev, 1));
3469 return -ENODEV;
3471 ivideo.vga_base = pci_resource_start(pdev, 2);
3472 if (!request_region(ivideo.vga_base, pci_resource_len(pdev, 2),
3473 "sisfb IO")) {
3474 printk(KERN_ERR "sisfb: cannot reserve I/O ports\n");
3475 release_mem_region(pci_resource_start(pdev, 1),
3476 pci_resource_len(pdev, 1));
3477 release_mem_region(pci_resource_start(pdev, 0),
3478 pci_resource_len(pdev, 0));
3479 return -ENODEV;
3481 ivideo.vga_base += 0x30;
3483 #ifndef CONFIG_FB_SIS_LINUXBIOS
3484 rom_base = 0x000C0000;
3485 request_region(rom_base, 32, "sisfb");
3486 #else
3487 rom_base = 0x0;
3488 #endif
3490 /* set passwd */
3491 vgawb(SEQ_ADR, IND_SIS_PASSWORD);
3492 vgawb(SEQ_DATA, SIS_PASSWORD);
3494 /* Enable MMIO & PCI linear address */
3495 vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET);
3496 jTemp = vgarb(SEQ_DATA);
3497 jTemp |= SIS_PCI_ADDR_ENABLE;
3498 jTemp |= SIS_MEM_MAP_IO_ENABLE;
3499 vgawb(SEQ_DATA, jTemp);
3501 /* get video ram size by SR14 */
3502 vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
3503 ivideo.video_size = ((int) ((vgarb(SEQ_DATA) & 0x3f) + 1) << 20);
3505 if (mode_idx < 0)
3506 mode_idx = DEFAULT_MODE; /* 0:640x480x8 */
3508 #ifdef CONFIG_FB_SIS_LINUXBIOS
3509 mode_idx = DEFAULT_MODE;
3510 rate_idx = sisbios_mode[mode_idx].rate_idx;
3511 /* set to default refresh rate 60MHz */
3512 ivideo.refresh_rate = 60;
3513 #endif
3515 mode_no = sisbios_mode[mode_idx].mode_no;
3517 if (ivideo.refresh_rate != 0)
3518 search_refresh_rate(ivideo.refresh_rate);
3520 if (rate_idx == 0) {
3521 rate_idx = sisbios_mode[mode_idx].rate_idx;
3522 /* set to default refresh rate 60MHz */
3523 ivideo.refresh_rate = 60;
3526 ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
3527 ivideo.video_width = sisbios_mode[mode_idx].xres;
3528 ivideo.video_height = sisbios_mode[mode_idx].yres;
3529 video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
3531 ivideo.video_vbase = ioremap(ivideo.video_base, ivideo.video_size);
3532 ivideo.mmio_vbase = ioremap(ivideo.mmio_base, MMIO_SIZE);
3534 #ifndef CONFIG_FB_SIS_LINUXBIOS
3535 rom_vbase = (unsigned long) ioremap(rom_base, MAX_ROM_SCAN);
3536 #endif
3538 SiSInit300();
3540 printk(KERN_INFO
3541 "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
3542 ivideo.video_base, ivideo.video_vbase,
3543 ivideo.video_size / 1024);
3544 printk(KERN_INFO "sisfb: mode is %dx%dx%d, linelength=%d\n",
3545 ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
3546 video_linelength);
3548 /* enable 2D engine */
3549 vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE);
3550 jTemp = vgarb(SEQ_DATA);
3551 jTemp |= SIS_2D_ENABLE;
3552 vgawb(SEQ_DATA, jTemp);
3554 pre_setmode();
3556 if (SiSSetMode(mode_no)) {
3557 DPRINTK("sisfb: set mode[0x%x]: failed\n", 0x30);
3558 return -1;
3561 post_setmode();
3563 crtc_to_var(&default_var);
3565 fb_info.changevar = NULL;
3566 fb_info.node = -1;
3567 fb_info.fbops = &sisfb_ops;
3568 fb_info.disp = &disp;
3569 fb_info.switch_con = &sisfb_switch;
3570 fb_info.updatevar = &sisfb_update_var;
3571 fb_info.blank = &sisfb_blank;
3572 fb_info.flags = FBINFO_FLAG_DEFAULT;
3574 sisfb_set_disp(-1, &default_var);
3576 if (sisfb_heap_init()) {
3577 DPRINTK("sisfb: Failed to enable offscreen heap\n");
3580 /* to avoid the inversed bgcolor bug of the initial state */
3581 vc_resize_con(1, 1, 0);
3583 if (register_framebuffer(&fb_info) < 0)
3584 return -EINVAL;
3586 ivideo.status = CRT1;
3588 printk(KERN_INFO "fb%d: %s frame buffer device\n",
3589 GET_FB_IDX(fb_info.node), fb_info.modename);
3591 return 0;
3594 #ifdef MODULE
3596 static char *mode = NULL;
3597 static unsigned int rate = 0;
3599 MODULE_PARM(mode, "s");
3600 MODULE_PARM(rate, "i");
3602 int init_module(void)
3604 if (mode)
3605 search_mode(mode);
3607 ivideo.refresh_rate = rate;
3609 sisfb_init();
3611 return 0;
3614 void cleanup_module(void)
3616 unregister_framebuffer(&fb_info);
3618 #endif /* MODULE */
3621 EXPORT_SYMBOL(sis_malloc);
3622 EXPORT_SYMBOL(sis_free);
3624 EXPORT_SYMBOL(ivideo);