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