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(®, 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(®);
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