* better
[mascara-docs.git] / i386 / linux-2.3.21 / drivers / video / tdfxfb.c
blob30f9111edce02d9a5abef55e2c6a254ac70bba52
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: Thu Oct 7 18:39:04 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. Thanks!
20 * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
21 * I do wish the next version is a bit more complete. Without the XF86
22 * patches I couldn't have gotten even this far... for instance, the
23 * extensions to the VGA register set go completely unmentioned in the
24 * spec! Also, lots of references are made to the 'SST core', but no
25 * spec is publicly available, AFAIK.
27 * The structure of this driver comes pretty much from the Permedia
28 * driver by Ilario Nardinocchi, which in turn is based on skeletonfb.
30 * TODO:
31 * - support for 16/32 bpp needs fixing (funky bootup penguin)
32 * - multihead support (it's all hosed now with pokes to VGA standard
33 * register locations, but shouldn't be that hard to change, some
34 * other code needs to be changed too where the fb_info (which should
35 * be an array of head-specific information) is referred to directly.
36 * are referred to )
37 * - hw cursor
38 * - better acceleration support (e.g., font blitting from fb memory?)
39 * - banshee and voodoo3 now supported -- any others? afaik, the original
40 * voodoo was a 3d-only card, so we won't consider that. what about
41 * voodoo2?
42 * - 24bpp
43 * - panning (doesn't seem to work properly yet)
45 * Version history:
47 * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga.
48 * 0.1.0 (released 1999-10-06) initial version
52 #include <linux/config.h>
53 #include <linux/module.h>
54 #include <linux/kernel.h>
55 #include <linux/errno.h>
56 #include <linux/string.h>
57 #include <linux/mm.h>
58 #include <linux/tty.h>
59 #include <linux/malloc.h>
60 #include <linux/vmalloc.h>
61 #include <linux/delay.h>
62 #include <linux/interrupt.h>
63 #include <linux/fb.h>
64 #include <linux/selection.h>
65 #include <linux/console.h>
66 #include <linux/init.h>
67 #include <linux/pci.h>
68 #include <linux/nvram.h>
69 #include <linux/kd.h>
70 #include <linux/vt_kern.h>
71 #include <asm/io.h>
73 #include <video/fbcon.h>
74 #include <video/fbcon-cfb8.h>
75 #include <video/fbcon-cfb16.h>
76 #include <video/fbcon-cfb32.h>
78 #ifndef LINUX_VERSION_CODE
79 #include <linux/version.h>
80 #endif
82 #ifndef KERNEL_VERSION
83 #define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
84 #endif
86 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
87 #define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005
88 #endif
90 /* membase0 register offsets */
91 #define STATUS 0x00
92 #define PCIINIT0 0x04
93 #define SIPMONITOR 0x08
94 #define LFBMEMORYCONFIG 0x0c
95 #define MISCINIT0 0x10
96 #define MISCINIT1 0x14
97 #define DRAMINIT0 0x18
98 #define DRAMINIT1 0x1c
99 #define AGPINIT 0x20
100 #define TMUGBEINIT 0x24
101 #define VGAINIT0 0x28
102 #define VGAINIT1 0x2c
103 #define DRAMCOMMAND 0x30
104 #define DRAMDATA 0x34
105 /* reserved 0x38 */
106 /* reserved 0x3c */
107 #define PLLCTRL0 0x40
108 #define PLLCTRL1 0x44
109 #define PLLCTRL2 0x48
110 #define DACMODE 0x4c
111 #define DACADDR 0x50
112 #define DACDATA 0x54
113 #define RGBMAXDELTA 0x58
114 #define VIDPROCCFG 0x5c
115 #define HWCURPATADDR 0x60
116 #define HWCURLOC 0x64
117 #define HWCURC0 0x68
118 #define HWCURC1 0x6c
119 #define VIDINFORMAT 0x70
120 #define VIDINSTATUS 0x74
121 #define VIDSERPARPORT 0x78
122 #define VIDINXDELTA 0x7c
123 #define VIDININITERR 0x80
124 #define VIDINYDELTA 0x84
125 #define VIDPIXBUFTHOLD 0x88
126 #define VIDCHRMIN 0x8c
127 #define VIDCHRMAX 0x90
128 #define VIDCURLIN 0x94
129 #define VIDSCREENSIZE 0x98
130 #define VIDOVRSTARTCRD 0x9c
131 #define VIDOVRENDCRD 0xa0
132 #define VIDOVRDUDX 0xa4
133 #define VIDOVRDUDXOFF 0xa8
134 #define VIDOVRDVDY 0xac
135 /* ... */
136 #define VIDOVRDVDYOFF 0xe0
137 #define VIDDESKSTART 0xe4
138 #define VIDDESKSTRIDE 0xe8
139 #define VIDINADDR0 0xec
140 #define VIDINADDR1 0xf0
141 #define VIDINADDR2 0xf4
142 #define VIDINSTRIDE 0xf8
143 #define VIDCUROVRSTART 0xfc
145 #define INTCTRL (0x00100000 + 0x04)
146 #define CLIP0MIN (0x00100000 + 0x08)
147 #define CLIP0MAX (0x00100000 + 0x0c)
148 #define DSTBASE (0x00100000 + 0x10)
149 #define DSTFORMAT (0x00100000 + 0x14)
150 #define SRCBASE (0x00100000 + 0x34)
151 #define COMMANDEXTRA_2D (0x00100000 + 0x38)
152 #define CLIP1MIN (0x00100000 + 0x4c)
153 #define CLIP1MAX (0x00100000 + 0x50)
154 #define SRCFORMAT (0x00100000 + 0x54)
155 #define SRCSIZE (0x00100000 + 0x58)
156 #define SRCXY (0x00100000 + 0x5c)
157 #define COLORBACK (0x00100000 + 0x60)
158 #define COLORFORE (0x00100000 + 0x64)
159 #define DSTSIZE (0x00100000 + 0x68)
160 #define DSTXY (0x00100000 + 0x6c)
161 #define COMMAND_2D (0x00100000 + 0x70)
162 #define LAUNCH_2D (0x00100000 + 0x80)
164 #define COMMAND_3D (0x00200000 + 0x120)
166 /* register bitfields (not all, only as needed) */
168 #define BIT(x) (1UL << (x))
170 #define ROP_COPY 0xcc
172 #define COMMAND_2D_FILLRECT 0x05
173 #define COMMAND_2D_BITBLT 0x01
175 #define COMMAND_3D_NOP 0x00
177 #define STATUS_RETRACE BIT(6)
178 #define STATUS_BUSY BIT(9)
180 #define MISCINIT1_CLUT_INV BIT(0)
181 #define MISCINIT1_2DBLOCK_DIS BIT(15)
183 #define DRAMINIT0_SGRAM_NUM BIT(26)
184 #define DRAMINIT0_SGRAM_TYPE BIT(27)
186 #define DRAMINIT1_MEM_SDRAM BIT(30)
188 #define VGAINIT0_VGA_DISABLE BIT(0)
189 #define VGAINIT0_EXT_TIMING BIT(1)
190 #define VGAINIT0_8BIT_DAC BIT(2)
191 #define VGAINIT0_EXT_ENABLE BIT(6)
192 #define VGAINIT0_WAKEUP_3C3 BIT(8)
193 #define VGAINIT0_LEGACY_DISABLE BIT(9)
194 #define VGAINIT0_ALT_READBACK BIT(10)
195 #define VGAINIT0_FAST_BLINK BIT(11)
196 #define VGAINIT0_EXTSHIFTOUT BIT(12)
197 #define VGAINIT0_DECODE_3C6 BIT(13)
198 #define VGAINIT0_SGRAM_HBLANK_DISABLE BIT(22)
200 #define VGAINIT1_MASK 0x1fffff
202 #define VIDCFG_VIDPROC_ENABLE BIT(0)
203 #define VIDCFG_CURS_X11 BIT(1)
204 #define VIDCFG_HALF_MODE BIT(4)
205 #define VIDCFG_DESK_ENABLE BIT(7)
206 #define VIDCFG_CLUT_BYPASS BIT(10)
207 #define VIDCFG_2X BIT(26)
208 #define VIDCFG_PIXFMT_SHIFT 18
210 #define DACMODE_2X BIT(0)
212 /* VGA rubbish, need to change this for multihead support */
213 #define MISC_W 0x3c2
214 #define MISC_R 0x3cc
215 #define SEQ_I 0x3c4
216 #define SEQ_D 0x3c5
217 #define CRT_I 0x3d4
218 #define CRT_D 0x3d5
219 #define ATT_IW 0x3c0
220 #define IS1_R 0x3da
221 #define GRA_I 0x3ce
222 #define GRA_D 0x3cf
223 #define DAC_IR 0x3c7
224 #define DAC_IW 0x3c8
225 #define DAC_D 0x3c9
227 #ifndef FB_ACCEL_3DFX_BANSHEE
228 #define FB_ACCEL_3DFX_BANSHEE 31
229 #endif
231 #define TDFXF_HSYNC_ACT_HIGH 0x01
232 #define TDFXF_HSYNC_ACT_LOW 0x02
233 #define TDFXF_VSYNC_ACT_HIGH 0x04
234 #define TDFXF_VSYNC_ACT_LOW 0x08
235 #define TDFXF_LINE_DOUBLE 0x10
236 #define TDFXF_VIDEO_ENABLE 0x20
238 #define TDFXF_HSYNC_MASK 0x03
239 #define TDFXF_VSYNC_MASK 0x0c
241 /* #define TDFXFB_DEBUG */
242 #ifdef TDFXFB_DEBUG
243 #define DPRINTK(a,b...) printk("fb: %s: " a, __FUNCTION__ , ## b)
244 #else
245 #define DPRINTK(a,b...)
246 #endif
248 #define PICOS2KHZ(a) (1000000000UL/(a))
249 #define KHZ2PICOS(a) (1000000000UL/(a))
251 #define BANSHEE_MAX_PIXCLOCK 270000.0
252 #define VOODOO3_MAX_PIXCLOCK 300000.0
254 struct banshee_reg {
255 /* VGA rubbish */
256 unsigned char att[21];
257 unsigned char crt[25];
258 unsigned char gra[ 9];
259 unsigned char misc[1];
260 unsigned char seq[ 5];
262 /* Banshee extensions */
263 unsigned char ext[2];
264 unsigned long vidcfg;
265 unsigned long vidpll;
266 unsigned long mempll;
267 unsigned long gfxpll;
268 unsigned long dacmode;
269 unsigned long vgainit0;
270 unsigned long vgainit1;
271 unsigned long screensize;
272 unsigned long stride;
273 unsigned long cursloc;
274 unsigned long startaddr;
275 unsigned long clip0min;
276 unsigned long clip0max;
277 unsigned long clip1min;
278 unsigned long clip1max;
279 unsigned long srcbase;
280 unsigned long dstbase;
283 struct tdfxfb_par {
284 u32 pixclock;
286 u32 baseline;
288 u32 width;
289 u32 height;
290 u32 width_virt;
291 u32 height_virt;
292 u32 lpitch; /* line pitch, in bytes */
293 u32 ppitch; /* pixel pitch, in bits */
294 u32 bpp;
296 u32 hdispend;
297 u32 hsyncsta;
298 u32 hsyncend;
299 u32 htotal;
301 u32 vdispend;
302 u32 vsyncsta;
303 u32 vsyncend;
304 u32 vtotal;
306 u32 video;
307 u32 accel_flags;
310 struct fb_info_tdfx {
311 struct fb_info fb_info;
313 u16 dev;
314 u32 max_pixclock;
316 unsigned long regbase_phys;
317 unsigned long regbase_virt;
318 unsigned long regbase_size;
319 unsigned long bufbase_phys;
320 unsigned long bufbase_virt;
321 unsigned long bufbase_size;
323 struct { u8 red, green, blue, pad; } palette[256];
324 struct tdfxfb_par default_par;
325 struct tdfxfb_par current_par;
326 struct display disp;
327 struct display_switch dispsw;
329 union {
330 #ifdef FBCON_HAS_CFB16
331 u16 cfb16[16];
332 #endif
333 #ifdef FBCON_HAS_CFB32
334 u32 cfb32[16];
335 #endif
336 } fbcon_cmap;
340 * Frame buffer device API
342 static int tdfxfb_open(struct fb_info* info,
343 int user);
344 static int tdfxfb_release(struct fb_info* info,
345 int user);
346 static int tdfxfb_get_fix(struct fb_fix_screeninfo* fix,
347 int con,
348 struct fb_info* fb);
349 static int tdfxfb_get_var(struct fb_var_screeninfo* var,
350 int con,
351 struct fb_info* fb);
352 static int tdfxfb_set_var(struct fb_var_screeninfo* var,
353 int con,
354 struct fb_info* fb);
355 static int tdfxfb_pan_display(struct fb_var_screeninfo* var,
356 int con,
357 struct fb_info* fb);
358 static int tdfxfb_get_cmap(struct fb_cmap *cmap,
359 int kspc,
360 int con,
361 struct fb_info* info);
362 static int tdfxfb_set_cmap(struct fb_cmap* cmap,
363 int kspc,
364 int con,
365 struct fb_info* info);
366 static int tdfxfb_ioctl(struct inode* inode,
367 struct file* file,
368 u_int cmd,
369 u_long arg,
370 int con,
371 struct fb_info* info);
374 * Interface to the low level console driver
376 static int tdfxfb_switch_con(int con,
377 struct fb_info* fb);
378 static int tdfxfb_updatevar(int con,
379 struct fb_info* fb);
380 static void tdfxfb_blank(int blank,
381 struct fb_info* fb);
384 * Internal routines
386 static void tdfxfb_set_par(const struct tdfxfb_par* par,
387 struct fb_info_tdfx*
388 info);
389 static int tdfxfb_decode_var(const struct fb_var_screeninfo *var,
390 struct tdfxfb_par *par,
391 const struct fb_info_tdfx *info);
392 static int tdfxfb_encode_var(struct fb_var_screeninfo* var,
393 const struct tdfxfb_par* par,
394 const struct fb_info_tdfx* info);
395 static int tdfxfb_encode_fix(struct fb_fix_screeninfo* fix,
396 const struct tdfxfb_par* par,
397 const struct fb_info_tdfx* info);
398 static void tdfxfb_set_disp(struct display* disp,
399 struct fb_info_tdfx* info,
400 int bpp,
401 int accel);
402 static int tdfxfb_getcolreg(u_int regno,
403 u_int* red,
404 u_int* green,
405 u_int* blue,
406 u_int* transp,
407 struct fb_info* fb);
408 static int tdfxfb_setcolreg(u_int regno,
409 u_int red,
410 u_int green,
411 u_int blue,
412 u_int transp,
413 struct fb_info* fb);
414 static void tdfxfb_install_cmap(int con,
415 struct fb_info *info);
418 * Interface used by the world
420 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
421 void tdfxfb_init(void);
422 #else
423 int tdfxfb_init(void);
424 #endif
425 void tdfxfb_setup(char *options,
426 int *ints);
428 static int currcon = 0;
430 static struct fb_ops tdfxfb_ops = {
431 tdfxfb_open,
432 tdfxfb_release,
433 tdfxfb_get_fix,
434 tdfxfb_get_var,
435 tdfxfb_set_var,
436 tdfxfb_get_cmap,
437 tdfxfb_set_cmap,
438 tdfxfb_pan_display,
439 tdfxfb_ioctl,
440 NULL
443 struct mode {
444 char* name;
445 struct fb_var_screeninfo var;
446 } mode;
448 /* 2.3.x kernels have a fb mode database, so supply only one backup default */
449 struct mode default_mode[] = {
450 { "640x480-8@60", /* @ 60 Hz */
452 640, 480, 640, 480, 0, 0, 8, 0,
453 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
454 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
455 39722, 40, 24, 32, 11, 96, 2,
456 0, FB_VMODE_NONINTERLACED
459 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
461 { "800x600-8@56", /* @ 56 Hz */
463 800, 600, 800, 600, 0, 0, 8, 0,
464 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
465 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
466 27778, 128, 24, 22, 1, 72, 2,
467 0, FB_VMODE_NONINTERLACED
470 { "1024x768-8@60", /* @ 60 Hz */
472 1024, 768, 1024, 768, 0, 0, 8, 0,
473 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
474 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
475 15385, 168, 8, 29, 3, 144, 6,
476 0, FB_VMODE_NONINTERLACED
479 { "1280x1024-8@61", /* @ 61 Hz */
481 1280, 1024, 1280, 1024, 0, 0, 8, 0,
482 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
483 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
484 9091, 200, 48, 26, 1, 184, 3,
485 0, FB_VMODE_NONINTERLACED
488 { "1024x768-16@60", /* @ 60 Hz */ /* basically for testing */
490 1024, 768, 1024, 768, 0, 0, 16, 0,
491 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
492 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
493 15385, 168, 8, 29, 3, 144, 6,
494 0, FB_VMODE_NONINTERLACED
497 #endif
500 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
501 static int modes = sizeof(default_mode)/sizeof(struct mode);
502 static int default_mode_index = 0;
503 #endif
505 static struct fb_info_tdfx fb_info;
507 static int __initdata noaccel = 0;
508 static int __initdata nopan = 0;
509 static int __initdata nowrap = 0;
510 static int __initdata inverse = 0;
511 static char __initdata fontname[40] = { 0 };
512 static const char *mode_option __initdata = NULL;
514 /* ------------------------------------------------------------------------- */
516 static inline __u8 vga_inb(__u32 reg) { return inb(reg); }
517 static inline __u16 vga_inw(__u32 reg) { return inw(reg); }
518 static inline __u16 vga_inl(__u32 reg) { return inl(reg); }
520 static inline void vga_outb(__u32 reg, __u8 val) { outb(val, reg); }
521 static inline void vga_outw(__u32 reg, __u16 val) { outw(val, reg); }
522 static inline void vga_outl(__u32 reg, __u32 val) { outl(val, reg); }
524 static inline void gra_outb(__u32 idx, __u8 val) {
525 vga_outb(GRA_I, idx); vga_outb(GRA_D, val);
528 static inline __u8 gra_inb(__u32 idx) {
529 vga_outb(GRA_I, idx); return vga_inb(GRA_D);
532 static inline void seq_outb(__u32 idx, __u8 val) {
533 vga_outb(SEQ_I, idx); vga_outb(SEQ_D, val);
536 static inline __u8 seq_inb(__u32 idx) {
537 vga_outb(SEQ_I, idx); return vga_inb(SEQ_D);
540 static inline void crt_outb(__u32 idx, __u8 val) {
541 vga_outb(CRT_I, idx); vga_outb(CRT_D, val);
544 static inline __u8 crt_inb(__u32 idx) {
545 vga_outb(CRT_I, idx); return vga_inb(CRT_D);
548 static inline void att_outb(__u32 idx, __u8 val) {
549 unsigned char tmp;
550 tmp = vga_inb(IS1_R);
551 vga_outb(ATT_IW, idx);
552 vga_outb(ATT_IW, val);
555 static inline __u8 att_inb(__u32 idx) {
556 unsigned char tmp;
557 tmp = vga_inb(IS1_R);
558 vga_outb(ATT_IW, idx);
559 return vga_inb(ATT_IW);
562 static inline void vga_disable_video(void) {
563 unsigned char s;
564 s = seq_inb(0x01) | 0x20;
565 seq_outb(0x00, 0x01);
566 seq_outb(0x01, s);
567 seq_outb(0x00, 0x03);
570 static inline void vga_enable_video(void) {
571 unsigned char s;
572 s = seq_inb(0x01) & 0xdf;
573 seq_outb(0x00, 0x01);
574 seq_outb(0x01, s);
575 seq_outb(0x00, 0x03);
578 static inline void vga_disable_palette(void) {
579 vga_inb(IS1_R);
580 vga_outb(ATT_IW, 0x00);
583 static inline void vga_enable_palette(void) {
584 vga_inb(IS1_R);
585 vga_outb(ATT_IW, 0x20);
588 static inline __u32 tdfx_inl(unsigned int reg) {
589 return readl(fb_info.regbase_virt + reg);
592 static inline void tdfx_outl(unsigned int reg, __u32 val) {
593 writel(val, fb_info.regbase_virt + reg);
596 static inline void banshee_make_room(int size) {
597 while((tdfx_inl(STATUS) & 0x1f) < size);
600 static inline void banshee_wait_idle(void) {
601 int i = 0;
603 banshee_make_room(1);
604 tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
606 while(1) {
607 i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1;
608 if(i == 3) break;
612 static void banshee_fillrect(__u32 x,
613 __u32 y,
614 __u32 w,
615 __u32 h,
616 __u32 color,
617 __u32 stride,
618 __u32 bpp) {
619 banshee_make_room(2);
620 tdfx_outl(DSTFORMAT,
621 (stride & 0x3fff) |
622 (bpp == 8 ? 0x10000 :
623 bpp == 16 ? 0x30000 : 0x50000));
624 tdfx_outl(COLORFORE, color);
626 banshee_make_room(3);
627 tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (ROP_COPY << 24));
628 tdfx_outl(DSTSIZE, (w & 0x1fff) | ((h & 0x1fff) << 16));
629 tdfx_outl(LAUNCH_2D, (x & 0x1fff) | ((y & 0x1fff) << 16));
632 static void banshee_bitblt(__u32 curx,
633 __u32 cury,
634 __u32 dstx,
635 __u32 dsty,
636 __u32 width,
637 __u32 height,
638 __u32 stride,
639 __u32 bpp) {
640 int xdir, ydir;
642 xdir = dstx < curx ? 1 : -1;
643 ydir = dsty < cury ? 1 : -1;
645 banshee_make_room(4);
646 tdfx_outl(SRCFORMAT,
647 (stride & 0x3fff) |
648 (bpp == 8 ? 0x10000 :
649 bpp == 16 ? 0x30000 : 0x50000));
650 tdfx_outl(DSTFORMAT,
651 (stride & 0x3fff) |
652 (bpp == 8 ? 0x10000 :
653 bpp == 16 ? 0x30000 : 0x50000));
654 tdfx_outl(COMMAND_2D,
655 COMMAND_2D_BITBLT |
656 (xdir == -1 ? BIT(14) : 0) |
657 (ydir == -1 ? BIT(15) : 0));
658 tdfx_outl(COMMANDEXTRA_2D, 0); /* no color keying */
660 if(xdir == -1) {
661 curx += width - 1;
662 dstx += width - 1;
664 if(ydir == -1) {
665 cury += height - 1;
666 dsty += height - 1;
669 /* Consecutive overlapping regions can hang the board --
670 since we allow mmap'ing of control registers, we cannot
671 __safely__ assume anything, like XF86 does... */
672 banshee_make_room(1);
673 tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
675 banshee_make_room(3);
676 tdfx_outl(DSTSIZE, (width & 0x1fff) | ((height & 0x1fff) << 16));
677 tdfx_outl(DSTXY, (dstx & 0x1fff) | ((dsty & 0x1fff) << 16));
678 tdfx_outl(LAUNCH_2D, (curx & 0x1fff) | ((cury & 0x1fff) << 16));
681 static __u32 banshee_calc_pll(int freq, int* freq_out) {
682 int m, n, k, best_m, best_n, best_k, f_cur, best_error;
683 int fref = 14318;
685 /* this really could be done with more intelligence */
686 best_error = freq;
687 best_n = best_m = best_k = 0;
688 for(n = 1; n < 256; n++) {
689 for(m = 1; m < 64; m++) {
690 for(k = 0; k < 4; k++) {
691 f_cur = fref*(n + 2)/(m + 2)/(1 << k);
692 if(abs(f_cur - freq) < best_error) {
693 best_error = abs(f_cur-freq);
694 best_n = n;
695 best_m = m;
696 best_k = k;
701 n = best_n;
702 m = best_m;
703 k = best_k;
704 *freq_out = fref*(n + 2)/(m + 2)/(1 << k);
706 DPRINTK("freq = %d kHz, freq_out = %d kHz\n", freq, *freq_out);
707 DPRINTK("N = %d, M = %d, K = %d\n", n, m, k);
709 return (n << 8) | (m << 2) | k;
712 static void banshee_write_regs(struct banshee_reg* reg) {
713 int i;
715 banshee_wait_idle();
717 tdfx_outl(MISCINIT1, tdfx_inl(MISCINIT1) | 0x01);
719 crt_outb(0x11, crt_inb(0x11) & 0x7f); /* CRT unprotect */
721 banshee_make_room(3);
722 tdfx_outl(VGAINIT1, reg->vgainit1 & 0x001FFFFF);
723 tdfx_outl(VIDPROCCFG, reg->vidcfg & ~0x00000001);
724 #if 0
725 tdfx_outl(PLLCTRL1, reg->mempll);
726 tdfx_outl(PLLCTRL2, reg->gfxpll);
727 #endif
728 tdfx_outl(PLLCTRL0, reg->vidpll);
730 vga_outb(MISC_W, reg->misc[0x00] | 0x01);
732 for(i = 0; i < 5; i++)
733 seq_outb(i, reg->seq[i]);
735 for(i = 0; i < 25; i++)
736 crt_outb(i, reg->crt[i]);
738 for(i = 0; i < 9; i++)
739 gra_outb(i, reg->gra[i]);
741 for(i = 0; i < 21; i++)
742 att_outb(i, reg->att[i]);
744 crt_outb(0x1a, reg->ext[0]);
745 crt_outb(0x1b, reg->ext[1]);
747 vga_enable_palette();
748 vga_enable_video();
750 banshee_make_room(9);
751 tdfx_outl(VGAINIT0, reg->vgainit0);
752 tdfx_outl(DACMODE, reg->dacmode);
753 tdfx_outl(VIDDESKSTRIDE, reg->stride);
754 tdfx_outl(HWCURPATADDR, reg->cursloc);
755 tdfx_outl(VIDSCREENSIZE, reg->screensize);
756 tdfx_outl(VIDDESKSTART, reg->startaddr);
757 tdfx_outl(VIDPROCCFG, reg->vidcfg);
758 tdfx_outl(VGAINIT1, reg->vgainit1);
760 banshee_make_room(7);
761 tdfx_outl(SRCBASE, reg->srcbase);
762 tdfx_outl(DSTBASE, reg->dstbase);
763 tdfx_outl(COMMANDEXTRA_2D, 0);
764 tdfx_outl(CLIP0MIN, 0);
765 tdfx_outl(CLIP0MAX, 0x0fff0fff);
766 tdfx_outl(CLIP1MIN, 0);
767 tdfx_outl(CLIP1MAX, 0x0fff0fff);
769 banshee_wait_idle();
772 static unsigned long tdfx_lfb_size(void) {
773 __u32 draminit0 = 0;
774 __u32 draminit1 = 0;
775 __u32 miscinit1 = 0;
776 __u32 lfbsize = 0;
777 int sgram_p = 0;
779 if(!((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) ||
780 (fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3)))
781 return 0;
783 draminit0 = tdfx_inl(DRAMINIT0);
784 draminit1 = tdfx_inl(DRAMINIT1);
786 sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
788 lfbsize = sgram_p ?
789 (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) *
790 ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
791 16 * 1024 * 1024;
793 /* disable block writes for SDRAM (why?) */
794 miscinit1 = tdfx_inl(MISCINIT1);
795 miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
796 miscinit1 |= MISCINIT1_CLUT_INV;
797 tdfx_outl(MISCINIT1, miscinit1);
799 return lfbsize;
802 static void fbcon_banshee_bmove(struct display* p,
803 int sy,
804 int sx,
805 int dy,
806 int dx,
807 int height,
808 int width) {
809 banshee_bitblt(fontwidth(p)*sx,
810 fontheight(p)*sy,
811 fontwidth(p)*dx,
812 fontheight(p)*dy,
813 fontwidth(p)*width,
814 fontheight(p)*height,
815 fb_info.current_par.lpitch,
816 fb_info.current_par.bpp);
819 static void fbcon_banshee_clear(struct vc_data* conp,
820 struct display* p,
821 int sy,
822 int sx,
823 int height,
824 int width) {
825 unsigned int bg;
827 bg = attr_bgcol_ec(p,conp);
828 banshee_fillrect(fontwidth(p)*sx,
829 fontheight(p)*sy,
830 fontwidth(p)*width,
831 fontheight(p)*height,
832 bg,
833 fb_info.current_par.lpitch,
834 fb_info.current_par.bpp);
837 #ifdef FBCON_HAS_CFB8
838 static struct display_switch fbcon_banshee8 = {
839 fbcon_cfb8_setup,
840 fbcon_banshee_bmove,
841 fbcon_banshee_clear,
842 fbcon_cfb8_putc,
843 fbcon_cfb8_putcs,
844 fbcon_cfb8_revc,
845 NULL,
846 NULL,
847 fbcon_cfb8_clear_margins,
848 FONTWIDTH(8)
850 #endif
851 #ifdef FBCON_HAS_CFB16
852 static struct display_switch fbcon_banshee16 = {
853 fbcon_cfb16_setup,
854 fbcon_banshee_bmove,
855 fbcon_banshee_clear,
856 fbcon_cfb16_putc,
857 fbcon_cfb16_putcs,
858 fbcon_cfb16_revc,
859 NULL,
860 NULL,
861 fbcon_cfb16_clear_margins,
862 FONTWIDTH(8)
864 #endif
865 #ifdef FBCON_HAS_CFB32
866 static struct display_switch fbcon_banshee32 = {
867 fbcon_cfb32_setup,
868 fbcon_banshee_bmove,
869 fbcon_banshee_clear,
870 fbcon_cfb32_putc,
871 fbcon_cfb32_putcs,
872 fbcon_cfb32_revc,
873 NULL,
874 NULL,
875 fbcon_cfb32_clear_margins,
876 FONTWIDTH(8)
878 #endif
880 /* ------------------------------------------------------------------------- */
882 static void tdfxfb_set_par(const struct tdfxfb_par* par,
883 struct fb_info_tdfx* info) {
884 struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
885 struct banshee_reg reg;
886 __u32 cpp;
887 __u32 hd, hs, he, ht, hbs, hbe;
888 __u32 vd, vs, ve, vt, vbs, vbe;
889 __u32 wd;
890 int fout;
891 int freq;
893 memset(&reg, 0, sizeof(reg));
895 cpp = (par->bpp + 7)/8;
897 wd = (par->hdispend >> 3) - 1;
899 hd = (par->hdispend >> 3) - 1;
900 hs = (par->hsyncsta >> 3) - 1;
901 he = (par->hsyncend >> 3) - 1;
902 ht = (par->htotal >> 3) - 1;
903 hbs = hd;
904 hbe = ht;
906 vd = par->vdispend - 1;
907 vs = par->vsyncsta - 1;
908 ve = par->vsyncend - 1;
909 vt = par->vtotal - 2;
910 vbs = vd;
911 vbe = vt;
913 /* this is all pretty standard VGA register stuffing */
914 reg.misc[0x00] =
915 0x0f |
916 (par->hdispend < 400 ? 0xa0 :
917 par->hdispend < 480 ? 0x60 :
918 par->hdispend < 768 ? 0xe0 : 0x20);
920 reg.gra[0x00] = 0x00;
921 reg.gra[0x01] = 0x00;
922 reg.gra[0x02] = 0x00;
923 reg.gra[0x03] = 0x00;
924 reg.gra[0x04] = 0x00;
925 reg.gra[0x05] = 0x40;
926 reg.gra[0x06] = 0x05;
927 reg.gra[0x07] = 0x0f;
928 reg.gra[0x08] = 0xff;
930 reg.att[0x00] = 0x00;
931 reg.att[0x01] = 0x01;
932 reg.att[0x02] = 0x02;
933 reg.att[0x03] = 0x03;
934 reg.att[0x04] = 0x04;
935 reg.att[0x05] = 0x05;
936 reg.att[0x06] = 0x06;
937 reg.att[0x07] = 0x07;
938 reg.att[0x08] = 0x08;
939 reg.att[0x09] = 0x09;
940 reg.att[0x0a] = 0x0a;
941 reg.att[0x0b] = 0x0b;
942 reg.att[0x0c] = 0x0c;
943 reg.att[0x0d] = 0x0d;
944 reg.att[0x0e] = 0x0e;
945 reg.att[0x0f] = 0x0f;
946 reg.att[0x10] = 0x41;
947 reg.att[0x11] = 0x00;
948 reg.att[0x12] = 0x0f;
949 reg.att[0x13] = 0x00;
950 reg.att[0x14] = 0x00;
952 reg.seq[0x00] = 0x03;
953 reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
954 reg.seq[0x02] = 0x0f;
955 reg.seq[0x03] = 0x00;
956 reg.seq[0x04] = 0x0e;
958 reg.crt[0x00] = ht - 4;
959 reg.crt[0x01] = hd;
960 reg.crt[0x02] = hbs;
961 reg.crt[0x03] = 0x80 | (hbe & 0x1f);
962 reg.crt[0x04] = hs;
963 reg.crt[0x05] =
964 ((hbe & 0x20) << 2) |
965 (he & 0x1f);
966 reg.crt[0x06] = vt;
967 reg.crt[0x07] =
968 ((vs & 0x200) >> 2) |
969 ((vd & 0x200) >> 3) |
970 ((vt & 0x200) >> 4) |
971 0x10 |
972 ((vbs & 0x100) >> 5) |
973 ((vs & 0x100) >> 6) |
974 ((vd & 0x100) >> 7) |
975 ((vt & 0x100) >> 8);
976 reg.crt[0x08] = 0x00;
977 reg.crt[0x09] =
978 0x40 |
979 ((vbs & 0x200) >> 4);
980 reg.crt[0x0a] = 0x00;
981 reg.crt[0x0b] = 0x00;
982 reg.crt[0x0c] = 0x00;
983 reg.crt[0x0d] = 0x00;
984 reg.crt[0x0e] = 0x00;
985 reg.crt[0x0f] = 0x00;
986 reg.crt[0x10] = vs;
987 reg.crt[0x11] =
988 (ve & 0x0f) |
989 0x20;
990 reg.crt[0x12] = vd;
991 reg.crt[0x13] = wd;
992 reg.crt[0x14] = 0x00;
993 reg.crt[0x15] = vbs;
994 reg.crt[0x16] = vbe + 1;
995 reg.crt[0x17] = 0xc3;
996 reg.crt[0x18] = 0xff;
998 /* Banshee's nonvga stuff */
999 reg.ext[0x00] = (((ht & 0x100) >> 8) |
1000 ((hd & 0x100) >> 6) |
1001 ((hbs & 0x100) >> 4) |
1002 ((hbe & 0x40) >> 1) |
1003 ((hs & 0x100) >> 2) |
1004 ((he & 0x20) << 2));
1005 reg.ext[0x01] = (((vt & 0x400) >> 10) |
1006 ((vd & 0x400) >> 8) |
1007 ((vbs & 0x400) >> 6) |
1008 ((vbe & 0x400) >> 4));
1010 reg.vgainit0 =
1011 VGAINIT0_8BIT_DAC |
1012 VGAINIT0_EXT_ENABLE |
1013 VGAINIT0_WAKEUP_3C3 |
1014 VGAINIT0_ALT_READBACK |
1015 VGAINIT0_EXTSHIFTOUT;
1016 reg.vgainit1 = tdfx_inl(VGAINIT1) & 0x1fffff;
1018 reg.vidcfg =
1019 VIDCFG_VIDPROC_ENABLE |
1020 VIDCFG_DESK_ENABLE |
1021 ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
1022 (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
1023 reg.stride = par->width*cpp;
1024 reg.cursloc = 0;
1026 reg.startaddr = par->baseline*reg.stride;
1027 reg.srcbase = reg.startaddr;
1028 reg.dstbase = reg.startaddr;
1030 /* PLL settings */
1031 freq = par->pixclock;
1033 reg.dacmode &= ~DACMODE_2X;
1034 reg.vidcfg &= ~VIDCFG_2X;
1035 if(freq > i->max_pixclock/2) {
1036 freq = freq > i->max_pixclock ? i->max_pixclock : freq;
1037 reg.dacmode |= DACMODE_2X;
1038 reg.vidcfg |= VIDCFG_2X;
1040 reg.vidpll = banshee_calc_pll(freq, &fout);
1041 #if 0
1042 reg.mempll = banshee_calc_pll(..., &fout);
1043 reg.gfxpll = banshee_calc_pll(..., &fout);
1044 #endif
1046 reg.screensize = par->width | (par->height << 12);
1047 reg.vidcfg &= ~VIDCFG_HALF_MODE;
1049 banshee_write_regs(&reg);
1051 i->current_par = *par;
1054 static int tdfxfb_decode_var(const struct fb_var_screeninfo* var,
1055 struct tdfxfb_par* par,
1056 const struct fb_info_tdfx* info) {
1057 struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
1059 if(var->bits_per_pixel != 8 &&
1060 var->bits_per_pixel != 16 &&
1061 var->bits_per_pixel != 32) {
1062 DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
1063 return -EINVAL;
1066 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1067 DPRINTK("interlace not supported\n");
1068 return -EINVAL;
1071 if(var->xoffset) {
1072 DPRINTK("xoffset not supported\n");
1073 return -EINVAL;
1076 if(var->xres != var->xres_virtual) {
1077 DPRINTK("virtual x resolution != physical x resolution not supported\n");
1078 return -EINVAL;
1081 if(nopan && nowrap) {
1082 if(var->yres != var->yres_virtual) {
1083 DPRINTK("virtual y resolution != physical y resolution not supported\n");
1084 return -EINVAL;
1086 } else {
1087 if(var->yres > var->yres_virtual) {
1088 DPRINTK("virtual y resolution < physical y resolution not possible\n");
1089 return -EINVAL;
1093 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1094 DPRINTK("interlace not supported\n");
1095 return -EINVAL;
1098 memset(par, 0, sizeof(struct tdfxfb_par));
1100 switch(i->dev) {
1101 case PCI_DEVICE_ID_3DFX_BANSHEE:
1102 case PCI_DEVICE_ID_3DFX_VOODOO3:
1103 par->width = (var->xres + 15) & ~15; /* could sometimes be 8 */
1104 par->width_virt = par->width;
1105 par->height = var->yres;
1106 par->height_virt = var->yres_virtual;
1107 par->bpp = var->bits_per_pixel;
1108 par->ppitch = var->bits_per_pixel;
1109 par->lpitch = par->width*par->ppitch/8;
1111 par->baseline = 0;
1113 if(par->width < 320 || par->width > 2048) {
1114 DPRINTK("width not supported: %u\n", par->width);
1115 return -EINVAL;
1117 if(par->height < 200 || par->height > 2048) {
1118 DPRINTK("height not supported: %u\n", par->height);
1119 return -EINVAL;
1121 if(par->lpitch*par->height_virt > i->bufbase_size) {
1122 DPRINTK("no memory for screen (%ux%ux%u)\n",
1123 par->width, par->height_virt, par->bpp);
1124 return -EINVAL;
1126 par->pixclock = PICOS2KHZ(var->pixclock);
1127 if(par->pixclock > i->max_pixclock) {
1128 DPRINTK("pixclock too high (%uKHz)\n", par->pixclock);
1129 return -EINVAL;
1132 par->hdispend = var->xres;
1133 par->hsyncsta = par->hdispend + var->right_margin;
1134 par->hsyncend = par->hsyncsta + var->hsync_len;
1135 par->htotal = par->hsyncend + var->left_margin;
1137 par->vdispend = var->yres;
1138 par->vsyncsta = par->vdispend + var->lower_margin;
1139 par->vsyncend = par->vsyncsta + var->vsync_len;
1140 par->vtotal = par->vsyncend + var->upper_margin;
1142 if(var->sync & FB_SYNC_HOR_HIGH_ACT)
1143 par->video |= TDFXF_HSYNC_ACT_HIGH;
1144 else
1145 par->video |= TDFXF_HSYNC_ACT_LOW;
1146 if(var->sync & FB_SYNC_VERT_HIGH_ACT)
1147 par->video |= TDFXF_VSYNC_ACT_HIGH;
1148 else
1149 par->video |= TDFXF_VSYNC_ACT_LOW;
1150 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
1151 par->video |= TDFXF_LINE_DOUBLE;
1152 if(var->activate == FB_ACTIVATE_NOW)
1153 par->video |= TDFXF_VIDEO_ENABLE;
1156 if(var->accel_flags & FB_ACCELF_TEXT)
1157 par->accel_flags = FB_ACCELF_TEXT;
1158 else
1159 par->accel_flags = 0;
1161 return 0;
1164 static int tdfxfb_encode_var(struct fb_var_screeninfo* var,
1165 const struct tdfxfb_par* par,
1166 const struct fb_info_tdfx* info) {
1167 struct fb_var_screeninfo v;
1169 memset(&v, 0, sizeof(struct fb_var_screeninfo));
1170 v.xres_virtual = par->width_virt;
1171 v.yres_virtual = par->height_virt;
1172 v.xres = par->width;
1173 v.yres = par->height;
1174 v.right_margin = par->hsyncsta - par->hdispend;
1175 v.hsync_len = par->hsyncend - par->hsyncsta;
1176 v.left_margin = par->htotal - par->hsyncend;
1177 v.lower_margin = par->vsyncsta - par->vdispend;
1178 v.vsync_len = par->vsyncend - par->vsyncsta;
1179 v.upper_margin = par->vtotal - par->vsyncend;
1180 v.bits_per_pixel = par->bpp;
1181 switch(par->bpp) {
1182 case 8:
1183 v.red.length = v.green.length = v.blue.length = 8;
1184 break;
1185 case 16:
1186 v.red.offset = 11;
1187 v.red.length = 5;
1188 v.green.offset = 5;
1189 v.green.length = 6;
1190 v.blue.offset = 0;
1191 v.blue.length = 5;
1192 break;
1193 case 32:
1194 v.red.offset = 16;
1195 v.green.offset = 8;
1196 v.blue.offset = 0;
1197 v.red.length = v.green.length = v.blue.length = 8;
1198 break;
1200 v.height = v.width = -1;
1201 v.pixclock = KHZ2PICOS(par->pixclock);
1202 if((par->video & TDFXF_HSYNC_MASK) == TDFXF_HSYNC_ACT_HIGH)
1203 v.sync |= FB_SYNC_HOR_HIGH_ACT;
1204 if((par->video & TDFXF_VSYNC_MASK) == TDFXF_VSYNC_ACT_HIGH)
1205 v.sync |= FB_SYNC_VERT_HIGH_ACT;
1206 if(par->video & TDFXF_LINE_DOUBLE)
1207 v.vmode = FB_VMODE_DOUBLE;
1208 *var = v;
1209 return 0;
1212 static int tdfxfb_open(struct fb_info* info,
1213 int user) {
1214 MOD_INC_USE_COUNT;
1215 return(0);
1218 static int tdfxfb_release(struct fb_info* info,
1219 int user) {
1220 MOD_DEC_USE_COUNT;
1221 return(0);
1225 static int tdfxfb_encode_fix(struct fb_fix_screeninfo* fix,
1226 const struct tdfxfb_par* par,
1227 const struct fb_info_tdfx* info) {
1228 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1230 switch(info->dev) {
1231 case PCI_DEVICE_ID_3DFX_BANSHEE:
1232 case PCI_DEVICE_ID_3DFX_VOODOO3:
1233 if (info->dev == PCI_DEVICE_ID_3DFX_BANSHEE)
1234 strcpy(fix->id, "3Dfx Banshee");
1235 else
1236 strcpy(fix->id, "3Dfx Voodoo3");
1237 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1238 fix->smem_start = (char*)info->bufbase_phys;
1239 fix->smem_len = info->bufbase_size;
1240 fix->mmio_start = (char*)info->regbase_phys;
1241 fix->mmio_len = info->regbase_size;
1242 #else
1243 fix->smem_start = info->bufbase_phys;
1244 fix->smem_len = info->bufbase_size;
1245 fix->mmio_start = info->regbase_phys;
1246 fix->mmio_len = info->regbase_size;
1247 #endif
1248 fix->accel = FB_ACCEL_3DFX_BANSHEE;
1249 fix->type = FB_TYPE_PACKED_PIXELS;
1250 fix->type_aux = 0;
1251 fix->line_length = par->lpitch;
1252 fix->visual = par->bpp == 8
1253 ? FB_VISUAL_PSEUDOCOLOR
1254 : FB_VISUAL_DIRECTCOLOR;
1256 fix->xpanstep = 0;
1257 fix->ypanstep = (nowrap && nopan) ? 0 : 1;
1258 fix->ywrapstep = nowrap ? 0 : 1;
1260 break;
1261 default:
1262 return -EINVAL;
1265 return 0;
1268 static int tdfxfb_get_fix(struct fb_fix_screeninfo *fix,
1269 int con,
1270 struct fb_info *fb) {
1271 const struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
1272 struct tdfxfb_par par;
1274 if(con == -1)
1275 par = info->default_par;
1276 else
1277 tdfxfb_decode_var(&fb_display[con].var, &par, info);
1278 tdfxfb_encode_fix(fix, &par, info);
1279 return 0;
1282 static int tdfxfb_get_var(struct fb_var_screeninfo *var,
1283 int con,
1284 struct fb_info *fb) {
1285 const struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
1287 if(con == -1)
1288 tdfxfb_encode_var(var, &info->default_par, info);
1289 else
1290 *var = fb_display[con].var;
1291 return 0;
1294 static void tdfxfb_set_disp(struct display *disp,
1295 struct fb_info_tdfx *info,
1296 int bpp,
1297 int accel) {
1298 DPRINTK("actually, %s using acceleration!\n",
1299 noaccel ? "NOT" : "");
1301 switch(bpp) {
1302 #ifdef FBCON_HAS_CFB8
1303 case 8:
1304 info->dispsw = noaccel ? fbcon_cfb8 : fbcon_banshee8;
1305 disp->dispsw = &info->dispsw;
1306 break;
1307 #endif
1308 #ifdef FBCON_HAS_CFB16
1309 case 16:
1310 info->dispsw = noaccel ? fbcon_cfb16 : fbcon_banshee16;
1311 disp->dispsw = &info->dispsw;
1312 disp->dispsw_data = info->fbcon_cmap.cfb16;
1313 break;
1314 #endif
1315 #ifdef FBCON_HAS_CFB32
1316 case 32:
1317 info->dispsw = noaccel ? fbcon_cfb32 : fbcon_banshee32;
1318 disp->dispsw = &info->dispsw;
1319 disp->dispsw_data = info->fbcon_cmap.cfb32;
1320 break;
1321 #endif
1322 default:
1323 info->dispsw = fbcon_dummy;
1324 disp->dispsw = &info->dispsw;
1328 static int tdfxfb_set_var(struct fb_var_screeninfo *var,
1329 int con,
1330 struct fb_info *fb) {
1331 struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
1332 struct tdfxfb_par par;
1333 struct display *display;
1334 int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
1335 int activate = var->activate;
1337 if(con >= 0)
1338 display = &fb_display[con];
1339 else
1340 display = fb->disp; /* used during initialization */
1342 if((err = tdfxfb_decode_var(var, &par, info)))
1343 return err;
1345 tdfxfb_encode_var(var, &par, info);
1347 if((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1348 oldxres = display->var.xres;
1349 oldyres = display->var.yres;
1350 oldvxres = display->var.xres_virtual;
1351 oldvyres = display->var.yres_virtual;
1352 oldbpp = display->var.bits_per_pixel;
1353 oldaccel = display->var.accel_flags;
1354 display->var = *var;
1355 if(con < 0 ||
1356 oldxres != var->xres ||
1357 oldyres != var->yres ||
1358 oldvxres != var->xres_virtual ||
1359 oldvyres != var->yres_virtual ||
1360 oldbpp != var->bits_per_pixel ||
1361 oldaccel != var->accel_flags) {
1362 struct fb_fix_screeninfo fix;
1364 tdfxfb_encode_fix(&fix, &par, info);
1365 display->screen_base = (char *)info->bufbase_virt;
1366 display->visual = fix.visual;
1367 display->type = fix.type;
1368 display->type_aux = fix.type_aux;
1369 display->ypanstep = fix.ypanstep;
1370 display->ywrapstep = fix.ywrapstep;
1371 display->line_length = fix.line_length;
1372 display->next_line = fix.line_length;
1373 display->can_soft_blank = 1;
1374 display->inverse = inverse;
1375 accel = var->accel_flags & FB_ACCELF_TEXT;
1376 tdfxfb_set_disp(display, info, par.bpp, accel);
1378 if(nopan && nowrap) {
1379 display->scrollmode = SCROLL_YREDRAW;
1380 #ifdef FBCON_HAS_CFB8
1381 fbcon_banshee8.bmove = fbcon_redraw_bmove;
1382 #endif
1383 #ifdef FBCON_HAS_CFB16
1384 fbcon_banshee16.bmove = fbcon_redraw_bmove;
1385 #endif
1386 #ifdef FBCON_HAS_CFB32
1387 fbcon_banshee32.bmove = fbcon_redraw_bmove;
1388 #endif
1390 if (info->fb_info.changevar)
1391 (*info->fb_info.changevar)(con);
1393 if(!info->fb_info.display_fg ||
1394 info->fb_info.display_fg->vc_num == con ||
1395 con < 0)
1396 tdfxfb_set_par(&par, info);
1397 if(oldbpp != var->bits_per_pixel || con < 0) {
1398 if((err = fb_alloc_cmap(&display->cmap, 0, 0)))
1399 return err;
1400 tdfxfb_install_cmap(con, &info->fb_info);
1404 return 0;
1407 static int tdfxfb_pan_display(struct fb_var_screeninfo* var,
1408 int con,
1409 struct fb_info* fb) {
1410 struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
1411 __u32 addr;
1413 if(nowrap && nopan) {
1414 return -EINVAL;
1415 } else {
1416 if(var->xoffset)
1417 return -EINVAL;
1418 if(var->yoffset < 0)
1419 return -EINVAL;
1420 if(nopan && var->yoffset > var->yres_virtual)
1421 return -EINVAL;
1422 if(nowrap && var->yoffset + var->yres > var->yres_virtual)
1423 return -EINVAL;
1425 i->current_par.baseline = var->yoffset;
1427 addr = var->yoffset*i->current_par.lpitch;
1428 tdfx_outl(VIDDESKSTART, addr);
1429 tdfx_outl(SRCBASE, addr);
1430 tdfx_outl(DSTBASE, addr);
1431 return 0;
1435 static int tdfxfb_get_cmap(struct fb_cmap *cmap,
1436 int kspc,
1437 int con,
1438 struct fb_info *fb) {
1439 if(!fb->display_fg || con == fb->display_fg->vc_num) {
1440 /* current console? */
1441 return fb_get_cmap(cmap, kspc, tdfxfb_getcolreg, fb);
1442 } else if(fb_display[con].cmap.len) {
1443 /* non default colormap? */
1444 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
1445 } else {
1446 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
1447 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
1449 return 0;
1452 static int tdfxfb_set_cmap(struct fb_cmap *cmap,
1453 int kspc,
1454 int con,
1455 struct fb_info *fb) {
1456 int err;
1457 struct display *disp;
1459 if(con >= 0)
1460 disp = &fb_display[con];
1461 else
1462 disp = fb->disp;
1463 if(!disp->cmap.len) { /* no colormap allocated? */
1464 int size = disp->var.bits_per_pixel == 16 ? 32 : 256;
1465 if((err = fb_alloc_cmap(&disp->cmap, size, 0)))
1466 return err;
1468 if(!fb->display_fg || con == fb->display_fg->vc_num) {
1469 /* current console? */
1470 return fb_set_cmap(cmap, kspc, tdfxfb_setcolreg, fb);
1471 } else {
1472 fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
1474 return 0;
1477 static int tdfxfb_ioctl(struct inode *inode,
1478 struct file *file,
1479 u_int cmd,
1480 u_long arg,
1481 int con,
1482 struct fb_info *fb) {
1483 return -EINVAL;
1486 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1487 __initfunc(void tdfxfb_init(void)) {
1488 #else
1489 int __init tdfxfb_init(void) {
1490 #endif
1491 struct pci_dev *pdev = NULL;
1492 struct fb_var_screeninfo var;
1493 int j, k;
1495 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1496 if(!pcibios_present()) return;
1497 #else
1498 if(!pcibios_present()) return -ENXIO;
1499 #endif
1501 for(pdev = pci_devices; pdev; pdev = pdev->next) {
1502 if(((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
1503 (pdev->vendor == PCI_VENDOR_ID_3DFX) &&
1504 ((pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE) ||
1505 (pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3))) {
1507 fb_info.dev = pdev->device;
1508 fb_info.max_pixclock =
1509 pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE
1510 ? BANSHEE_MAX_PIXCLOCK
1511 : VOODOO3_MAX_PIXCLOCK;
1513 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1514 fb_info.regbase_phys = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
1515 fb_info.regbase_size = 1 << 25;
1516 fb_info.regbase_virt =
1517 (__u32)ioremap_nocache(fb_info.regbase_phys, 1 << 25);
1518 if(!fb_info.regbase_virt) {
1519 if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
1520 printk("fb: Can't remap Banshee register area.\n");
1521 else
1522 printk("fb: Can't remap Voodoo3 register area.\n");
1523 return;
1526 fb_info.bufbase_phys = pdev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK;
1527 if(!(fb_info.bufbase_size = tdfx_lfb_size())) {
1528 if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
1529 printk("fb: Can't count Banshee memory.\n");
1530 else
1531 printk("fb: Can't count Voodoo3 memory.\n");
1532 iounmap((void*)fb_info.regbase_virt);
1533 return;
1535 fb_info.bufbase_virt =
1536 (__u32)ioremap_nocache(fb_info.bufbase_phys, 1 << 25);
1537 if(!fb_info.regbase_virt) {
1538 if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
1539 printk("fb: Can't remap Banshee framebuffer.\n");
1540 else
1541 printk("fb: Can't remap Voodoo3 framebuffer.\n");
1542 iounmap((void*)fb_info.regbase_virt);
1543 return;
1545 #else
1546 fb_info.regbase_phys = pdev->resource[0].start;
1547 fb_info.regbase_size = 1 << 25;
1548 fb_info.regbase_virt =
1549 (__u32)ioremap_nocache(fb_info.regbase_phys, 1 << 25);
1550 if(!fb_info.regbase_virt) {
1551 if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
1552 printk("fb: Can't remap Banshee register area.\n");
1553 else
1554 printk("fb: Can't remap Voodoo3 register area.\n");
1555 return -ENXIO;
1558 fb_info.bufbase_phys = pdev->resource[1].start;
1559 if(!(fb_info.bufbase_size = tdfx_lfb_size())) {
1560 iounmap((void*)fb_info.regbase_virt);
1561 if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
1562 printk("fb: Can't count Banshee memory.\n");
1563 else
1564 printk("fb: Can't count Voodoo3 memory.\n");
1565 return -ENXIO;
1567 fb_info.bufbase_virt =
1568 (__u32)ioremap_nocache(fb_info.bufbase_phys, 1 << 25);
1569 if(!fb_info.regbase_virt) {
1570 if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
1571 printk("fb: Can't remap Banshee framebuffer.\n");
1572 else
1573 printk("fb: Can't remap Voodoo3 framebuffer.\n");
1574 iounmap((void*)fb_info.regbase_virt);
1575 return -ENXIO;
1577 #endif
1579 if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
1580 printk("fb: Banshee memory = %ldK\n", fb_info.bufbase_size >> 10);
1581 else
1582 printk("fb: Voodoo3 memory = %ldK\n", fb_info.bufbase_size >> 10);
1584 /* clear framebuffer memory */
1585 memset_io(fb_info.bufbase_virt, 0, fb_info.bufbase_size);
1587 if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
1588 strcpy(fb_info.fb_info.modename, "3Dfx Banshee");
1589 else
1590 strcpy(fb_info.fb_info.modename, "3Dfx Voodoo3");
1591 fb_info.fb_info.changevar = NULL;
1592 fb_info.fb_info.node = -1;
1593 fb_info.fb_info.fbops = &tdfxfb_ops;
1594 fb_info.fb_info.disp = &fb_info.disp;
1595 strcpy(fb_info.fb_info.fontname, fontname);
1596 fb_info.fb_info.switch_con = &tdfxfb_switch_con;
1597 fb_info.fb_info.updatevar = &tdfxfb_updatevar;
1598 fb_info.fb_info.blank = &tdfxfb_blank;
1599 fb_info.fb_info.flags = FBINFO_FLAG_DEFAULT;
1601 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1602 var = default_mode[default_mode_index < modes
1603 ? default_mode_index
1604 : 0].var;
1605 #else
1606 memset(&var, 0, sizeof(var));
1607 if(!mode_option ||
1608 !fb_find_mode(&var, &fb_info.fb_info, mode_option, NULL, 0, NULL, 8))
1609 var = default_mode[0].var;
1610 #endif
1612 if(noaccel) var.accel_flags &= ~FB_ACCELF_TEXT;
1613 else var.accel_flags |= FB_ACCELF_TEXT;
1615 if(tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
1616 /* ugh -- can't use the mode from the mode db. (or command line),
1617 so try the default */
1619 printk("tdfxfb: "
1620 "can't decode the supplied video mode, using default\n");
1622 var = default_mode[0].var;
1623 if(noaccel) var.accel_flags &= ~FB_ACCELF_TEXT;
1624 else var.accel_flags |= FB_ACCELF_TEXT;
1626 if(tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
1627 printk("tdfxfb: can't decode default video mode\n");
1628 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1629 return;
1630 #else
1631 return -ENXIO;
1632 #endif
1636 fb_info.disp.screen_base = (void*)fb_info.bufbase_virt;
1637 fb_info.disp.visual =
1638 var.bits_per_pixel == 8
1639 ? FB_VISUAL_PSEUDOCOLOR
1640 : FB_VISUAL_DIRECTCOLOR;
1641 fb_info.disp.type = FB_TYPE_PACKED_PIXELS;
1642 fb_info.disp.type_aux = 0;
1644 fb_info.disp.ypanstep = (nowrap && nopan) ? 0 : 1;
1645 fb_info.disp.ywrapstep = nowrap ? 0 : 1;
1647 fb_info.disp.line_length =
1648 fb_info.disp.next_line =
1649 var.xres*(var.bits_per_pixel + 7)/8;
1650 fb_info.disp.can_soft_blank = 1;
1651 fb_info.disp.inverse = inverse;
1652 fb_info.disp.scrollmode = SCROLL_YREDRAW;
1653 fb_info.disp.var = var;
1654 tdfxfb_set_disp(&fb_info.disp, &fb_info,
1655 var.bits_per_pixel,
1658 for(j = 0; j < 16; j++) {
1659 k = color_table[j];
1660 fb_info.palette[j].red = default_red[k];
1661 fb_info.palette[j].green = default_grn[k];
1662 fb_info.palette[j].blue = default_blu[k];
1665 if(tdfxfb_set_var(&var, -1, &fb_info.fb_info)) {
1666 printk("tdfxfb: can't set default video mode\n");
1667 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1668 return;
1669 #else
1670 return -ENXIO;
1671 #endif
1674 if(register_framebuffer(&fb_info.fb_info) < 0) {
1675 printk("tdfxfb: can't register framebuffer\n");
1676 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1677 return;
1678 #else
1679 return -ENXIO;
1680 #endif
1683 printk("fb%d: %s frame buffer device\n",
1684 GET_FB_IDX(fb_info.fb_info.node),
1685 fb_info.fb_info.modename);
1687 MOD_INC_USE_COUNT;
1689 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1690 return;
1691 #else
1692 return 0;
1693 #endif
1697 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1698 return;
1699 #else
1700 return -ENXIO;
1701 #endif
1704 void tdfxfb_setup(char *options,
1705 int *ints) {
1706 char* this_opt;
1708 if(!options || !*options)
1709 return;
1711 for(this_opt = strtok(options, ",");
1712 this_opt;
1713 this_opt = strtok(NULL, ",")) {
1714 if(!strcmp(this_opt, "inverse")) {
1715 inverse = 1;
1716 fb_invert_cmaps();
1717 } else if(!strcmp(this_opt, "noaccel")) {
1718 noaccel = 1;
1719 } else if(!strcmp(this_opt, "nopan")) {
1720 nopan = 1;
1721 } else if(!strcmp(this_opt, "nowrap")) {
1722 nowrap = 1;
1723 } else if (!strncmp(this_opt, "font:", 5)) {
1724 strncpy(fontname, this_opt + 5, 40);
1725 } else {
1726 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1727 int i;
1728 for(i = 0; i < modes; i++) {
1729 if(!strcmp(this_opt, default_mode[i].name)) {
1730 default_mode_index = i;
1733 #else
1734 mode_option = this_opt;
1735 #endif
1740 static int tdfxfb_switch_con(int con,
1741 struct fb_info *fb) {
1742 struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
1743 struct tdfxfb_par par;
1745 /* Do we have to save the colormap? */
1746 if(fb_display[currcon].cmap.len)
1747 fb_get_cmap(&fb_display[currcon].cmap, 1, tdfxfb_getcolreg, fb);
1749 currcon = con;
1751 tdfxfb_decode_var(&fb_display[con].var, &par, info);
1752 tdfxfb_set_par(&par, info);
1753 tdfxfb_set_disp(&fb_display[con],
1754 info,
1755 par.bpp,
1756 par.accel_flags & FB_ACCELF_TEXT);
1758 tdfxfb_install_cmap(con, fb);
1759 tdfxfb_updatevar(con, fb);
1761 return 1;
1764 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
1765 static void tdfxfb_blank(int blank,
1766 struct fb_info *fb) {
1767 u32 dacmode, state = 0, vgablank = 0;
1769 dacmode = tdfx_inl(DACMODE);
1771 switch(blank) {
1772 case 0: /* Screen: On; HSync: On, VSync: On */
1773 state = 0;
1774 vgablank = 0;
1775 break;
1776 case 1: /* Screen: Off; HSync: On, VSync: On */
1777 state = 0;
1778 vgablank = 1;
1779 break;
1780 case 2: /* Screen: Off; HSync: On, VSync: Off */
1781 state = BIT(3);
1782 vgablank = 1;
1783 break;
1784 case 3: /* Screen: Off; HSync: Off, VSync: On */
1785 state = BIT(1);
1786 vgablank = 1;
1787 break;
1788 case 4: /* Screen: Off; HSync: Off, VSync: Off */
1789 state = BIT(1) | BIT(3);
1790 vgablank = 1;
1791 break;
1794 dacmode &= ~(BIT(1) | BIT(3));
1795 dacmode |= state;
1796 tdfx_outl(DACMODE, dacmode);
1797 if(vgablank)
1798 vga_disable_video();
1799 else
1800 vga_enable_video();
1802 return;
1805 static int tdfxfb_updatevar(int con,
1806 struct fb_info* fb) {
1807 if(con != currcon || (nowrap && nopan)) {
1808 return 0;
1809 } else {
1810 struct fb_var_screeninfo* var = &fb_display[currcon].var;
1811 return tdfxfb_pan_display(var, con, fb);
1815 static int tdfxfb_getcolreg(unsigned regno,
1816 unsigned* red,
1817 unsigned* green,
1818 unsigned* blue,
1819 unsigned* transp,
1820 struct fb_info* fb) {
1821 struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
1823 if(regno < 256) {
1824 *red = i->palette[regno].red << 8 | i->palette[regno].red;
1825 *green = i->palette[regno].green << 8 | i->palette[regno].green;
1826 *blue = i->palette[regno].blue << 8 | i->palette[regno].blue;
1827 *transp = 0;
1829 return regno > 255;
1832 static int tdfxfb_setcolreg(unsigned regno,
1833 unsigned red,
1834 unsigned green,
1835 unsigned blue,
1836 unsigned transp,
1837 struct fb_info* info) {
1838 struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
1840 if(regno < 16) {
1841 switch(i->current_par.bpp) {
1842 #ifdef FBCON_HAS_CFB8
1843 case 8:
1844 break;
1845 #endif
1846 #ifdef FBCON_HAS_CFB16
1847 case 16:
1848 i->fbcon_cmap.cfb16[regno] =
1849 (((u32)red & 0xf800) >> 0) |
1850 (((u32)green & 0xfc00) >> 5) |
1851 (((u32)blue & 0xf800) >> 11);
1852 break;
1853 #endif
1854 #ifdef FBCON_HAS_CFB32
1855 case 32:
1856 i->fbcon_cmap.cfb32[regno] =
1857 (((u32)red & 0xff00) << 8) |
1858 (((u32)green & 0xff00) << 0) |
1859 (((u32)blue & 0xff00) >> 8);
1860 break;
1861 #endif
1862 default:
1863 DPRINTK("bad depth %u\n", i->current_par.bpp);
1864 break;
1867 if(regno < 256) {
1868 i->palette[regno].red = red >> 8;
1869 i->palette[regno].green = green >> 8;
1870 i->palette[regno].blue = blue >> 8;
1871 if(i->current_par.bpp == 8) {
1872 vga_outb(DAC_IW, (unsigned char)regno);
1873 vga_outb(DAC_D, (unsigned char)(red >> 8));
1874 vga_outb(DAC_D, (unsigned char)(green >> 8));
1875 vga_outb(DAC_D, (unsigned char)(blue >> 8));
1878 return regno > 255;
1881 static void tdfxfb_install_cmap(int con,
1882 struct fb_info* info) {
1883 if(con != currcon) return;
1884 if(fb_display[con].cmap.len) {
1885 fb_set_cmap(&fb_display[con].cmap, 1, tdfxfb_setcolreg, info);
1886 } else {
1887 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
1888 fb_set_cmap(fb_default_cmap(size), 1, tdfxfb_setcolreg, info);