~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/video/tdfxfb.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.