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