- Andries Brouwer: final isofs pieces.
[davej-history.git] / drivers / video / tdfxfb.c
blobd954dc02e85c4b3ae2f45714c17f94f95de1ba7e
1 /*
3 * tdfxfb.c
5 * Author: Hannu Mallat <hmallat@cc.hut.fi>
7 * Copyright © 1999 Hannu Mallat
8 * All rights reserved
10 * Created : Thu Sep 23 18:17:43 1999, hmallat
11 * Last modified: Tue Nov 2 21:19:47 1999, hmallat
13 * Lots of the information here comes from the Daryll Strauss' Banshee
14 * patches to the XF86 server, and the rest comes from the 3dfx
15 * Banshee specification. I'm very much indebted to Daryll for his
16 * work on the X server.
18 * Voodoo3 support was contributed Harold Oga. Lots of additions
19 * (proper acceleration, 24 bpp, hardware cursor) and bug fixes by Attila
20 * Kesmarki. Thanks guys!
22 * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
23 * I do wish the next version is a bit more complete. Without the XF86
24 * patches I couldn't have gotten even this far... for instance, the
25 * extensions to the VGA register set go completely unmentioned in the
26 * spec! Also, lots of references are made to the 'SST core', but no
27 * spec is publicly available, AFAIK.
29 * The structure of this driver comes pretty much from the Permedia
30 * driver by Ilario Nardinocchi, which in turn is based on skeletonfb.
32 * TODO:
33 * - support for 16/32 bpp needs fixing (funky bootup penguin)
34 * - multihead support (basically need to support an array of fb_infos)
35 * - banshee and voodoo3 now supported -- any others? afaik, the original
36 * voodoo was a 3d-only card, so we won't consider that. what about
37 * voodoo2?
38 * - support other architectures (PPC, Alpha); does the fact that the VGA
39 * core can be accessed only thru I/O (not memory mapped) complicate
40 * things?
42 * Version history:
44 * 0.1.3 (released 1999-11-02) added Attila's panning support, code
45 * reorg, hwcursor address page size alignment
46 * (for mmaping both frame buffer and regs),
47 * and my changes to get rid of hardcoded
48 * VGA i/o register locations (uses PCI
49 * configuration info now)
50 * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and
51 * improvements
52 * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga.
53 * 0.1.0 (released 1999-10-06) initial version
57 #include <linux/config.h>
58 #include <linux/module.h>
59 #include <linux/kernel.h>
60 #include <linux/errno.h>
61 #include <linux/string.h>
62 #include <linux/mm.h>
63 #include <linux/tty.h>
64 #include <linux/malloc.h>
65 #include <linux/vmalloc.h>
66 #include <linux/delay.h>
67 #include <linux/interrupt.h>
68 #include <linux/fb.h>
69 #include <linux/selection.h>
70 #include <linux/console.h>
71 #include <linux/init.h>
72 #include <linux/pci.h>
73 #include <linux/nvram.h>
74 #include <linux/kd.h>
75 #include <linux/vt_kern.h>
76 #include <asm/io.h>
77 #include <linux/timer.h>
79 #ifdef CONFIG_MTRR
80 #include <asm/mtrr.h>
81 #endif
83 #include <video/fbcon.h>
84 #include <video/fbcon-cfb8.h>
85 #include <video/fbcon-cfb16.h>
86 #include <video/fbcon-cfb24.h>
87 #include <video/fbcon-cfb32.h>
89 #include <linux/spinlock.h>
91 /* membase0 register offsets */
92 #define STATUS 0x00
93 #define PCIINIT0 0x04
94 #define SIPMONITOR 0x08
95 #define LFBMEMORYCONFIG 0x0c
96 #define MISCINIT0 0x10
97 #define MISCINIT1 0x14
98 #define DRAMINIT0 0x18
99 #define DRAMINIT1 0x1c
100 #define AGPINIT 0x20
101 #define TMUGBEINIT 0x24
102 #define VGAINIT0 0x28
103 #define VGAINIT1 0x2c
104 #define DRAMCOMMAND 0x30
105 #define DRAMDATA 0x34
106 /* reserved 0x38 */
107 /* reserved 0x3c */
108 #define PLLCTRL0 0x40
109 #define PLLCTRL1 0x44
110 #define PLLCTRL2 0x48
111 #define DACMODE 0x4c
112 #define DACADDR 0x50
113 #define DACDATA 0x54
114 #define RGBMAXDELTA 0x58
115 #define VIDPROCCFG 0x5c
116 #define HWCURPATADDR 0x60
117 #define HWCURLOC 0x64
118 #define HWCURC0 0x68
119 #define HWCURC1 0x6c
120 #define VIDINFORMAT 0x70
121 #define VIDINSTATUS 0x74
122 #define VIDSERPARPORT 0x78
123 #define VIDINXDELTA 0x7c
124 #define VIDININITERR 0x80
125 #define VIDINYDELTA 0x84
126 #define VIDPIXBUFTHOLD 0x88
127 #define VIDCHRMIN 0x8c
128 #define VIDCHRMAX 0x90
129 #define VIDCURLIN 0x94
130 #define VIDSCREENSIZE 0x98
131 #define VIDOVRSTARTCRD 0x9c
132 #define VIDOVRENDCRD 0xa0
133 #define VIDOVRDUDX 0xa4
134 #define VIDOVRDUDXOFF 0xa8
135 #define VIDOVRDVDY 0xac
136 /* ... */
137 #define VIDOVRDVDYOFF 0xe0
138 #define VIDDESKSTART 0xe4
139 #define VIDDESKSTRIDE 0xe8
140 #define VIDINADDR0 0xec
141 #define VIDINADDR1 0xf0
142 #define VIDINADDR2 0xf4
143 #define VIDINSTRIDE 0xf8
144 #define VIDCUROVRSTART 0xfc
146 #define INTCTRL (0x00100000 + 0x04)
147 #define CLIP0MIN (0x00100000 + 0x08)
148 #define CLIP0MAX (0x00100000 + 0x0c)
149 #define DSTBASE (0x00100000 + 0x10)
150 #define DSTFORMAT (0x00100000 + 0x14)
151 #define SRCBASE (0x00100000 + 0x34)
152 #define COMMANDEXTRA_2D (0x00100000 + 0x38)
153 #define CLIP1MIN (0x00100000 + 0x4c)
154 #define CLIP1MAX (0x00100000 + 0x50)
155 #define SRCFORMAT (0x00100000 + 0x54)
156 #define SRCSIZE (0x00100000 + 0x58)
157 #define SRCXY (0x00100000 + 0x5c)
158 #define COLORBACK (0x00100000 + 0x60)
159 #define COLORFORE (0x00100000 + 0x64)
160 #define DSTSIZE (0x00100000 + 0x68)
161 #define DSTXY (0x00100000 + 0x6c)
162 #define COMMAND_2D (0x00100000 + 0x70)
163 #define LAUNCH_2D (0x00100000 + 0x80)
165 #define COMMAND_3D (0x00200000 + 0x120)
167 /* register bitfields (not all, only as needed) */
169 #define BIT(x) (1UL << (x))
171 /* COMMAND_2D reg. values */
172 #define ROP_COPY 0xcc // src
173 #define ROP_INVERT 0x55 // NOT dst
174 #define ROP_XOR 0x66 // src XOR dst
176 #define AUTOINC_DSTX BIT(10)
177 #define AUTOINC_DSTY BIT(11)
178 #define COMMAND_2D_FILLRECT 0x05
179 #define COMMAND_2D_S2S_BITBLT 0x01 // screen to screen
180 #define COMMAND_2D_H2S_BITBLT 0x03 // host to screen
183 #define COMMAND_3D_NOP 0x00
184 #define STATUS_RETRACE BIT(6)
185 #define STATUS_BUSY BIT(9)
186 #define MISCINIT1_CLUT_INV BIT(0)
187 #define MISCINIT1_2DBLOCK_DIS BIT(15)
188 #define DRAMINIT0_SGRAM_NUM BIT(26)
189 #define DRAMINIT0_SGRAM_TYPE BIT(27)
190 #define DRAMINIT1_MEM_SDRAM BIT(30)
191 #define VGAINIT0_VGA_DISABLE BIT(0)
192 #define VGAINIT0_EXT_TIMING BIT(1)
193 #define VGAINIT0_8BIT_DAC BIT(2)
194 #define VGAINIT0_EXT_ENABLE BIT(6)
195 #define VGAINIT0_WAKEUP_3C3 BIT(8)
196 #define VGAINIT0_LEGACY_DISABLE BIT(9)
197 #define VGAINIT0_ALT_READBACK BIT(10)
198 #define VGAINIT0_FAST_BLINK BIT(11)
199 #define VGAINIT0_EXTSHIFTOUT BIT(12)
200 #define VGAINIT0_DECODE_3C6 BIT(13)
201 #define VGAINIT0_SGRAM_HBLANK_DISABLE BIT(22)
202 #define VGAINIT1_MASK 0x1fffff
203 #define VIDCFG_VIDPROC_ENABLE BIT(0)
204 #define VIDCFG_CURS_X11 BIT(1)
205 #define VIDCFG_HALF_MODE BIT(4)
206 #define VIDCFG_DESK_ENABLE BIT(7)
207 #define VIDCFG_CLUT_BYPASS BIT(10)
208 #define VIDCFG_2X BIT(26)
209 #define VIDCFG_HWCURSOR_ENABLE BIT(27)
210 #define VIDCFG_PIXFMT_SHIFT 18
211 #define DACMODE_2X BIT(0)
213 /* VGA rubbish, need to change this for multihead support */
214 #define MISC_W 0x3c2
215 #define MISC_R 0x3cc
216 #define SEQ_I 0x3c4
217 #define SEQ_D 0x3c5
218 #define CRT_I 0x3d4
219 #define CRT_D 0x3d5
220 #define ATT_IW 0x3c0
221 #define IS1_R 0x3da
222 #define GRA_I 0x3ce
223 #define GRA_D 0x3cf
225 #ifndef FB_ACCEL_3DFX_BANSHEE
226 #define FB_ACCEL_3DFX_BANSHEE 31
227 #endif
229 #define TDFXF_HSYNC_ACT_HIGH 0x01
230 #define TDFXF_HSYNC_ACT_LOW 0x02
231 #define TDFXF_VSYNC_ACT_HIGH 0x04
232 #define TDFXF_VSYNC_ACT_LOW 0x08
233 #define TDFXF_LINE_DOUBLE 0x10
234 #define TDFXF_VIDEO_ENABLE 0x20
236 #define TDFXF_HSYNC_MASK 0x03
237 #define TDFXF_VSYNC_MASK 0x0c
239 //#define TDFXFB_DEBUG
240 #ifdef TDFXFB_DEBUG
241 #define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b)
242 #else
243 #define DPRINTK(a,b...)
244 #endif
246 #define PICOS2KHZ(a) (1000000000UL/(a))
247 #define KHZ2PICOS(a) (1000000000UL/(a))
249 #define BANSHEE_MAX_PIXCLOCK 270000.0
250 #define VOODOO3_MAX_PIXCLOCK 300000.0
252 struct banshee_reg {
253 /* VGA rubbish */
254 unsigned char att[21];
255 unsigned char crt[25];
256 unsigned char gra[ 9];
257 unsigned char misc[1];
258 unsigned char seq[ 5];
260 /* Banshee extensions */
261 unsigned char ext[2];
262 unsigned long vidcfg;
263 unsigned long vidpll;
264 unsigned long mempll;
265 unsigned long gfxpll;
266 unsigned long dacmode;
267 unsigned long vgainit0;
268 unsigned long vgainit1;
269 unsigned long screensize;
270 unsigned long stride;
271 unsigned long cursloc;
272 unsigned long curspataddr;
273 unsigned long cursc0;
274 unsigned long cursc1;
275 unsigned long startaddr;
276 unsigned long clip0min;
277 unsigned long clip0max;
278 unsigned long clip1min;
279 unsigned long clip1max;
280 unsigned long srcbase;
281 unsigned long dstbase;
284 struct tdfxfb_par {
285 u32 pixclock;
287 u32 baseline;
289 u32 width;
290 u32 height;
291 u32 width_virt;
292 u32 height_virt;
293 u32 lpitch; /* line pitch, in bytes */
294 u32 ppitch; /* pixel pitch, in bits */
295 u32 bpp;
297 u32 hdispend;
298 u32 hsyncsta;
299 u32 hsyncend;
300 u32 htotal;
302 u32 vdispend;
303 u32 vsyncsta;
304 u32 vsyncend;
305 u32 vtotal;
307 u32 video;
308 u32 accel_flags;
309 u32 cmap_len;
312 struct fb_info_tdfx {
313 struct fb_info fb_info;
315 u16 dev;
316 u32 max_pixclock;
318 unsigned long regbase_phys;
319 void *regbase_virt;
320 unsigned long regbase_size;
321 unsigned long bufbase_phys;
322 void *bufbase_virt;
323 unsigned long bufbase_size;
324 unsigned long iobase;
326 struct { unsigned red, green, blue, pad; } palette[256];
327 struct tdfxfb_par default_par;
328 struct tdfxfb_par current_par;
329 struct display disp;
330 #if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)
331 union {
332 #ifdef FBCON_HAS_CFB16
333 u16 cfb16[16];
334 #endif
335 #ifdef FBCON_HAS_CFB24
336 u32 cfb24[16];
337 #endif
338 #ifdef FBCON_HAS_CFB32
339 u32 cfb32[16];
340 #endif
341 } fbcon_cmap;
342 #endif
343 struct {
344 int type;
345 int state;
346 int w,u,d;
347 int x,y,redraw;
348 unsigned long enable,disable;
349 unsigned long cursorimage;
350 struct timer_list timer;
351 } cursor;
353 spinlock_t DAClock;
354 #ifdef CONFIG_MTRR
355 int mtrr_idx;
356 #endif
360 * Frame buffer device API
362 static int tdfxfb_get_fix(struct fb_fix_screeninfo* fix,
363 int con,
364 struct fb_info* fb);
365 static int tdfxfb_get_var(struct fb_var_screeninfo* var,
366 int con,
367 struct fb_info* fb);
368 static int tdfxfb_set_var(struct fb_var_screeninfo* var,
369 int con,
370 struct fb_info* fb);
371 static int tdfxfb_pan_display(struct fb_var_screeninfo* var,
372 int con,
373 struct fb_info* fb);
374 static int tdfxfb_get_cmap(struct fb_cmap *cmap,
375 int kspc,
376 int con,
377 struct fb_info* info);
378 static int tdfxfb_set_cmap(struct fb_cmap* cmap,
379 int kspc,
380 int con,
381 struct fb_info* info);
382 static int tdfxfb_ioctl(struct inode* inode,
383 struct file* file,
384 u_int cmd,
385 u_long arg,
386 int con,
387 struct fb_info* info);
390 * Interface to the low level console driver
392 static int tdfxfb_switch_con(int con,
393 struct fb_info* fb);
394 static int tdfxfb_updatevar(int con,
395 struct fb_info* fb);
396 static void tdfxfb_blank(int blank,
397 struct fb_info* fb);
400 * Internal routines
402 static void tdfxfb_set_par(const struct tdfxfb_par* par,
403 struct fb_info_tdfx*
404 info);
405 static int tdfxfb_decode_var(const struct fb_var_screeninfo *var,
406 struct tdfxfb_par *par,
407 const struct fb_info_tdfx *info);
408 static int tdfxfb_encode_var(struct fb_var_screeninfo* var,
409 const struct tdfxfb_par* par,
410 const struct fb_info_tdfx* info);
411 static int tdfxfb_encode_fix(struct fb_fix_screeninfo* fix,
412 const struct tdfxfb_par* par,
413 const struct fb_info_tdfx* info);
414 static void tdfxfb_set_dispsw(struct display* disp,
415 struct fb_info_tdfx* info,
416 int bpp,
417 int accel);
418 static int tdfxfb_getcolreg(u_int regno,
419 u_int* red,
420 u_int* green,
421 u_int* blue,
422 u_int* transp,
423 struct fb_info* fb);
424 static int tdfxfb_setcolreg(u_int regno,
425 u_int red,
426 u_int green,
427 u_int blue,
428 u_int transp,
429 struct fb_info* fb);
430 static void tdfxfb_install_cmap(struct display *d,
431 struct fb_info *info);
433 static void tdfxfb_hwcursor_init(void);
434 static void tdfxfb_createcursorshape(struct display* p);
435 static void tdfxfb_createcursor(struct display * p);
438 * do_xxx: Hardware-specific functions
440 static void do_pan_var(struct fb_var_screeninfo* var, struct fb_info_tdfx *i);
441 static void do_flashcursor(unsigned long ptr);
442 static void do_bitblt(u32 curx, u32 cury, u32 dstx,u32 dsty,
443 u32 width, u32 height,u32 stride,u32 bpp);
444 static void do_fillrect(u32 x, u32 y, u32 w,u32 h,
445 u32 color,u32 stride,u32 bpp,u32 rop);
446 static void do_putc(u32 fgx, u32 bgx,struct display *p,
447 int c, int yy,int xx);
448 static void do_putcs(u32 fgx, u32 bgx,struct display *p,
449 const unsigned short *s,int count, int yy,int xx);
450 static u32 do_calc_pll(int freq, int* freq_out);
451 static void do_write_regs(struct banshee_reg* reg);
452 static unsigned long do_lfb_size(void);
455 * Interface used by the world
457 int tdfxfb_init(void);
458 void tdfxfb_setup(char *options,
459 int *ints);
461 static int currcon = 0;
463 static struct fb_ops tdfxfb_ops = {
464 owner: THIS_MODULE,
465 fb_get_fix: tdfxfb_get_fix,
466 fb_get_var: tdfxfb_get_var,
467 fb_set_var: tdfxfb_set_var,
468 fb_get_cmap: tdfxfb_get_cmap,
469 fb_set_cmap: tdfxfb_set_cmap,
470 fb_pan_display: tdfxfb_pan_display,
471 fb_ioctl: tdfxfb_ioctl,
474 struct mode {
475 char* name;
476 struct fb_var_screeninfo var;
477 } mode;
479 /* 2.3.x kernels have a fb mode database, so supply only one backup default */
480 struct mode default_mode[] = {
481 { "640x480-8@60", /* @ 60 Hz */
483 640, 480, 640, 1024, 0, 0, 8, 0,
484 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
485 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
486 39722, 40, 24, 32, 11, 96, 2,
487 0, FB_VMODE_NONINTERLACED
492 static struct fb_info_tdfx fb_info;
494 static int noaccel = 0;
495 static int nopan = 0;
496 static int nowrap = 1; // not implemented (yet)
497 static int inverse = 0;
498 #ifdef CONFIG_MTRR
499 static int nomtrr = 0;
500 #endif
501 static int nohwcursor = 0;
502 static char __initdata fontname[40] = { 0 };
503 static const char *mode_option __initdata = NULL;
505 /* -------------------------------------------------------------------------
506 * Hardware-specific funcions
507 * ------------------------------------------------------------------------- */
509 #ifdef VGA_REG_IO
510 static inline u8 vga_inb(u32 reg) { return inb(reg); }
511 static inline u16 vga_inw(u32 reg) { return inw(reg); }
512 static inline u16 vga_inl(u32 reg) { return inl(reg); }
514 static inline void vga_outb(u32 reg, u8 val) { outb(val, reg); }
515 static inline void vga_outw(u32 reg, u16 val) { outw(val, reg); }
516 static inline void vga_outl(u32 reg, u32 val) { outl(val, reg); }
517 #else
518 static inline u8 vga_inb(u32 reg) {
519 return inb(fb_info.iobase + reg - 0x300);
521 static inline u16 vga_inw(u32 reg) {
522 return inw(fb_info.iobase + reg - 0x300);
524 static inline u16 vga_inl(u32 reg) {
525 return inl(fb_info.iobase + reg - 0x300);
528 static inline void vga_outb(u32 reg, u8 val) {
529 outb(val, fb_info.iobase + reg - 0x300);
531 static inline void vga_outw(u32 reg, u16 val) {
532 outw(val, fb_info.iobase + reg - 0x300);
534 static inline void vga_outl(u32 reg, u32 val) {
535 outl(val, fb_info.iobase + reg - 0x300);
537 #endif
539 static inline void gra_outb(u32 idx, u8 val) {
540 vga_outb(GRA_I, idx); vga_outb(GRA_D, val);
543 static inline u8 gra_inb(u32 idx) {
544 vga_outb(GRA_I, idx); return vga_inb(GRA_D);
547 static inline void seq_outb(u32 idx, u8 val) {
548 vga_outb(SEQ_I, idx); vga_outb(SEQ_D, val);
551 static inline u8 seq_inb(u32 idx) {
552 vga_outb(SEQ_I, idx); return vga_inb(SEQ_D);
555 static inline void crt_outb(u32 idx, u8 val) {
556 vga_outb(CRT_I, idx); vga_outb(CRT_D, val);
559 static inline u8 crt_inb(u32 idx) {
560 vga_outb(CRT_I, idx); return vga_inb(CRT_D);
563 static inline void att_outb(u32 idx, u8 val) {
564 unsigned char tmp;
565 tmp = vga_inb(IS1_R);
566 vga_outb(ATT_IW, idx);
567 vga_outb(ATT_IW, val);
570 static inline u8 att_inb(u32 idx) {
571 unsigned char tmp;
572 tmp = vga_inb(IS1_R);
573 vga_outb(ATT_IW, idx);
574 return vga_inb(ATT_IW);
577 static inline void vga_disable_video(void) {
578 unsigned char s;
579 s = seq_inb(0x01) | 0x20;
580 seq_outb(0x00, 0x01);
581 seq_outb(0x01, s);
582 seq_outb(0x00, 0x03);
585 static inline void vga_enable_video(void) {
586 unsigned char s;
587 s = seq_inb(0x01) & 0xdf;
588 seq_outb(0x00, 0x01);
589 seq_outb(0x01, s);
590 seq_outb(0x00, 0x03);
593 static inline void vga_disable_palette(void) {
594 vga_inb(IS1_R);
595 vga_outb(ATT_IW, 0x00);
598 static inline void vga_enable_palette(void) {
599 vga_inb(IS1_R);
600 vga_outb(ATT_IW, 0x20);
603 static inline u32 tdfx_inl(unsigned int reg) {
604 return readl(fb_info.regbase_virt + reg);
607 static inline void tdfx_outl(unsigned int reg, u32 val) {
608 writel(val, fb_info.regbase_virt + reg);
611 static inline void banshee_make_room(int size) {
612 while((tdfx_inl(STATUS) & 0x1f) < size);
615 static inline void banshee_wait_idle(void) {
616 int i = 0;
618 banshee_make_room(1);
619 tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
621 while(1) {
622 i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1;
623 if(i == 3) break;
627 * Set the color of a palette entry in 8bpp mode
629 static inline void do_setpalentry(unsigned regno, u32 c) {
630 banshee_make_room(2); tdfx_outl(DACADDR, regno); tdfx_outl(DACDATA, c); }
633 * Set the starting position of the visible screen to var->yoffset
635 static void do_pan_var(struct fb_var_screeninfo* var, struct fb_info_tdfx *i)
637 u32 addr;
638 addr = var->yoffset*i->current_par.lpitch;
639 banshee_make_room(1);
640 tdfx_outl(VIDDESKSTART, addr);
644 * Invert the hardware cursor image (timerfunc)
646 static void do_flashcursor(unsigned long ptr)
648 struct fb_info_tdfx* i=(struct fb_info_tdfx *)ptr;
649 spin_lock(&i->DAClock);
650 banshee_make_room(1);
651 tdfx_outl( VIDPROCCFG, tdfx_inl(VIDPROCCFG) ^ VIDCFG_HWCURSOR_ENABLE );
652 i->cursor.timer.expires=jiffies+HZ/2;
653 add_timer(&i->cursor.timer);
654 spin_unlock(&i->DAClock);
658 * FillRect 2D command (solidfill or invert (via ROP_XOR))
660 static void do_fillrect(u32 x, u32 y, u32 w, u32 h,
661 u32 color, u32 stride, u32 bpp, u32 rop) {
663 u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
665 banshee_make_room(5);
666 tdfx_outl(DSTFORMAT, fmt);
667 tdfx_outl(COLORFORE, color);
668 tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (rop << 24));
669 tdfx_outl(DSTSIZE, w | (h << 16));
670 tdfx_outl(LAUNCH_2D, x | (y << 16));
671 banshee_wait_idle();
675 * Screen-to-Screen BitBlt 2D command (for the bmove fb op.)
678 static void do_bitblt(u32 curx,
679 u32 cury,
680 u32 dstx,
681 u32 dsty,
682 u32 width,
683 u32 height,
684 u32 stride,
685 u32 bpp) {
687 u32 blitcmd = COMMAND_2D_S2S_BITBLT | (ROP_COPY << 24);
688 u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
690 if (curx <= dstx) {
691 //-X
692 blitcmd |= BIT(14);
693 curx += width-1;
694 dstx += width-1;
696 if (cury <= dsty) {
697 //-Y
698 blitcmd |= BIT(15);
699 cury += height-1;
700 dsty += height-1;
703 banshee_make_room(6);
705 tdfx_outl(SRCFORMAT, fmt);
706 tdfx_outl(DSTFORMAT, fmt);
707 tdfx_outl(COMMAND_2D, blitcmd);
708 tdfx_outl(DSTSIZE, width | (height << 16));
709 tdfx_outl(DSTXY, dstx | (dsty << 16));
710 tdfx_outl(LAUNCH_2D, curx | (cury << 16));
711 banshee_wait_idle();
714 static void do_putc(u32 fgx, u32 bgx,
715 struct display *p,
716 int c, int yy,int xx)
718 int i;
719 int stride=fb_info.current_par.lpitch;
720 u32 bpp=fb_info.current_par.bpp;
721 int fw=(fontwidth(p)+7)>>3;
722 u8 *chardata=p->fontdata+(c&p->charmask)*fontheight(p)*fw;
723 u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
725 xx *= fontwidth(p);
726 yy *= fontheight(p);
728 banshee_make_room(8+((fontheight(p)*fw+3)>>2) );
729 tdfx_outl(COLORFORE, fgx);
730 tdfx_outl(COLORBACK, bgx);
731 tdfx_outl(SRCXY, 0);
732 tdfx_outl(DSTXY, xx | (yy << 16));
733 tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (ROP_COPY << 24));
734 tdfx_outl(SRCFORMAT, 0x400000);
735 tdfx_outl(DSTFORMAT, fmt);
736 tdfx_outl(DSTSIZE, fontwidth(p) | (fontheight(p) << 16));
737 i=fontheight(p);
738 switch (fw) {
739 case 1:
740 while (i>=4) {
741 tdfx_outl(LAUNCH_2D,*(u32*)chardata);
742 chardata+=4;
743 i-=4;
745 switch (i) {
746 case 0: break;
747 case 1: tdfx_outl(LAUNCH_2D,*chardata); break;
748 case 2: tdfx_outl(LAUNCH_2D,*(u16*)chardata); break;
749 case 3: tdfx_outl(LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
751 break;
752 case 2:
753 while (i>=2) {
754 tdfx_outl(LAUNCH_2D,*(u32*)chardata);
755 chardata+=4;
756 i-=2;
758 if (i) tdfx_outl(LAUNCH_2D,*(u16*)chardata);
759 break;
760 default:
761 // Is there a font with width more that 16 pixels ?
762 for (i=fontheight(p);i>0;i--) {
763 tdfx_outl(LAUNCH_2D,*(u32*)chardata);
764 chardata+=4;
766 break;
768 banshee_wait_idle();
771 static void do_putcs(u32 fgx, u32 bgx,
772 struct display *p,
773 const unsigned short *s,
774 int count, int yy,int xx)
776 int i;
777 int stride=fb_info.current_par.lpitch;
778 u32 bpp=fb_info.current_par.bpp;
779 int fw=(fontwidth(p)+7)>>3;
780 int w=fontwidth(p);
781 int h=fontheight(p);
782 int regsneed=1+((h*fw+3)>>2);
783 u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
785 xx *= w;
786 yy = (yy*h) << 16;
787 banshee_make_room(8);
789 tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
790 tdfx_outl(COLORFORE, fgx);
791 tdfx_outl(COLORBACK, bgx);
792 tdfx_outl(SRCFORMAT, 0x400000);
793 tdfx_outl(DSTFORMAT, fmt);
794 tdfx_outl(DSTSIZE, w | (h << 16));
795 tdfx_outl(SRCXY, 0);
796 tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (ROP_COPY << 24));
798 while (count--) {
799 u8 *chardata=p->fontdata+(scr_readw(s++) & p->charmask)*h*fw;
801 banshee_make_room(regsneed);
802 tdfx_outl(DSTXY, xx | yy);
803 xx+=w;
805 i=h;
806 switch (fw) {
807 case 1:
808 while (i>=4) {
809 tdfx_outl(LAUNCH_2D,*(u32*)chardata);
810 chardata+=4;
811 i-=4;
813 switch (i) {
814 case 0: break;
815 case 1: tdfx_outl(LAUNCH_2D,*chardata); break;
816 case 2: tdfx_outl(LAUNCH_2D,*(u16*)chardata); break;
817 case 3: tdfx_outl(LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
819 break;
820 case 2:
821 while (i>=2) {
822 tdfx_outl(LAUNCH_2D,*(u32*)chardata);
823 chardata+=4;
824 i-=2;
826 if (i) tdfx_outl(LAUNCH_2D,*(u16*)chardata);
827 break;
828 default:
829 // Is there a font with width more that 16 pixels ?
830 for (;i>0;i--) {
831 tdfx_outl(LAUNCH_2D,*(u32*)chardata);
832 chardata+=4;
834 break;
837 banshee_wait_idle();
840 static u32 do_calc_pll(int freq, int* freq_out) {
841 int m, n, k, best_m, best_n, best_k, f_cur, best_error;
842 int fref = 14318;
844 /* this really could be done with more intelligence --
845 255*63*4 = 64260 iterations is silly */
846 best_error = freq;
847 best_n = best_m = best_k = 0;
848 for(n = 1; n < 256; n++) {
849 for(m = 1; m < 64; m++) {
850 for(k = 0; k < 4; k++) {
851 f_cur = fref*(n + 2)/(m + 2)/(1 << k);
852 if(abs(f_cur - freq) < best_error) {
853 best_error = abs(f_cur-freq);
854 best_n = n;
855 best_m = m;
856 best_k = k;
861 n = best_n;
862 m = best_m;
863 k = best_k;
864 *freq_out = fref*(n + 2)/(m + 2)/(1 << k);
866 return (n << 8) | (m << 2) | k;
869 static void do_write_regs(struct banshee_reg* reg) {
870 int i;
872 banshee_wait_idle();
874 tdfx_outl(MISCINIT1, tdfx_inl(MISCINIT1) | 0x01);
876 crt_outb(0x11, crt_inb(0x11) & 0x7f); /* CRT unprotect */
878 banshee_make_room(3);
879 tdfx_outl(VGAINIT1, reg->vgainit1 & 0x001FFFFF);
880 tdfx_outl(VIDPROCCFG, reg->vidcfg & ~0x00000001);
881 #if 0
882 tdfx_outl(PLLCTRL1, reg->mempll);
883 tdfx_outl(PLLCTRL2, reg->gfxpll);
884 #endif
885 tdfx_outl(PLLCTRL0, reg->vidpll);
887 vga_outb(MISC_W, reg->misc[0x00] | 0x01);
889 for(i = 0; i < 5; i++)
890 seq_outb(i, reg->seq[i]);
892 for(i = 0; i < 25; i++)
893 crt_outb(i, reg->crt[i]);
895 for(i = 0; i < 9; i++)
896 gra_outb(i, reg->gra[i]);
898 for(i = 0; i < 21; i++)
899 att_outb(i, reg->att[i]);
901 crt_outb(0x1a, reg->ext[0]);
902 crt_outb(0x1b, reg->ext[1]);
904 vga_enable_palette();
905 vga_enable_video();
907 banshee_make_room(11);
908 tdfx_outl(VGAINIT0, reg->vgainit0);
909 tdfx_outl(DACMODE, reg->dacmode);
910 tdfx_outl(VIDDESKSTRIDE, reg->stride);
911 if (nohwcursor) {
912 tdfx_outl(HWCURPATADDR, 0);
913 } else {
914 tdfx_outl(HWCURPATADDR, reg->curspataddr);
915 tdfx_outl(HWCURC0, reg->cursc0);
916 tdfx_outl(HWCURC1, reg->cursc1);
917 tdfx_outl(HWCURLOC, reg->cursloc);
920 tdfx_outl(VIDSCREENSIZE, reg->screensize);
921 tdfx_outl(VIDDESKSTART, reg->startaddr);
922 tdfx_outl(VIDPROCCFG, reg->vidcfg);
923 tdfx_outl(VGAINIT1, reg->vgainit1);
925 banshee_make_room(8);
926 tdfx_outl(SRCBASE, reg->srcbase);
927 tdfx_outl(DSTBASE, reg->dstbase);
928 tdfx_outl(COMMANDEXTRA_2D, 0);
929 tdfx_outl(CLIP0MIN, 0);
930 tdfx_outl(CLIP0MAX, 0x0fff0fff);
931 tdfx_outl(CLIP1MIN, 0);
932 tdfx_outl(CLIP1MAX, 0x0fff0fff);
933 tdfx_outl(SRCXY, 0);
935 banshee_wait_idle();
938 static unsigned long do_lfb_size(void) {
939 u32 draminit0 = 0;
940 u32 draminit1 = 0;
941 u32 miscinit1 = 0;
942 u32 lfbsize = 0;
943 int sgram_p = 0;
945 if(!((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) ||
946 (fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3)))
947 return 0;
949 draminit0 = tdfx_inl(DRAMINIT0);
950 draminit1 = tdfx_inl(DRAMINIT1);
952 sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
954 lfbsize = sgram_p ?
955 (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) *
956 ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
957 16 * 1024 * 1024;
959 /* disable block writes for SDRAM (why?) */
960 miscinit1 = tdfx_inl(MISCINIT1);
961 miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
962 miscinit1 |= MISCINIT1_CLUT_INV;
964 banshee_make_room(1);
965 tdfx_outl(MISCINIT1, miscinit1);
967 return lfbsize;
970 /* -------------------------------------------------------------------------
971 * Hardware independent part, interface to the world
972 * ------------------------------------------------------------------------- */
974 #define tdfx_cfb24_putc tdfx_cfb32_putc
975 #define tdfx_cfb24_putcs tdfx_cfb32_putcs
976 #define tdfx_cfb24_clear tdfx_cfb32_clear
978 static void tdfx_cfbX_clear_margins(struct vc_data* conp, struct display* p,
979 int bottom_only)
981 unsigned int cw=fontwidth(p);
982 unsigned int ch=fontheight(p);
983 unsigned int rw=p->var.xres % cw; // it be in a non-standard mode or not?
984 unsigned int bh=p->var.yres % ch;
985 unsigned int rs=p->var.xres - rw;
986 unsigned int bs=p->var.yres - bh;
988 if (!bottom_only && rw) {
989 do_fillrect( p->var.xoffset+rs, 0,
990 rw, p->var.yres_virtual, 0,
991 fb_info.current_par.lpitch,
992 fb_info.current_par.bpp, ROP_COPY);
995 if (bh) {
996 do_fillrect( p->var.xoffset, p->var.yoffset+bs,
997 rs, bh, 0,
998 fb_info.current_par.lpitch,
999 fb_info.current_par.bpp, ROP_COPY);
1002 static void tdfx_cfbX_bmove(struct display* p,
1003 int sy,
1004 int sx,
1005 int dy,
1006 int dx,
1007 int height,
1008 int width) {
1009 do_bitblt(fontwidth(p)*sx,
1010 fontheight(p)*sy,
1011 fontwidth(p)*dx,
1012 fontheight(p)*dy,
1013 fontwidth(p)*width,
1014 fontheight(p)*height,
1015 fb_info.current_par.lpitch,
1016 fb_info.current_par.bpp);
1018 static void tdfx_cfb8_putc(struct vc_data* conp,
1019 struct display* p,
1020 int c, int yy,int xx)
1022 u32 fgx,bgx;
1023 fgx=attr_fgcol(p, c);
1024 bgx=attr_bgcol(p, c);
1025 do_putc( fgx,bgx,p,c,yy,xx );
1028 static void tdfx_cfb16_putc(struct vc_data* conp,
1029 struct display* p,
1030 int c, int yy,int xx)
1032 u32 fgx,bgx;
1033 fgx=((u16*)p->dispsw_data)[attr_fgcol(p,c)];
1034 bgx=((u16*)p->dispsw_data)[attr_bgcol(p,c)];
1035 do_putc( fgx,bgx,p,c,yy,xx );
1038 static void tdfx_cfb32_putc(struct vc_data* conp,
1039 struct display* p,
1040 int c, int yy,int xx)
1042 u32 fgx,bgx;
1043 fgx=((u32*)p->dispsw_data)[attr_fgcol(p,c)];
1044 bgx=((u32*)p->dispsw_data)[attr_bgcol(p,c)];
1045 do_putc( fgx,bgx,p,c,yy,xx );
1047 static void tdfx_cfb8_putcs(struct vc_data* conp,
1048 struct display* p,
1049 const unsigned short *s,int count,int yy,int xx)
1051 u32 fgx,bgx;
1052 fgx=attr_fgcol(p, *s);
1053 bgx=attr_bgcol(p, *s);
1054 do_putcs( fgx,bgx,p,s,count,yy,xx );
1056 static void tdfx_cfb16_putcs(struct vc_data* conp,
1057 struct display* p,
1058 const unsigned short *s,int count,int yy,int xx)
1060 u32 fgx,bgx;
1061 fgx=((u16*)p->dispsw_data)[attr_fgcol(p,*s)];
1062 bgx=((u16*)p->dispsw_data)[attr_bgcol(p,*s)];
1063 do_putcs( fgx,bgx,p,s,count,yy,xx );
1065 static void tdfx_cfb32_putcs(struct vc_data* conp,
1066 struct display* p,
1067 const unsigned short *s,int count,int yy,int xx)
1069 u32 fgx,bgx;
1070 fgx=((u32*)p->dispsw_data)[attr_fgcol(p,*s)];
1071 bgx=((u32*)p->dispsw_data)[attr_bgcol(p,*s)];
1072 do_putcs( fgx,bgx,p,s,count,yy,xx );
1075 static void tdfx_cfb8_clear(struct vc_data* conp,
1076 struct display* p,
1077 int sy,
1078 int sx,
1079 int height,
1080 int width) {
1081 u32 bg;
1083 bg = attr_bgcol_ec(p,conp);
1084 do_fillrect(fontwidth(p)*sx,
1085 fontheight(p)*sy,
1086 fontwidth(p)*width,
1087 fontheight(p)*height,
1088 bg,
1089 fb_info.current_par.lpitch,
1090 fb_info.current_par.bpp,ROP_COPY);
1093 static void tdfx_cfb16_clear(struct vc_data* conp,
1094 struct display* p,
1095 int sy,
1096 int sx,
1097 int height,
1098 int width) {
1099 u32 bg;
1101 bg = ((u16*)p->dispsw_data)[attr_bgcol_ec(p,conp)];
1102 do_fillrect(fontwidth(p)*sx,
1103 fontheight(p)*sy,
1104 fontwidth(p)*width,
1105 fontheight(p)*height,
1106 bg,
1107 fb_info.current_par.lpitch,
1108 fb_info.current_par.bpp,ROP_COPY);
1111 static void tdfx_cfb32_clear(struct vc_data* conp,
1112 struct display* p,
1113 int sy,
1114 int sx,
1115 int height,
1116 int width) {
1117 u32 bg;
1119 bg = ((u32*)p->dispsw_data)[attr_bgcol_ec(p,conp)];
1120 do_fillrect(fontwidth(p)*sx,
1121 fontheight(p)*sy,
1122 fontwidth(p)*width,
1123 fontheight(p)*height,
1124 bg,
1125 fb_info.current_par.lpitch,
1126 fb_info.current_par.bpp,ROP_COPY);
1128 static void tdfx_cfbX_revc(struct display *p, int xx, int yy)
1130 int bpp=fb_info.current_par.bpp;
1132 do_fillrect( xx * fontwidth(p), yy * fontheight(p),
1133 fontwidth(p), fontheight(p),
1134 (bpp==8) ? 0x0f : 0xffffffff,
1135 fb_info.current_par.lpitch, bpp, ROP_XOR);
1138 static void tdfx_cfbX_cursor(struct display *p, int mode, int x, int y)
1140 unsigned long flags;
1141 int tip;
1142 struct fb_info_tdfx *info=(struct fb_info_tdfx *)p->fb_info;
1144 tip=p->conp->vc_cursor_type & CUR_HWMASK;
1145 if (mode==CM_ERASE) {
1146 if (info->cursor.state != CM_ERASE) {
1147 spin_lock_irqsave(&info->DAClock,flags);
1148 info->cursor.state=CM_ERASE;
1149 del_timer(&(info->cursor.timer));
1150 tdfx_outl(VIDPROCCFG,info->cursor.disable);
1151 spin_unlock_irqrestore(&info->DAClock,flags);
1153 return;
1155 if ((p->conp->vc_cursor_type & CUR_HWMASK) != info->cursor.type)
1156 tdfxfb_createcursor(p);
1157 x *= fontwidth(p);
1158 y *= fontheight(p);
1159 y -= p->var.yoffset;
1160 spin_lock_irqsave(&info->DAClock,flags);
1161 if ((x!=info->cursor.x) ||
1162 (y!=info->cursor.y) ||
1163 (info->cursor.redraw)) {
1164 info->cursor.x=x;
1165 info->cursor.y=y;
1166 info->cursor.redraw=0;
1167 x += 63;
1168 y += 63;
1169 banshee_make_room(2);
1170 tdfx_outl(VIDPROCCFG, info->cursor.disable);
1171 tdfx_outl(HWCURLOC, (y << 16) + x);
1172 /* fix cursor color - XFree86 forgets to restore it properly */
1173 tdfx_outl(HWCURC0, 0);
1174 tdfx_outl(HWCURC1, 0xffffff);
1176 info->cursor.state = CM_DRAW;
1177 mod_timer(&info->cursor.timer,jiffies+HZ/2);
1178 banshee_make_room(1);
1179 tdfx_outl(VIDPROCCFG, info->cursor.enable);
1180 spin_unlock_irqrestore(&info->DAClock,flags);
1181 return;
1183 #ifdef FBCON_HAS_CFB8
1184 static struct display_switch fbcon_banshee8 = {
1185 setup: fbcon_cfb8_setup,
1186 bmove: tdfx_cfbX_bmove,
1187 clear: tdfx_cfb8_clear,
1188 putc: tdfx_cfb8_putc,
1189 putcs: tdfx_cfb8_putcs,
1190 revc: tdfx_cfbX_revc,
1191 cursor: tdfx_cfbX_cursor,
1192 clear_margins: tdfx_cfbX_clear_margins,
1193 fontwidthmask: FONTWIDTH(8)
1195 #endif
1196 #ifdef FBCON_HAS_CFB16
1197 static struct display_switch fbcon_banshee16 = {
1198 setup: fbcon_cfb16_setup,
1199 bmove: tdfx_cfbX_bmove,
1200 clear: tdfx_cfb16_clear,
1201 putc: tdfx_cfb16_putc,
1202 putcs: tdfx_cfb16_putcs,
1203 revc: tdfx_cfbX_revc,
1204 cursor: tdfx_cfbX_cursor,
1205 clear_margins: tdfx_cfbX_clear_margins,
1206 fontwidthmask: FONTWIDTH(8)
1208 #endif
1209 #ifdef FBCON_HAS_CFB24
1210 static struct display_switch fbcon_banshee24 = {
1211 setup: fbcon_cfb24_setup,
1212 bmove: tdfx_cfbX_bmove,
1213 clear: tdfx_cfb24_clear,
1214 putc: tdfx_cfb24_putc,
1215 putcs: tdfx_cfb24_putcs,
1216 revc: tdfx_cfbX_revc,
1217 cursor: tdfx_cfbX_cursor,
1218 clear_margins: tdfx_cfbX_clear_margins,
1219 fontwidthmask: FONTWIDTH(8)
1221 #endif
1222 #ifdef FBCON_HAS_CFB32
1223 static struct display_switch fbcon_banshee32 = {
1224 setup: fbcon_cfb32_setup,
1225 bmove: tdfx_cfbX_bmove,
1226 clear: tdfx_cfb32_clear,
1227 putc: tdfx_cfb32_putc,
1228 putcs: tdfx_cfb32_putcs,
1229 revc: tdfx_cfbX_revc,
1230 cursor: tdfx_cfbX_cursor,
1231 clear_margins: tdfx_cfbX_clear_margins,
1232 fontwidthmask: FONTWIDTH(8)
1234 #endif
1236 /* ------------------------------------------------------------------------- */
1238 static void tdfxfb_set_par(const struct tdfxfb_par* par,
1239 struct fb_info_tdfx* info) {
1240 struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
1241 struct banshee_reg reg;
1242 u32 cpp;
1243 u32 hd, hs, he, ht, hbs, hbe;
1244 u32 vd, vs, ve, vt, vbs, vbe;
1245 u32 wd;
1246 int fout;
1247 int freq;
1249 memset(&reg, 0, sizeof(reg));
1251 cpp = (par->bpp + 7)/8;
1253 wd = (par->hdispend >> 3) - 1;
1255 hd = (par->hdispend >> 3) - 1;
1256 hs = (par->hsyncsta >> 3) - 1;
1257 he = (par->hsyncend >> 3) - 1;
1258 ht = (par->htotal >> 3) - 1;
1259 hbs = hd;
1260 hbe = ht;
1262 vd = par->vdispend - 1;
1263 vs = par->vsyncsta - 1;
1264 ve = par->vsyncend - 1;
1265 vt = par->vtotal - 2;
1266 vbs = vd;
1267 vbe = vt;
1269 /* this is all pretty standard VGA register stuffing */
1270 reg.misc[0x00] =
1271 0x0f |
1272 (par->hdispend < 400 ? 0xa0 :
1273 par->hdispend < 480 ? 0x60 :
1274 par->hdispend < 768 ? 0xe0 : 0x20);
1276 reg.gra[0x00] = 0x00;
1277 reg.gra[0x01] = 0x00;
1278 reg.gra[0x02] = 0x00;
1279 reg.gra[0x03] = 0x00;
1280 reg.gra[0x04] = 0x00;
1281 reg.gra[0x05] = 0x40;
1282 reg.gra[0x06] = 0x05;
1283 reg.gra[0x07] = 0x0f;
1284 reg.gra[0x08] = 0xff;
1286 reg.att[0x00] = 0x00;
1287 reg.att[0x01] = 0x01;
1288 reg.att[0x02] = 0x02;
1289 reg.att[0x03] = 0x03;
1290 reg.att[0x04] = 0x04;
1291 reg.att[0x05] = 0x05;
1292 reg.att[0x06] = 0x06;
1293 reg.att[0x07] = 0x07;
1294 reg.att[0x08] = 0x08;
1295 reg.att[0x09] = 0x09;
1296 reg.att[0x0a] = 0x0a;
1297 reg.att[0x0b] = 0x0b;
1298 reg.att[0x0c] = 0x0c;
1299 reg.att[0x0d] = 0x0d;
1300 reg.att[0x0e] = 0x0e;
1301 reg.att[0x0f] = 0x0f;
1302 reg.att[0x10] = 0x41;
1303 reg.att[0x11] = 0x00;
1304 reg.att[0x12] = 0x0f;
1305 reg.att[0x13] = 0x00;
1306 reg.att[0x14] = 0x00;
1308 reg.seq[0x00] = 0x03;
1309 reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
1310 reg.seq[0x02] = 0x0f;
1311 reg.seq[0x03] = 0x00;
1312 reg.seq[0x04] = 0x0e;
1314 reg.crt[0x00] = ht - 4;
1315 reg.crt[0x01] = hd;
1316 reg.crt[0x02] = hbs;
1317 reg.crt[0x03] = 0x80 | (hbe & 0x1f);
1318 reg.crt[0x04] = hs;
1319 reg.crt[0x05] =
1320 ((hbe & 0x20) << 2) |
1321 (he & 0x1f);
1322 reg.crt[0x06] = vt;
1323 reg.crt[0x07] =
1324 ((vs & 0x200) >> 2) |
1325 ((vd & 0x200) >> 3) |
1326 ((vt & 0x200) >> 4) |
1327 0x10 |
1328 ((vbs & 0x100) >> 5) |
1329 ((vs & 0x100) >> 6) |
1330 ((vd & 0x100) >> 7) |
1331 ((vt & 0x100) >> 8);
1332 reg.crt[0x08] = 0x00;
1333 reg.crt[0x09] =
1334 0x40 |
1335 ((vbs & 0x200) >> 4);
1336 reg.crt[0x0a] = 0x00;
1337 reg.crt[0x0b] = 0x00;
1338 reg.crt[0x0c] = 0x00;
1339 reg.crt[0x0d] = 0x00;
1340 reg.crt[0x0e] = 0x00;
1341 reg.crt[0x0f] = 0x00;
1342 reg.crt[0x10] = vs;
1343 reg.crt[0x11] =
1344 (ve & 0x0f) |
1345 0x20;
1346 reg.crt[0x12] = vd;
1347 reg.crt[0x13] = wd;
1348 reg.crt[0x14] = 0x00;
1349 reg.crt[0x15] = vbs;
1350 reg.crt[0x16] = vbe + 1;
1351 reg.crt[0x17] = 0xc3;
1352 reg.crt[0x18] = 0xff;
1354 /* Banshee's nonvga stuff */
1355 reg.ext[0x00] = (((ht & 0x100) >> 8) |
1356 ((hd & 0x100) >> 6) |
1357 ((hbs & 0x100) >> 4) |
1358 ((hbe & 0x40) >> 1) |
1359 ((hs & 0x100) >> 2) |
1360 ((he & 0x20) << 2));
1361 reg.ext[0x01] = (((vt & 0x400) >> 10) |
1362 ((vd & 0x400) >> 8) |
1363 ((vbs & 0x400) >> 6) |
1364 ((vbe & 0x400) >> 4));
1366 reg.vgainit0 =
1367 VGAINIT0_8BIT_DAC |
1368 VGAINIT0_EXT_ENABLE |
1369 VGAINIT0_WAKEUP_3C3 |
1370 VGAINIT0_ALT_READBACK |
1371 VGAINIT0_EXTSHIFTOUT;
1372 reg.vgainit1 = tdfx_inl(VGAINIT1) & 0x1fffff;
1374 reg.vidcfg =
1375 VIDCFG_VIDPROC_ENABLE |
1376 VIDCFG_DESK_ENABLE |
1377 VIDCFG_CURS_X11 |
1378 ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
1379 (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
1381 fb_info.cursor.enable=reg.vidcfg | VIDCFG_HWCURSOR_ENABLE;
1382 fb_info.cursor.disable=reg.vidcfg;
1384 reg.stride = par->width*cpp;
1385 reg.cursloc = 0;
1387 reg.cursc0 = 0;
1388 reg.cursc1 = 0xffffff;
1390 reg.curspataddr = fb_info.cursor.cursorimage;
1392 reg.startaddr = par->baseline*reg.stride;
1393 reg.srcbase = reg.startaddr;
1394 reg.dstbase = reg.startaddr;
1396 /* PLL settings */
1397 freq = par->pixclock;
1399 reg.dacmode &= ~DACMODE_2X;
1400 reg.vidcfg &= ~VIDCFG_2X;
1401 if(freq > i->max_pixclock/2) {
1402 freq = freq > i->max_pixclock ? i->max_pixclock : freq;
1403 reg.dacmode |= DACMODE_2X;
1404 reg.vidcfg |= VIDCFG_2X;
1406 reg.vidpll = do_calc_pll(freq, &fout);
1407 #if 0
1408 reg.mempll = do_calc_pll(..., &fout);
1409 reg.gfxpll = do_calc_pll(..., &fout);
1410 #endif
1412 reg.screensize = par->width | (par->height << 12);
1413 reg.vidcfg &= ~VIDCFG_HALF_MODE;
1415 do_write_regs(&reg);
1417 i->current_par = *par;
1421 static int tdfxfb_decode_var(const struct fb_var_screeninfo* var,
1422 struct tdfxfb_par* par,
1423 const struct fb_info_tdfx* info) {
1424 struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
1426 if(var->bits_per_pixel != 8 &&
1427 var->bits_per_pixel != 16 &&
1428 var->bits_per_pixel != 24 &&
1429 var->bits_per_pixel != 32) {
1430 DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
1431 return -EINVAL;
1434 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1435 DPRINTK("interlace not supported\n");
1436 return -EINVAL;
1439 if(var->xoffset) {
1440 DPRINTK("xoffset not supported\n");
1441 return -EINVAL;
1444 if(var->xres != var->xres_virtual) {
1445 DPRINTK("virtual x resolution != physical x resolution not supported\n");
1446 return -EINVAL;
1449 if(var->yres > var->yres_virtual) {
1450 DPRINTK("virtual y resolution < physical y resolution not possible\n");
1451 return -EINVAL;
1454 /* fixme: does Voodoo3 support interlace? Banshee doesn't */
1455 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1456 DPRINTK("interlace not supported\n");
1457 return -EINVAL;
1460 memset(par, 0, sizeof(struct tdfxfb_par));
1462 switch(i->dev) {
1463 case PCI_DEVICE_ID_3DFX_BANSHEE:
1464 case PCI_DEVICE_ID_3DFX_VOODOO3:
1465 par->width = (var->xres + 15) & ~15; /* could sometimes be 8 */
1466 par->width_virt = par->width;
1467 par->height = var->yres;
1468 par->height_virt = var->yres_virtual;
1469 par->bpp = var->bits_per_pixel;
1470 par->ppitch = var->bits_per_pixel;
1471 par->lpitch = par->width* ((par->ppitch+7)>>3);
1472 par->cmap_len = (par->bpp == 8) ? 256 : 16;
1474 par->baseline = 0;
1476 if(par->width < 320 || par->width > 2048) {
1477 DPRINTK("width not supported: %u\n", par->width);
1478 return -EINVAL;
1480 if(par->height < 200 || par->height > 2048) {
1481 DPRINTK("height not supported: %u\n", par->height);
1482 return -EINVAL;
1484 if(par->lpitch*par->height_virt > i->bufbase_size) {
1485 DPRINTK("no memory for screen (%ux%ux%u)\n",
1486 par->width, par->height_virt, par->bpp);
1487 return -EINVAL;
1489 par->pixclock = PICOS2KHZ(var->pixclock);
1490 if(par->pixclock > i->max_pixclock) {
1491 DPRINTK("pixclock too high (%uKHz)\n", par->pixclock);
1492 return -EINVAL;
1495 par->hdispend = var->xres;
1496 par->hsyncsta = par->hdispend + var->right_margin;
1497 par->hsyncend = par->hsyncsta + var->hsync_len;
1498 par->htotal = par->hsyncend + var->left_margin;
1500 par->vdispend = var->yres;
1501 par->vsyncsta = par->vdispend + var->lower_margin;
1502 par->vsyncend = par->vsyncsta + var->vsync_len;
1503 par->vtotal = par->vsyncend + var->upper_margin;
1505 if(var->sync & FB_SYNC_HOR_HIGH_ACT)
1506 par->video |= TDFXF_HSYNC_ACT_HIGH;
1507 else
1508 par->video |= TDFXF_HSYNC_ACT_LOW;
1509 if(var->sync & FB_SYNC_VERT_HIGH_ACT)
1510 par->video |= TDFXF_VSYNC_ACT_HIGH;
1511 else
1512 par->video |= TDFXF_VSYNC_ACT_LOW;
1513 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
1514 par->video |= TDFXF_LINE_DOUBLE;
1515 if(var->activate == FB_ACTIVATE_NOW)
1516 par->video |= TDFXF_VIDEO_ENABLE;
1519 if(var->accel_flags & FB_ACCELF_TEXT)
1520 par->accel_flags = FB_ACCELF_TEXT;
1521 else
1522 par->accel_flags = 0;
1524 return 0;
1527 static int tdfxfb_encode_var(struct fb_var_screeninfo* var,
1528 const struct tdfxfb_par* par,
1529 const struct fb_info_tdfx* info) {
1530 struct fb_var_screeninfo v;
1532 memset(&v, 0, sizeof(struct fb_var_screeninfo));
1533 v.xres_virtual = par->width_virt;
1534 v.yres_virtual = par->height_virt;
1535 v.xres = par->width;
1536 v.yres = par->height;
1537 v.right_margin = par->hsyncsta - par->hdispend;
1538 v.hsync_len = par->hsyncend - par->hsyncsta;
1539 v.left_margin = par->htotal - par->hsyncend;
1540 v.lower_margin = par->vsyncsta - par->vdispend;
1541 v.vsync_len = par->vsyncend - par->vsyncsta;
1542 v.upper_margin = par->vtotal - par->vsyncend;
1543 v.bits_per_pixel = par->bpp;
1544 switch(par->bpp) {
1545 case 8:
1546 v.red.length = v.green.length = v.blue.length = 8;
1547 break;
1548 case 16:
1549 v.red.offset = 11;
1550 v.red.length = 5;
1551 v.green.offset = 5;
1552 v.green.length = 6;
1553 v.blue.offset = 0;
1554 v.blue.length = 5;
1555 break;
1556 case 24:
1557 v.red.offset=16;
1558 v.green.offset=8;
1559 v.blue.offset=0;
1560 v.red.length = v.green.length = v.blue.length = 8;
1561 case 32:
1562 v.red.offset = 16;
1563 v.green.offset = 8;
1564 v.blue.offset = 0;
1565 v.red.length = v.green.length = v.blue.length = 8;
1566 break;
1568 v.height = v.width = -1;
1569 v.pixclock = KHZ2PICOS(par->pixclock);
1570 if((par->video & TDFXF_HSYNC_MASK) == TDFXF_HSYNC_ACT_HIGH)
1571 v.sync |= FB_SYNC_HOR_HIGH_ACT;
1572 if((par->video & TDFXF_VSYNC_MASK) == TDFXF_VSYNC_ACT_HIGH)
1573 v.sync |= FB_SYNC_VERT_HIGH_ACT;
1574 if(par->video & TDFXF_LINE_DOUBLE)
1575 v.vmode = FB_VMODE_DOUBLE;
1576 *var = v;
1577 return 0;
1580 static int tdfxfb_encode_fix(struct fb_fix_screeninfo* fix,
1581 const struct tdfxfb_par* par,
1582 const struct fb_info_tdfx* info) {
1583 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1585 switch(info->dev) {
1586 case PCI_DEVICE_ID_3DFX_BANSHEE:
1587 case PCI_DEVICE_ID_3DFX_VOODOO3:
1588 strcpy(fix->id,
1589 info->dev == PCI_DEVICE_ID_3DFX_BANSHEE
1590 ? "3Dfx Banshee"
1591 : "3Dfx Voodoo3");
1592 fix->smem_start = info->bufbase_phys;
1593 fix->smem_len = info->bufbase_size;
1594 fix->mmio_start = info->regbase_phys;
1595 fix->mmio_len = info->regbase_size;
1596 fix->accel = FB_ACCEL_3DFX_BANSHEE;
1597 fix->type = FB_TYPE_PACKED_PIXELS;
1598 fix->type_aux = 0;
1599 fix->line_length = par->lpitch;
1600 fix->visual = (par->bpp == 8)
1601 ? FB_VISUAL_PSEUDOCOLOR
1602 : FB_VISUAL_DIRECTCOLOR;
1604 fix->xpanstep = 0;
1605 fix->ypanstep = nopan ? 0 : 1;
1606 fix->ywrapstep = nowrap ? 0 : 1;
1608 break;
1609 default:
1610 return -EINVAL;
1613 return 0;
1616 static int tdfxfb_get_fix(struct fb_fix_screeninfo *fix,
1617 int con,
1618 struct fb_info *fb) {
1619 const struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
1620 struct tdfxfb_par par;
1622 if(con == -1)
1623 par = info->default_par;
1624 else
1625 tdfxfb_decode_var(&fb_display[con].var, &par, info);
1626 tdfxfb_encode_fix(fix, &par, info);
1627 return 0;
1630 static int tdfxfb_get_var(struct fb_var_screeninfo *var,
1631 int con,
1632 struct fb_info *fb) {
1633 const struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
1635 if(con == -1)
1636 tdfxfb_encode_var(var, &info->default_par, info);
1637 else
1638 *var = fb_display[con].var;
1639 return 0;
1642 static void tdfxfb_set_dispsw(struct display *disp,
1643 struct fb_info_tdfx *info,
1644 int bpp,
1645 int accel) {
1647 if (disp->dispsw && disp->conp)
1648 fb_con.con_cursor(disp->conp, CM_ERASE);
1649 switch(bpp) {
1650 #ifdef FBCON_HAS_CFB8
1651 case 8:
1652 disp->dispsw = noaccel ? &fbcon_cfb8 : &fbcon_banshee8;
1653 if (nohwcursor) fbcon_banshee8.cursor = NULL;
1654 break;
1655 #endif
1656 #ifdef FBCON_HAS_CFB16
1657 case 16:
1658 disp->dispsw = noaccel ? &fbcon_cfb16 : &fbcon_banshee16;
1659 disp->dispsw_data = info->fbcon_cmap.cfb16;
1660 if (nohwcursor) fbcon_banshee16.cursor = NULL;
1661 break;
1662 #endif
1663 #ifdef FBCON_HAS_CFB24
1664 case 24:
1665 disp->dispsw = noaccel ? &fbcon_cfb24 : &fbcon_banshee24;
1666 disp->dispsw_data = info->fbcon_cmap.cfb24;
1667 if (nohwcursor) fbcon_banshee24.cursor = NULL;
1668 break;
1669 #endif
1670 #ifdef FBCON_HAS_CFB32
1671 case 32:
1672 disp->dispsw = noaccel ? &fbcon_cfb32 : &fbcon_banshee32;
1673 disp->dispsw_data = info->fbcon_cmap.cfb32;
1674 if (nohwcursor) fbcon_banshee32.cursor = NULL;
1675 break;
1676 #endif
1677 default:
1678 disp->dispsw = &fbcon_dummy;
1683 static int tdfxfb_set_var(struct fb_var_screeninfo *var,
1684 int con,
1685 struct fb_info *fb) {
1686 struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
1687 struct tdfxfb_par par;
1688 struct display *display;
1689 int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
1690 int activate = var->activate;
1691 int j,k;
1693 if(con >= 0)
1694 display = &fb_display[con];
1695 else
1696 display = fb->disp; /* used during initialization */
1698 if((err = tdfxfb_decode_var(var, &par, info)))
1699 return err;
1701 tdfxfb_encode_var(var, &par, info);
1703 if((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1704 oldxres = display->var.xres;
1705 oldyres = display->var.yres;
1706 oldvxres = display->var.xres_virtual;
1707 oldvyres = display->var.yres_virtual;
1708 oldbpp = display->var.bits_per_pixel;
1709 oldaccel = display->var.accel_flags;
1710 display->var = *var;
1711 if(con < 0 ||
1712 oldxres != var->xres ||
1713 oldyres != var->yres ||
1714 oldvxres != var->xres_virtual ||
1715 oldvyres != var->yres_virtual ||
1716 oldbpp != var->bits_per_pixel ||
1717 oldaccel != var->accel_flags) {
1718 struct fb_fix_screeninfo fix;
1720 tdfxfb_encode_fix(&fix, &par, info);
1721 display->screen_base = info->bufbase_virt;
1722 display->visual = fix.visual;
1723 display->type = fix.type;
1724 display->type_aux = fix.type_aux;
1725 display->ypanstep = fix.ypanstep;
1726 display->ywrapstep = fix.ywrapstep;
1727 display->line_length = fix.line_length;
1728 display->next_line = fix.line_length;
1729 display->can_soft_blank = 1;
1730 display->inverse = inverse;
1731 accel = var->accel_flags & FB_ACCELF_TEXT;
1732 tdfxfb_set_dispsw(display, info, par.bpp, accel);
1734 if(nopan) display->scrollmode = SCROLL_YREDRAW;
1736 if (info->fb_info.changevar)
1737 (*info->fb_info.changevar)(con);
1739 if (var->bits_per_pixel==8)
1740 for(j = 0; j < 16; j++) {
1741 k = color_table[j];
1742 fb_info.palette[j].red = default_red[k];
1743 fb_info.palette[j].green = default_grn[k];
1744 fb_info.palette[j].blue = default_blu[k];
1747 del_timer(&(info->cursor.timer));
1748 fb_info.cursor.state=CM_ERASE;
1749 if(!info->fb_info.display_fg ||
1750 info->fb_info.display_fg->vc_num == con ||
1751 con < 0)
1752 tdfxfb_set_par(&par, info);
1753 if (!nohwcursor)
1754 if (display && display->conp)
1755 tdfxfb_createcursor( display );
1756 info->cursor.redraw=1;
1757 if(oldbpp != var->bits_per_pixel || con < 0) {
1758 if((err = fb_alloc_cmap(&display->cmap, 0, 0)))
1759 return err;
1760 tdfxfb_install_cmap(display, &(info->fb_info));
1764 return 0;
1767 static int tdfxfb_pan_display(struct fb_var_screeninfo* var,
1768 int con,
1769 struct fb_info* fb) {
1770 struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
1772 if(nopan) return -EINVAL;
1773 if(var->xoffset) return -EINVAL;
1774 if(var->yoffset > var->yres_virtual) return -EINVAL;
1775 if(nowrap &&
1776 (var->yoffset + var->yres > var->yres_virtual)) return -EINVAL;
1778 if (con==currcon)
1779 do_pan_var(var,i);
1781 fb_display[con].var.xoffset=var->xoffset;
1782 fb_display[con].var.yoffset=var->yoffset;
1783 return 0;
1786 static int tdfxfb_get_cmap(struct fb_cmap *cmap,
1787 int kspc,
1788 int con,
1789 struct fb_info *fb) {
1791 struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
1792 struct display *d=(con<0) ? fb->disp : fb_display + con;
1794 if(con == currcon) {
1795 /* current console? */
1796 return fb_get_cmap(cmap, kspc, tdfxfb_getcolreg, fb);
1797 } else if(d->cmap.len) {
1798 /* non default colormap? */
1799 fb_copy_cmap(&d->cmap, cmap, kspc ? 0 : 2);
1800 } else {
1801 fb_copy_cmap(fb_default_cmap(i->current_par.cmap_len), cmap, kspc ? 0 : 2);
1803 return 0;
1806 static int tdfxfb_set_cmap(struct fb_cmap *cmap,
1807 int kspc,
1808 int con,
1809 struct fb_info *fb) {
1810 struct display *d=(con<0) ? fb->disp : fb_display + con;
1811 struct fb_info_tdfx *i = (struct fb_info_tdfx*)fb;
1813 int cmap_len= (i->current_par.bpp == 8) ? 256 : 16;
1814 if (d->cmap.len!=cmap_len) {
1815 int err;
1816 if((err = fb_alloc_cmap(&d->cmap, cmap_len, 0)))
1817 return err;
1819 if(con == currcon) {
1820 /* current console? */
1821 return fb_set_cmap(cmap, kspc, tdfxfb_setcolreg, fb);
1822 } else {
1823 fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1);
1825 return 0;
1828 static int tdfxfb_ioctl(struct inode *inode,
1829 struct file *file,
1830 u_int cmd,
1831 u_long arg,
1832 int con,
1833 struct fb_info *fb) {
1834 /* These IOCTLs ar just for testing only...
1835 switch (cmd) {
1836 case 0x4680:
1837 nowrap=nopan=0;
1838 return 0;
1839 case 0x4681:
1840 nowrap=nopan=1;
1841 return 0;
1843 return -EINVAL;
1846 int __init tdfxfb_init(void) {
1847 struct pci_dev *pdev = NULL;
1848 struct fb_var_screeninfo var;
1850 while ((pdev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_ANY_ID, pdev))) {
1851 if(((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
1852 ((pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE) ||
1853 (pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3))) {
1854 char* name = pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE
1855 ? "Banshee"
1856 : "Voodoo3";
1858 fb_info.dev = pdev->device;
1859 fb_info.max_pixclock =
1860 pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE
1861 ? BANSHEE_MAX_PIXCLOCK
1862 : VOODOO3_MAX_PIXCLOCK;
1864 fb_info.regbase_phys = pci_resource_start(pdev, 0);
1865 fb_info.regbase_size = 1 << 24;
1866 fb_info.regbase_virt = ioremap_nocache(fb_info.regbase_phys, 1 << 24);
1867 if(!fb_info.regbase_virt) {
1868 printk("fb: Can't remap %s register area.\n", name);
1869 return -ENXIO;
1872 fb_info.bufbase_phys = pci_resource_start (pdev, 1);
1873 if(!(fb_info.bufbase_size = do_lfb_size())) {
1874 iounmap(fb_info.regbase_virt);
1875 printk("fb: Can't count %s memory.\n", name);
1876 return -ENXIO;
1878 fb_info.bufbase_virt = ioremap_nocache(fb_info.bufbase_phys, fb_info.bufbase_size);
1879 if(!fb_info.regbase_virt) {
1880 printk("fb: Can't remap %s framebuffer.\n", name);
1881 iounmap(fb_info.regbase_virt);
1882 return -ENXIO;
1885 fb_info.iobase = pci_resource_start (pdev, 2);
1887 printk("fb: %s memory = %ldK\n", name, fb_info.bufbase_size >> 10);
1889 #ifdef CONFIG_MTRR
1890 if (!nomtrr) {
1891 fb_info.mtrr_idx = mtrr_add(fb_info.bufbase_phys, fb_info.bufbase_size,
1892 MTRR_TYPE_WRCOMB, 1);
1893 printk("fb: MTRR's turned on\n");
1895 #endif
1897 /* clear framebuffer memory */
1898 memset_io(fb_info.bufbase_virt, 0, fb_info.bufbase_size);
1899 currcon = -1;
1900 if (!nohwcursor) tdfxfb_hwcursor_init();
1902 init_timer(&fb_info.cursor.timer);
1903 fb_info.cursor.timer.function = do_flashcursor;
1904 fb_info.cursor.timer.data = (unsigned long)(&fb_info);
1905 fb_info.cursor.state = CM_ERASE;
1906 spin_lock_init(&fb_info.DAClock);
1908 strcpy(fb_info.fb_info.modename, "3Dfx ");
1909 strcat(fb_info.fb_info.modename, name);
1910 fb_info.fb_info.changevar = NULL;
1911 fb_info.fb_info.node = -1;
1912 fb_info.fb_info.fbops = &tdfxfb_ops;
1913 fb_info.fb_info.disp = &fb_info.disp;
1914 strcpy(fb_info.fb_info.fontname, fontname);
1915 fb_info.fb_info.switch_con = &tdfxfb_switch_con;
1916 fb_info.fb_info.updatevar = &tdfxfb_updatevar;
1917 fb_info.fb_info.blank = &tdfxfb_blank;
1918 fb_info.fb_info.flags = FBINFO_FLAG_DEFAULT;
1920 memset(&var, 0, sizeof(var));
1921 if(!mode_option ||
1922 !fb_find_mode(&var, &fb_info.fb_info, mode_option, NULL, 0, NULL, 8))
1923 var = default_mode[0].var;
1925 if(noaccel) var.accel_flags &= ~FB_ACCELF_TEXT;
1926 else var.accel_flags |= FB_ACCELF_TEXT;
1928 if(tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
1929 /* ugh -- can't use the mode from the mode db. (or command line),
1930 so try the default */
1932 printk("tdfxfb: "
1933 "can't decode the supplied video mode, using default\n");
1935 var = default_mode[0].var;
1936 if(noaccel) var.accel_flags &= ~FB_ACCELF_TEXT;
1937 else var.accel_flags |= FB_ACCELF_TEXT;
1939 if(tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
1940 /* this is getting really bad!... */
1941 printk("tdfxfb: can't decode default video mode\n");
1942 return -ENXIO;
1946 fb_info.disp.screen_base = fb_info.bufbase_virt;
1947 fb_info.disp.var = var;
1949 if(tdfxfb_set_var(&var, -1, &fb_info.fb_info)) {
1950 printk("tdfxfb: can't set default video mode\n");
1951 return -ENXIO;
1954 if(register_framebuffer(&fb_info.fb_info) < 0) {
1955 printk("tdfxfb: can't register framebuffer\n");
1956 return -ENXIO;
1959 printk("fb%d: %s frame buffer device\n",
1960 GET_FB_IDX(fb_info.fb_info.node),
1961 fb_info.fb_info.modename);
1963 /* FIXME: module cannot be unloaded */
1964 /* verify tdfxfb_exit before removing this */
1965 MOD_INC_USE_COUNT;
1967 return 0;
1971 /* hmm, no frame suitable buffer found ... */
1972 return -ENXIO;
1976 * tdfxfb_exit - Driver cleanup
1978 * Releases all resources allocated during the
1979 * course of the driver's lifetime.
1981 * FIXME - do results of fb_alloc_cmap need disposal?
1983 static void __exit tdfxfb_exit (void)
1985 unregister_framebuffer(&fb_info.fb_info);
1986 del_timer_sync(&fb_info.cursor.timer);
1988 #ifdef CONFIG_MTRR
1989 if (!nomtrr) {
1990 mtrr_del(fb_info.mtrr_idx, fb_info.bufbase_phys, fb_info.bufbase_size);
1991 printk("fb: MTRR's turned off\n");
1993 #endif
1995 iounmap(fb_info.regbase_virt);
1996 iounmap(fb_info.bufbase_virt);
1999 MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>");
2000 MODULE_DESCRIPTION("3Dfx framebuffer device driver");
2002 #ifdef MODULE
2003 module_init(tdfxfb_init);
2004 #endif
2005 module_exit(tdfxfb_exit);
2008 #ifndef MODULE
2009 void tdfxfb_setup(char *options,
2010 int *ints) {
2011 char* this_opt;
2013 if(!options || !*options)
2014 return;
2016 for(this_opt = strtok(options, ",");
2017 this_opt;
2018 this_opt = strtok(NULL, ",")) {
2019 if(!strcmp(this_opt, "inverse")) {
2020 inverse = 1;
2021 fb_invert_cmaps();
2022 } else if(!strcmp(this_opt, "noaccel")) {
2023 noaccel = nopan = nowrap = nohwcursor = 1;
2024 } else if(!strcmp(this_opt, "nopan")) {
2025 nopan = 1;
2026 } else if(!strcmp(this_opt, "nowrap")) {
2027 nowrap = 1;
2028 } else if (!strcmp(this_opt, "nohwcursor")) {
2029 nohwcursor = 1;
2030 #ifdef CONFIG_MTRR
2031 } else if (!strcmp(this_opt, "nomtrr")) {
2032 nomtrr = 1;
2033 #endif
2034 } else if (!strncmp(this_opt, "font:", 5)) {
2035 strncpy(fontname, this_opt + 5, 40);
2036 } else {
2037 mode_option = this_opt;
2041 #endif
2043 static int tdfxfb_switch_con(int con,
2044 struct fb_info *fb) {
2045 struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
2046 struct tdfxfb_par par;
2047 int old_con = currcon;
2048 int set_par = 1;
2050 /* Do we have to save the colormap? */
2051 if (currcon>=0)
2052 if(fb_display[currcon].cmap.len)
2053 fb_get_cmap(&fb_display[currcon].cmap, 1, tdfxfb_getcolreg, fb);
2055 currcon = con;
2056 fb_display[currcon].var.activate = FB_ACTIVATE_NOW;
2057 tdfxfb_decode_var(&fb_display[con].var, &par, info);
2058 if (old_con>=0 && vt_cons[old_con]->vc_mode!=KD_GRAPHICS) {
2059 /* check if we have to change video registers */
2060 struct tdfxfb_par old_par;
2061 tdfxfb_decode_var(&fb_display[old_con].var, &old_par, info);
2062 if (!memcmp(&par,&old_par,sizeof(par)))
2063 set_par = 0; /* avoid flicker */
2065 if (set_par)
2066 tdfxfb_set_par(&par, info);
2068 if (fb_display[con].dispsw && fb_display[con].conp)
2069 fb_con.con_cursor(fb_display[con].conp, CM_ERASE);
2071 del_timer(&(info->cursor.timer));
2072 fb_info.cursor.state=CM_ERASE;
2074 if (!nohwcursor)
2075 if (fb_display[con].conp)
2076 tdfxfb_createcursor( &fb_display[con] );
2078 info->cursor.redraw=1;
2080 tdfxfb_set_dispsw(&fb_display[con],
2081 info,
2082 par.bpp,
2083 par.accel_flags & FB_ACCELF_TEXT);
2085 tdfxfb_install_cmap(&fb_display[con], fb);
2086 tdfxfb_updatevar(con, fb);
2088 return 1;
2091 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
2092 static void tdfxfb_blank(int blank,
2093 struct fb_info *fb) {
2094 u32 dacmode, state = 0, vgablank = 0;
2096 dacmode = tdfx_inl(DACMODE);
2098 switch(blank) {
2099 case 0: /* Screen: On; HSync: On, VSync: On */
2100 state = 0;
2101 vgablank = 0;
2102 break;
2103 case 1: /* Screen: Off; HSync: On, VSync: On */
2104 state = 0;
2105 vgablank = 1;
2106 break;
2107 case 2: /* Screen: Off; HSync: On, VSync: Off */
2108 state = BIT(3);
2109 vgablank = 1;
2110 break;
2111 case 3: /* Screen: Off; HSync: Off, VSync: On */
2112 state = BIT(1);
2113 vgablank = 1;
2114 break;
2115 case 4: /* Screen: Off; HSync: Off, VSync: Off */
2116 state = BIT(1) | BIT(3);
2117 vgablank = 1;
2118 break;
2121 dacmode &= ~(BIT(1) | BIT(3));
2122 dacmode |= state;
2123 banshee_make_room(1);
2124 tdfx_outl(DACMODE, dacmode);
2125 if(vgablank)
2126 vga_disable_video();
2127 else
2128 vga_enable_video();
2130 return;
2133 static int tdfxfb_updatevar(int con,
2134 struct fb_info* fb) {
2136 struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
2137 if ((con==currcon) && (!nopan))
2138 do_pan_var(&fb_display[con].var,i);
2139 return 0;
2142 static int tdfxfb_getcolreg(unsigned regno,
2143 unsigned* red,
2144 unsigned* green,
2145 unsigned* blue,
2146 unsigned* transp,
2147 struct fb_info* fb) {
2148 struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
2150 if (regno > i->current_par.cmap_len) return 1;
2152 *red = i->palette[regno].red;
2153 *green = i->palette[regno].green;
2154 *blue = i->palette[regno].blue;
2155 *transp = 0;
2157 return 0;
2160 static int tdfxfb_setcolreg(unsigned regno,
2161 unsigned red,
2162 unsigned green,
2163 unsigned blue,
2164 unsigned transp,
2165 struct fb_info* info) {
2166 struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
2167 u32 rgbcol;
2168 if (regno >= i->current_par.cmap_len) return 1;
2170 i->palette[regno].red = red;
2171 i->palette[regno].green = green;
2172 i->palette[regno].blue = blue;
2174 switch(i->current_par.bpp) {
2175 #ifdef FBCON_HAS_CFB8
2176 case 8:
2177 rgbcol=(((u32)red & 0xff00) << 8) |
2178 (((u32)green & 0xff00) << 0) |
2179 (((u32)blue & 0xff00) >> 8);
2180 do_setpalentry(regno,rgbcol);
2181 break;
2182 #endif
2183 #ifdef FBCON_HAS_CFB16
2184 case 16:
2185 i->fbcon_cmap.cfb16[regno] =
2186 (((u32)red & 0xf800) >> 0) |
2187 (((u32)green & 0xfc00) >> 5) |
2188 (((u32)blue & 0xf800) >> 11);
2189 break;
2190 #endif
2191 #ifdef FBCON_HAS_CFB24
2192 case 24:
2193 i->fbcon_cmap.cfb24[regno] =
2194 (((u32)red & 0xff00) << 8) |
2195 (((u32)green & 0xff00) << 0) |
2196 (((u32)blue & 0xff00) >> 8);
2197 break;
2198 #endif
2199 #ifdef FBCON_HAS_CFB32
2200 case 32:
2201 i->fbcon_cmap.cfb32[regno] =
2202 (((u32)red & 0xff00) << 8) |
2203 (((u32)green & 0xff00) << 0) |
2204 (((u32)blue & 0xff00) >> 8);
2205 break;
2206 #endif
2207 default:
2208 DPRINTK("bad depth %u\n", i->current_par.bpp);
2209 break;
2211 return 0;
2214 static void tdfxfb_install_cmap(struct display *d,struct fb_info *info)
2216 struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
2218 if(d->cmap.len) {
2219 fb_set_cmap(&(d->cmap), 1, tdfxfb_setcolreg, info);
2220 } else {
2221 fb_set_cmap(fb_default_cmap(i->current_par.cmap_len), 1,
2222 tdfxfb_setcolreg, info);
2226 static void tdfxfb_createcursorshape(struct display* p)
2228 unsigned int h,cu,cd;
2230 h=fontheight(p);
2231 cd=h;
2232 if (cd >= 10) cd --;
2233 fb_info.cursor.type=p->conp->vc_cursor_type & CUR_HWMASK;
2234 switch (fb_info.cursor.type) {
2235 case CUR_NONE:
2236 cu=cd;
2237 break;
2238 case CUR_UNDERLINE:
2239 cu=cd - 2;
2240 break;
2241 case CUR_LOWER_THIRD:
2242 cu=(h * 2) / 3;
2243 break;
2244 case CUR_LOWER_HALF:
2245 cu=h / 2;
2246 break;
2247 case CUR_TWO_THIRDS:
2248 cu=h / 3;
2249 break;
2250 case CUR_BLOCK:
2251 default:
2252 cu=0;
2253 cd = h;
2254 break;
2256 fb_info.cursor.w=fontwidth(p);
2257 fb_info.cursor.u=cu;
2258 fb_info.cursor.d=cd;
2261 static void tdfxfb_createcursor(struct display *p)
2263 u8 *cursorbase;
2264 u32 xline;
2265 unsigned int i;
2266 unsigned int h,to;
2268 tdfxfb_createcursorshape(p);
2269 xline = (1 << fb_info.cursor.w)-1;
2270 cursorbase=(u8*)fb_info.bufbase_virt;
2271 h=fb_info.cursor.cursorimage;
2273 to=fb_info.cursor.u;
2274 for (i = 0; i < to; i++) {
2275 writel(0, cursorbase+h);
2276 writel(0, cursorbase+h+4);
2277 writel(~0, cursorbase+h+8);
2278 writel(~0, cursorbase+h+12);
2279 h += 16;
2282 to = fb_info.cursor.d;
2284 for (; i < to; i++) {
2285 writel(xline, cursorbase+h);
2286 writel(0, cursorbase+h+4);
2287 writel(~0, cursorbase+h+8);
2288 writel(~0, cursorbase+h+12);
2289 h += 16;
2292 for (; i < 64; i++) {
2293 writel(0, cursorbase+h);
2294 writel(0, cursorbase+h+4);
2295 writel(~0, cursorbase+h+8);
2296 writel(~0, cursorbase+h+12);
2297 h += 16;
2301 static void tdfxfb_hwcursor_init(void)
2303 unsigned int start;
2304 start = (fb_info.bufbase_size-1024) & PAGE_MASK;
2305 fb_info.bufbase_size=start;
2306 fb_info.cursor.cursorimage=fb_info.bufbase_size;
2307 printk("tdfxfb: reserving 1024 bytes for the hwcursor at %p\n",
2308 fb_info.regbase_virt+fb_info.cursor.cursorimage);