5 * Author: Hannu Mallat <hmallat@cc.hut.fi>
7 * Copyright © 1999 Hannu Mallat
10 * Created : Thu Sep 23 18:17:43 1999, hmallat
11 * Last modified: Thu Oct 7 18:39:04 1999, hmallat
13 * Lots of the information here comes from the Daryll Strauss' Banshee
14 * patches to the XF86 server, and the rest comes from the 3dfx
15 * Banshee specification. I'm very much indebted to Daryll for his
16 * work on the X server.
18 * Voodoo3 support was contributed Harold Oga. Thanks!
20 * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
21 * I do wish the next version is a bit more complete. Without the XF86
22 * patches I couldn't have gotten even this far... for instance, the
23 * extensions to the VGA register set go completely unmentioned in the
24 * spec! Also, lots of references are made to the 'SST core', but no
25 * spec is publicly available, AFAIK.
27 * The structure of this driver comes pretty much from the Permedia
28 * driver by Ilario Nardinocchi, which in turn is based on skeletonfb.
31 * - support for 16/32 bpp needs fixing (funky bootup penguin)
32 * - multihead support (it's all hosed now with pokes to VGA standard
33 * register locations, but shouldn't be that hard to change, some
34 * other code needs to be changed too where the fb_info (which should
35 * be an array of head-specific information) is referred to directly.
38 * - better acceleration support (e.g., font blitting from fb memory?)
39 * - banshee and voodoo3 now supported -- any others? afaik, the original
40 * voodoo was a 3d-only card, so we won't consider that. what about
43 * - panning (doesn't seem to work properly yet)
47 * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga.
48 * 0.1.0 (released 1999-10-06) initial version
52 #include <linux/config.h>
53 #include <linux/module.h>
54 #include <linux/kernel.h>
55 #include <linux/errno.h>
56 #include <linux/string.h>
58 #include <linux/tty.h>
59 #include <linux/malloc.h>
60 #include <linux/vmalloc.h>
61 #include <linux/delay.h>
62 #include <linux/interrupt.h>
64 #include <linux/selection.h>
65 #include <linux/console.h>
66 #include <linux/init.h>
67 #include <linux/pci.h>
68 #include <linux/nvram.h>
70 #include <linux/vt_kern.h>
73 #include <video/fbcon.h>
74 #include <video/fbcon-cfb8.h>
75 #include <video/fbcon-cfb16.h>
76 #include <video/fbcon-cfb32.h>
78 #ifndef LINUX_VERSION_CODE
79 #include <linux/version.h>
82 #ifndef KERNEL_VERSION
83 #define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
86 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
87 #define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005
90 /* membase0 register offsets */
93 #define SIPMONITOR 0x08
94 #define LFBMEMORYCONFIG 0x0c
95 #define MISCINIT0 0x10
96 #define MISCINIT1 0x14
97 #define DRAMINIT0 0x18
98 #define DRAMINIT1 0x1c
100 #define TMUGBEINIT 0x24
101 #define VGAINIT0 0x28
102 #define VGAINIT1 0x2c
103 #define DRAMCOMMAND 0x30
104 #define DRAMDATA 0x34
107 #define PLLCTRL0 0x40
108 #define PLLCTRL1 0x44
109 #define PLLCTRL2 0x48
113 #define RGBMAXDELTA 0x58
114 #define VIDPROCCFG 0x5c
115 #define HWCURPATADDR 0x60
116 #define HWCURLOC 0x64
119 #define VIDINFORMAT 0x70
120 #define VIDINSTATUS 0x74
121 #define VIDSERPARPORT 0x78
122 #define VIDINXDELTA 0x7c
123 #define VIDININITERR 0x80
124 #define VIDINYDELTA 0x84
125 #define VIDPIXBUFTHOLD 0x88
126 #define VIDCHRMIN 0x8c
127 #define VIDCHRMAX 0x90
128 #define VIDCURLIN 0x94
129 #define VIDSCREENSIZE 0x98
130 #define VIDOVRSTARTCRD 0x9c
131 #define VIDOVRENDCRD 0xa0
132 #define VIDOVRDUDX 0xa4
133 #define VIDOVRDUDXOFF 0xa8
134 #define VIDOVRDVDY 0xac
136 #define VIDOVRDVDYOFF 0xe0
137 #define VIDDESKSTART 0xe4
138 #define VIDDESKSTRIDE 0xe8
139 #define VIDINADDR0 0xec
140 #define VIDINADDR1 0xf0
141 #define VIDINADDR2 0xf4
142 #define VIDINSTRIDE 0xf8
143 #define VIDCUROVRSTART 0xfc
145 #define INTCTRL (0x00100000 + 0x04)
146 #define CLIP0MIN (0x00100000 + 0x08)
147 #define CLIP0MAX (0x00100000 + 0x0c)
148 #define DSTBASE (0x00100000 + 0x10)
149 #define DSTFORMAT (0x00100000 + 0x14)
150 #define SRCBASE (0x00100000 + 0x34)
151 #define COMMANDEXTRA_2D (0x00100000 + 0x38)
152 #define CLIP1MIN (0x00100000 + 0x4c)
153 #define CLIP1MAX (0x00100000 + 0x50)
154 #define SRCFORMAT (0x00100000 + 0x54)
155 #define SRCSIZE (0x00100000 + 0x58)
156 #define SRCXY (0x00100000 + 0x5c)
157 #define COLORBACK (0x00100000 + 0x60)
158 #define COLORFORE (0x00100000 + 0x64)
159 #define DSTSIZE (0x00100000 + 0x68)
160 #define DSTXY (0x00100000 + 0x6c)
161 #define COMMAND_2D (0x00100000 + 0x70)
162 #define LAUNCH_2D (0x00100000 + 0x80)
164 #define COMMAND_3D (0x00200000 + 0x120)
166 /* register bitfields (not all, only as needed) */
168 #define BIT(x) (1UL << (x))
170 #define ROP_COPY 0xcc
172 #define COMMAND_2D_FILLRECT 0x05
173 #define COMMAND_2D_BITBLT 0x01
175 #define COMMAND_3D_NOP 0x00
177 #define STATUS_RETRACE BIT(6)
178 #define STATUS_BUSY BIT(9)
180 #define MISCINIT1_CLUT_INV BIT(0)
181 #define MISCINIT1_2DBLOCK_DIS BIT(15)
183 #define DRAMINIT0_SGRAM_NUM BIT(26)
184 #define DRAMINIT0_SGRAM_TYPE BIT(27)
186 #define DRAMINIT1_MEM_SDRAM BIT(30)
188 #define VGAINIT0_VGA_DISABLE BIT(0)
189 #define VGAINIT0_EXT_TIMING BIT(1)
190 #define VGAINIT0_8BIT_DAC BIT(2)
191 #define VGAINIT0_EXT_ENABLE BIT(6)
192 #define VGAINIT0_WAKEUP_3C3 BIT(8)
193 #define VGAINIT0_LEGACY_DISABLE BIT(9)
194 #define VGAINIT0_ALT_READBACK BIT(10)
195 #define VGAINIT0_FAST_BLINK BIT(11)
196 #define VGAINIT0_EXTSHIFTOUT BIT(12)
197 #define VGAINIT0_DECODE_3C6 BIT(13)
198 #define VGAINIT0_SGRAM_HBLANK_DISABLE BIT(22)
200 #define VGAINIT1_MASK 0x1fffff
202 #define VIDCFG_VIDPROC_ENABLE BIT(0)
203 #define VIDCFG_CURS_X11 BIT(1)
204 #define VIDCFG_HALF_MODE BIT(4)
205 #define VIDCFG_DESK_ENABLE BIT(7)
206 #define VIDCFG_CLUT_BYPASS BIT(10)
207 #define VIDCFG_2X BIT(26)
208 #define VIDCFG_PIXFMT_SHIFT 18
210 #define DACMODE_2X BIT(0)
212 /* VGA rubbish, need to change this for multihead support */
227 #ifndef FB_ACCEL_3DFX_BANSHEE
228 #define FB_ACCEL_3DFX_BANSHEE 31
231 #define TDFXF_HSYNC_ACT_HIGH 0x01
232 #define TDFXF_HSYNC_ACT_LOW 0x02
233 #define TDFXF_VSYNC_ACT_HIGH 0x04
234 #define TDFXF_VSYNC_ACT_LOW 0x08
235 #define TDFXF_LINE_DOUBLE 0x10
236 #define TDFXF_VIDEO_ENABLE 0x20
238 #define TDFXF_HSYNC_MASK 0x03
239 #define TDFXF_VSYNC_MASK 0x0c
241 /* #define TDFXFB_DEBUG */
243 #define DPRINTK(a,b...) printk("fb: %s: " a, __FUNCTION__ , ## b)
245 #define DPRINTK(a,b...)
248 #define PICOS2KHZ(a) (1000000000UL/(a))
249 #define KHZ2PICOS(a) (1000000000UL/(a))
251 #define BANSHEE_MAX_PIXCLOCK 270000.0
252 #define VOODOO3_MAX_PIXCLOCK 300000.0
256 unsigned char att
[21];
257 unsigned char crt
[25];
258 unsigned char gra
[ 9];
259 unsigned char misc
[1];
260 unsigned char seq
[ 5];
262 /* Banshee extensions */
263 unsigned char ext
[2];
264 unsigned long vidcfg
;
265 unsigned long vidpll
;
266 unsigned long mempll
;
267 unsigned long gfxpll
;
268 unsigned long dacmode
;
269 unsigned long vgainit0
;
270 unsigned long vgainit1
;
271 unsigned long screensize
;
272 unsigned long stride
;
273 unsigned long cursloc
;
274 unsigned long startaddr
;
275 unsigned long clip0min
;
276 unsigned long clip0max
;
277 unsigned long clip1min
;
278 unsigned long clip1max
;
279 unsigned long srcbase
;
280 unsigned long dstbase
;
292 u32 lpitch
; /* line pitch, in bytes */
293 u32 ppitch
; /* pixel pitch, in bits */
310 struct fb_info_tdfx
{
311 struct fb_info fb_info
;
316 unsigned long regbase_phys
;
317 unsigned long regbase_virt
;
318 unsigned long regbase_size
;
319 unsigned long bufbase_phys
;
320 unsigned long bufbase_virt
;
321 unsigned long bufbase_size
;
323 struct { u8 red
, green
, blue
, pad
; } palette
[256];
324 struct tdfxfb_par default_par
;
325 struct tdfxfb_par current_par
;
327 struct display_switch dispsw
;
330 #ifdef FBCON_HAS_CFB16
333 #ifdef FBCON_HAS_CFB32
340 * Frame buffer device API
342 static int tdfxfb_open(struct fb_info
* info
,
344 static int tdfxfb_release(struct fb_info
* info
,
346 static int tdfxfb_get_fix(struct fb_fix_screeninfo
* fix
,
349 static int tdfxfb_get_var(struct fb_var_screeninfo
* var
,
352 static int tdfxfb_set_var(struct fb_var_screeninfo
* var
,
355 static int tdfxfb_pan_display(struct fb_var_screeninfo
* var
,
358 static int tdfxfb_get_cmap(struct fb_cmap
*cmap
,
361 struct fb_info
* info
);
362 static int tdfxfb_set_cmap(struct fb_cmap
* cmap
,
365 struct fb_info
* info
);
366 static int tdfxfb_ioctl(struct inode
* inode
,
371 struct fb_info
* info
);
374 * Interface to the low level console driver
376 static int tdfxfb_switch_con(int con
,
378 static int tdfxfb_updatevar(int con
,
380 static void tdfxfb_blank(int blank
,
386 static void tdfxfb_set_par(const struct tdfxfb_par
* par
,
389 static int tdfxfb_decode_var(const struct fb_var_screeninfo
*var
,
390 struct tdfxfb_par
*par
,
391 const struct fb_info_tdfx
*info
);
392 static int tdfxfb_encode_var(struct fb_var_screeninfo
* var
,
393 const struct tdfxfb_par
* par
,
394 const struct fb_info_tdfx
* info
);
395 static int tdfxfb_encode_fix(struct fb_fix_screeninfo
* fix
,
396 const struct tdfxfb_par
* par
,
397 const struct fb_info_tdfx
* info
);
398 static void tdfxfb_set_disp(struct display
* disp
,
399 struct fb_info_tdfx
* info
,
402 static int tdfxfb_getcolreg(u_int regno
,
408 static int tdfxfb_setcolreg(u_int regno
,
414 static void tdfxfb_install_cmap(int con
,
415 struct fb_info
*info
);
418 * Interface used by the world
420 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
421 void tdfxfb_init(void);
423 int tdfxfb_init(void);
425 void tdfxfb_setup(char *options
,
428 static int currcon
= 0;
430 static struct fb_ops tdfxfb_ops
= {
445 struct fb_var_screeninfo var
;
448 /* 2.3.x kernels have a fb mode database, so supply only one backup default */
449 struct mode default_mode
[] = {
450 { "640x480-8@60", /* @ 60 Hz */
452 640, 480, 640, 480, 0, 0, 8, 0,
453 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
454 0, FB_ACTIVATE_NOW
, -1, -1, FB_ACCELF_TEXT
,
455 39722, 40, 24, 32, 11, 96, 2,
456 0, FB_VMODE_NONINTERLACED
459 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
461 { "800x600-8@56", /* @ 56 Hz */
463 800, 600, 800, 600, 0, 0, 8, 0,
464 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
465 0, FB_ACTIVATE_NOW
, -1, -1, FB_ACCELF_TEXT
,
466 27778, 128, 24, 22, 1, 72, 2,
467 0, FB_VMODE_NONINTERLACED
470 { "1024x768-8@60", /* @ 60 Hz */
472 1024, 768, 1024, 768, 0, 0, 8, 0,
473 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
474 0, FB_ACTIVATE_NOW
, -1, -1, FB_ACCELF_TEXT
,
475 15385, 168, 8, 29, 3, 144, 6,
476 0, FB_VMODE_NONINTERLACED
479 { "1280x1024-8@61", /* @ 61 Hz */
481 1280, 1024, 1280, 1024, 0, 0, 8, 0,
482 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
483 0, FB_ACTIVATE_NOW
, -1, -1, FB_ACCELF_TEXT
,
484 9091, 200, 48, 26, 1, 184, 3,
485 0, FB_VMODE_NONINTERLACED
488 { "1024x768-16@60", /* @ 60 Hz */ /* basically for testing */
490 1024, 768, 1024, 768, 0, 0, 16, 0,
491 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
492 0, FB_ACTIVATE_NOW
, -1, -1, FB_ACCELF_TEXT
,
493 15385, 168, 8, 29, 3, 144, 6,
494 0, FB_VMODE_NONINTERLACED
500 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
501 static int modes
= sizeof(default_mode
)/sizeof(struct mode
);
502 static int default_mode_index
= 0;
505 static struct fb_info_tdfx fb_info
;
507 static int __initdata noaccel
= 0;
508 static int __initdata nopan
= 0;
509 static int __initdata nowrap
= 0;
510 static int __initdata inverse
= 0;
511 static char __initdata fontname
[40] = { 0 };
512 static const char *mode_option __initdata
= NULL
;
514 /* ------------------------------------------------------------------------- */
516 static inline __u8
vga_inb(__u32 reg
) { return inb(reg
); }
517 static inline __u16
vga_inw(__u32 reg
) { return inw(reg
); }
518 static inline __u16
vga_inl(__u32 reg
) { return inl(reg
); }
520 static inline void vga_outb(__u32 reg
, __u8 val
) { outb(val
, reg
); }
521 static inline void vga_outw(__u32 reg
, __u16 val
) { outw(val
, reg
); }
522 static inline void vga_outl(__u32 reg
, __u32 val
) { outl(val
, reg
); }
524 static inline void gra_outb(__u32 idx
, __u8 val
) {
525 vga_outb(GRA_I
, idx
); vga_outb(GRA_D
, val
);
528 static inline __u8
gra_inb(__u32 idx
) {
529 vga_outb(GRA_I
, idx
); return vga_inb(GRA_D
);
532 static inline void seq_outb(__u32 idx
, __u8 val
) {
533 vga_outb(SEQ_I
, idx
); vga_outb(SEQ_D
, val
);
536 static inline __u8
seq_inb(__u32 idx
) {
537 vga_outb(SEQ_I
, idx
); return vga_inb(SEQ_D
);
540 static inline void crt_outb(__u32 idx
, __u8 val
) {
541 vga_outb(CRT_I
, idx
); vga_outb(CRT_D
, val
);
544 static inline __u8
crt_inb(__u32 idx
) {
545 vga_outb(CRT_I
, idx
); return vga_inb(CRT_D
);
548 static inline void att_outb(__u32 idx
, __u8 val
) {
550 tmp
= vga_inb(IS1_R
);
551 vga_outb(ATT_IW
, idx
);
552 vga_outb(ATT_IW
, val
);
555 static inline __u8
att_inb(__u32 idx
) {
557 tmp
= vga_inb(IS1_R
);
558 vga_outb(ATT_IW
, idx
);
559 return vga_inb(ATT_IW
);
562 static inline void vga_disable_video(void) {
564 s
= seq_inb(0x01) | 0x20;
565 seq_outb(0x00, 0x01);
567 seq_outb(0x00, 0x03);
570 static inline void vga_enable_video(void) {
572 s
= seq_inb(0x01) & 0xdf;
573 seq_outb(0x00, 0x01);
575 seq_outb(0x00, 0x03);
578 static inline void vga_disable_palette(void) {
580 vga_outb(ATT_IW
, 0x00);
583 static inline void vga_enable_palette(void) {
585 vga_outb(ATT_IW
, 0x20);
588 static inline __u32
tdfx_inl(unsigned int reg
) {
589 return readl(fb_info
.regbase_virt
+ reg
);
592 static inline void tdfx_outl(unsigned int reg
, __u32 val
) {
593 writel(val
, fb_info
.regbase_virt
+ reg
);
596 static inline void banshee_make_room(int size
) {
597 while((tdfx_inl(STATUS
) & 0x1f) < size
);
600 static inline void banshee_wait_idle(void) {
603 banshee_make_room(1);
604 tdfx_outl(COMMAND_3D
, COMMAND_3D_NOP
);
607 i
= (tdfx_inl(STATUS
) & STATUS_BUSY
) ? 0 : i
+ 1;
612 static void banshee_fillrect(__u32 x
,
619 banshee_make_room(2);
622 (bpp
== 8 ? 0x10000 :
623 bpp
== 16 ? 0x30000 : 0x50000));
624 tdfx_outl(COLORFORE
, color
);
626 banshee_make_room(3);
627 tdfx_outl(COMMAND_2D
, COMMAND_2D_FILLRECT
| (ROP_COPY
<< 24));
628 tdfx_outl(DSTSIZE
, (w
& 0x1fff) | ((h
& 0x1fff) << 16));
629 tdfx_outl(LAUNCH_2D
, (x
& 0x1fff) | ((y
& 0x1fff) << 16));
632 static void banshee_bitblt(__u32 curx
,
642 xdir
= dstx
< curx
? 1 : -1;
643 ydir
= dsty
< cury
? 1 : -1;
645 banshee_make_room(4);
648 (bpp
== 8 ? 0x10000 :
649 bpp
== 16 ? 0x30000 : 0x50000));
652 (bpp
== 8 ? 0x10000 :
653 bpp
== 16 ? 0x30000 : 0x50000));
654 tdfx_outl(COMMAND_2D
,
656 (xdir
== -1 ? BIT(14) : 0) |
657 (ydir
== -1 ? BIT(15) : 0));
658 tdfx_outl(COMMANDEXTRA_2D
, 0); /* no color keying */
669 /* Consecutive overlapping regions can hang the board --
670 since we allow mmap'ing of control registers, we cannot
671 __safely__ assume anything, like XF86 does... */
672 banshee_make_room(1);
673 tdfx_outl(COMMAND_3D
, COMMAND_3D_NOP
);
675 banshee_make_room(3);
676 tdfx_outl(DSTSIZE
, (width
& 0x1fff) | ((height
& 0x1fff) << 16));
677 tdfx_outl(DSTXY
, (dstx
& 0x1fff) | ((dsty
& 0x1fff) << 16));
678 tdfx_outl(LAUNCH_2D
, (curx
& 0x1fff) | ((cury
& 0x1fff) << 16));
681 static __u32
banshee_calc_pll(int freq
, int* freq_out
) {
682 int m
, n
, k
, best_m
, best_n
, best_k
, f_cur
, best_error
;
685 /* this really could be done with more intelligence */
687 best_n
= best_m
= best_k
= 0;
688 for(n
= 1; n
< 256; n
++) {
689 for(m
= 1; m
< 64; m
++) {
690 for(k
= 0; k
< 4; k
++) {
691 f_cur
= fref
*(n
+ 2)/(m
+ 2)/(1 << k
);
692 if(abs(f_cur
- freq
) < best_error
) {
693 best_error
= abs(f_cur
-freq
);
704 *freq_out
= fref
*(n
+ 2)/(m
+ 2)/(1 << k
);
706 DPRINTK("freq = %d kHz, freq_out = %d kHz\n", freq
, *freq_out
);
707 DPRINTK("N = %d, M = %d, K = %d\n", n
, m
, k
);
709 return (n
<< 8) | (m
<< 2) | k
;
712 static void banshee_write_regs(struct banshee_reg
* reg
) {
717 tdfx_outl(MISCINIT1
, tdfx_inl(MISCINIT1
) | 0x01);
719 crt_outb(0x11, crt_inb(0x11) & 0x7f); /* CRT unprotect */
721 banshee_make_room(3);
722 tdfx_outl(VGAINIT1
, reg
->vgainit1
& 0x001FFFFF);
723 tdfx_outl(VIDPROCCFG
, reg
->vidcfg
& ~0x00000001);
725 tdfx_outl(PLLCTRL1
, reg
->mempll
);
726 tdfx_outl(PLLCTRL2
, reg
->gfxpll
);
728 tdfx_outl(PLLCTRL0
, reg
->vidpll
);
730 vga_outb(MISC_W
, reg
->misc
[0x00] | 0x01);
732 for(i
= 0; i
< 5; i
++)
733 seq_outb(i
, reg
->seq
[i
]);
735 for(i
= 0; i
< 25; i
++)
736 crt_outb(i
, reg
->crt
[i
]);
738 for(i
= 0; i
< 9; i
++)
739 gra_outb(i
, reg
->gra
[i
]);
741 for(i
= 0; i
< 21; i
++)
742 att_outb(i
, reg
->att
[i
]);
744 crt_outb(0x1a, reg
->ext
[0]);
745 crt_outb(0x1b, reg
->ext
[1]);
747 vga_enable_palette();
750 banshee_make_room(9);
751 tdfx_outl(VGAINIT0
, reg
->vgainit0
);
752 tdfx_outl(DACMODE
, reg
->dacmode
);
753 tdfx_outl(VIDDESKSTRIDE
, reg
->stride
);
754 tdfx_outl(HWCURPATADDR
, reg
->cursloc
);
755 tdfx_outl(VIDSCREENSIZE
, reg
->screensize
);
756 tdfx_outl(VIDDESKSTART
, reg
->startaddr
);
757 tdfx_outl(VIDPROCCFG
, reg
->vidcfg
);
758 tdfx_outl(VGAINIT1
, reg
->vgainit1
);
760 banshee_make_room(7);
761 tdfx_outl(SRCBASE
, reg
->srcbase
);
762 tdfx_outl(DSTBASE
, reg
->dstbase
);
763 tdfx_outl(COMMANDEXTRA_2D
, 0);
764 tdfx_outl(CLIP0MIN
, 0);
765 tdfx_outl(CLIP0MAX
, 0x0fff0fff);
766 tdfx_outl(CLIP1MIN
, 0);
767 tdfx_outl(CLIP1MAX
, 0x0fff0fff);
772 static unsigned long tdfx_lfb_size(void) {
779 if(!((fb_info
.dev
== PCI_DEVICE_ID_3DFX_BANSHEE
) ||
780 (fb_info
.dev
== PCI_DEVICE_ID_3DFX_VOODOO3
)))
783 draminit0
= tdfx_inl(DRAMINIT0
);
784 draminit1
= tdfx_inl(DRAMINIT1
);
786 sgram_p
= (draminit1
& DRAMINIT1_MEM_SDRAM
) ? 0 : 1;
789 (((draminit0
& DRAMINIT0_SGRAM_NUM
) ? 2 : 1) *
790 ((draminit0
& DRAMINIT0_SGRAM_TYPE
) ? 8 : 4) * 1024 * 1024) :
793 /* disable block writes for SDRAM (why?) */
794 miscinit1
= tdfx_inl(MISCINIT1
);
795 miscinit1
|= sgram_p
? 0 : MISCINIT1_2DBLOCK_DIS
;
796 miscinit1
|= MISCINIT1_CLUT_INV
;
797 tdfx_outl(MISCINIT1
, miscinit1
);
802 static void fbcon_banshee_bmove(struct display
* p
,
809 banshee_bitblt(fontwidth(p
)*sx
,
814 fontheight(p
)*height
,
815 fb_info
.current_par
.lpitch
,
816 fb_info
.current_par
.bpp
);
819 static void fbcon_banshee_clear(struct vc_data
* conp
,
827 bg
= attr_bgcol_ec(p
,conp
);
828 banshee_fillrect(fontwidth(p
)*sx
,
831 fontheight(p
)*height
,
833 fb_info
.current_par
.lpitch
,
834 fb_info
.current_par
.bpp
);
837 #ifdef FBCON_HAS_CFB8
838 static struct display_switch fbcon_banshee8
= {
847 fbcon_cfb8_clear_margins
,
851 #ifdef FBCON_HAS_CFB16
852 static struct display_switch fbcon_banshee16
= {
861 fbcon_cfb16_clear_margins
,
865 #ifdef FBCON_HAS_CFB32
866 static struct display_switch fbcon_banshee32
= {
875 fbcon_cfb32_clear_margins
,
880 /* ------------------------------------------------------------------------- */
882 static void tdfxfb_set_par(const struct tdfxfb_par
* par
,
883 struct fb_info_tdfx
* info
) {
884 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)info
;
885 struct banshee_reg reg
;
887 __u32 hd
, hs
, he
, ht
, hbs
, hbe
;
888 __u32 vd
, vs
, ve
, vt
, vbs
, vbe
;
893 memset(®
, 0, sizeof(reg
));
895 cpp
= (par
->bpp
+ 7)/8;
897 wd
= (par
->hdispend
>> 3) - 1;
899 hd
= (par
->hdispend
>> 3) - 1;
900 hs
= (par
->hsyncsta
>> 3) - 1;
901 he
= (par
->hsyncend
>> 3) - 1;
902 ht
= (par
->htotal
>> 3) - 1;
906 vd
= par
->vdispend
- 1;
907 vs
= par
->vsyncsta
- 1;
908 ve
= par
->vsyncend
- 1;
909 vt
= par
->vtotal
- 2;
913 /* this is all pretty standard VGA register stuffing */
916 (par
->hdispend
< 400 ? 0xa0 :
917 par
->hdispend
< 480 ? 0x60 :
918 par
->hdispend
< 768 ? 0xe0 : 0x20);
920 reg
.gra
[0x00] = 0x00;
921 reg
.gra
[0x01] = 0x00;
922 reg
.gra
[0x02] = 0x00;
923 reg
.gra
[0x03] = 0x00;
924 reg
.gra
[0x04] = 0x00;
925 reg
.gra
[0x05] = 0x40;
926 reg
.gra
[0x06] = 0x05;
927 reg
.gra
[0x07] = 0x0f;
928 reg
.gra
[0x08] = 0xff;
930 reg
.att
[0x00] = 0x00;
931 reg
.att
[0x01] = 0x01;
932 reg
.att
[0x02] = 0x02;
933 reg
.att
[0x03] = 0x03;
934 reg
.att
[0x04] = 0x04;
935 reg
.att
[0x05] = 0x05;
936 reg
.att
[0x06] = 0x06;
937 reg
.att
[0x07] = 0x07;
938 reg
.att
[0x08] = 0x08;
939 reg
.att
[0x09] = 0x09;
940 reg
.att
[0x0a] = 0x0a;
941 reg
.att
[0x0b] = 0x0b;
942 reg
.att
[0x0c] = 0x0c;
943 reg
.att
[0x0d] = 0x0d;
944 reg
.att
[0x0e] = 0x0e;
945 reg
.att
[0x0f] = 0x0f;
946 reg
.att
[0x10] = 0x41;
947 reg
.att
[0x11] = 0x00;
948 reg
.att
[0x12] = 0x0f;
949 reg
.att
[0x13] = 0x00;
950 reg
.att
[0x14] = 0x00;
952 reg
.seq
[0x00] = 0x03;
953 reg
.seq
[0x01] = 0x01; /* fixme: clkdiv2? */
954 reg
.seq
[0x02] = 0x0f;
955 reg
.seq
[0x03] = 0x00;
956 reg
.seq
[0x04] = 0x0e;
958 reg
.crt
[0x00] = ht
- 4;
961 reg
.crt
[0x03] = 0x80 | (hbe
& 0x1f);
964 ((hbe
& 0x20) << 2) |
968 ((vs
& 0x200) >> 2) |
969 ((vd
& 0x200) >> 3) |
970 ((vt
& 0x200) >> 4) |
972 ((vbs
& 0x100) >> 5) |
973 ((vs
& 0x100) >> 6) |
974 ((vd
& 0x100) >> 7) |
976 reg
.crt
[0x08] = 0x00;
979 ((vbs
& 0x200) >> 4);
980 reg
.crt
[0x0a] = 0x00;
981 reg
.crt
[0x0b] = 0x00;
982 reg
.crt
[0x0c] = 0x00;
983 reg
.crt
[0x0d] = 0x00;
984 reg
.crt
[0x0e] = 0x00;
985 reg
.crt
[0x0f] = 0x00;
992 reg
.crt
[0x14] = 0x00;
994 reg
.crt
[0x16] = vbe
+ 1;
995 reg
.crt
[0x17] = 0xc3;
996 reg
.crt
[0x18] = 0xff;
998 /* Banshee's nonvga stuff */
999 reg
.ext
[0x00] = (((ht
& 0x100) >> 8) |
1000 ((hd
& 0x100) >> 6) |
1001 ((hbs
& 0x100) >> 4) |
1002 ((hbe
& 0x40) >> 1) |
1003 ((hs
& 0x100) >> 2) |
1004 ((he
& 0x20) << 2));
1005 reg
.ext
[0x01] = (((vt
& 0x400) >> 10) |
1006 ((vd
& 0x400) >> 8) |
1007 ((vbs
& 0x400) >> 6) |
1008 ((vbe
& 0x400) >> 4));
1012 VGAINIT0_EXT_ENABLE
|
1013 VGAINIT0_WAKEUP_3C3
|
1014 VGAINIT0_ALT_READBACK
|
1015 VGAINIT0_EXTSHIFTOUT
;
1016 reg
.vgainit1
= tdfx_inl(VGAINIT1
) & 0x1fffff;
1019 VIDCFG_VIDPROC_ENABLE
|
1020 VIDCFG_DESK_ENABLE
|
1021 ((cpp
- 1) << VIDCFG_PIXFMT_SHIFT
) |
1022 (cpp
!= 1 ? VIDCFG_CLUT_BYPASS
: 0);
1023 reg
.stride
= par
->width
*cpp
;
1026 reg
.startaddr
= par
->baseline
*reg
.stride
;
1027 reg
.srcbase
= reg
.startaddr
;
1028 reg
.dstbase
= reg
.startaddr
;
1031 freq
= par
->pixclock
;
1033 reg
.dacmode
&= ~DACMODE_2X
;
1034 reg
.vidcfg
&= ~VIDCFG_2X
;
1035 if(freq
> i
->max_pixclock
/2) {
1036 freq
= freq
> i
->max_pixclock
? i
->max_pixclock
: freq
;
1037 reg
.dacmode
|= DACMODE_2X
;
1038 reg
.vidcfg
|= VIDCFG_2X
;
1040 reg
.vidpll
= banshee_calc_pll(freq
, &fout
);
1042 reg
.mempll
= banshee_calc_pll(..., &fout
);
1043 reg
.gfxpll
= banshee_calc_pll(..., &fout
);
1046 reg
.screensize
= par
->width
| (par
->height
<< 12);
1047 reg
.vidcfg
&= ~VIDCFG_HALF_MODE
;
1049 banshee_write_regs(®
);
1051 i
->current_par
= *par
;
1054 static int tdfxfb_decode_var(const struct fb_var_screeninfo
* var
,
1055 struct tdfxfb_par
* par
,
1056 const struct fb_info_tdfx
* info
) {
1057 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)info
;
1059 if(var
->bits_per_pixel
!= 8 &&
1060 var
->bits_per_pixel
!= 16 &&
1061 var
->bits_per_pixel
!= 32) {
1062 DPRINTK("depth not supported: %u\n", var
->bits_per_pixel
);
1066 if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_INTERLACED
) {
1067 DPRINTK("interlace not supported\n");
1072 DPRINTK("xoffset not supported\n");
1076 if(var
->xres
!= var
->xres_virtual
) {
1077 DPRINTK("virtual x resolution != physical x resolution not supported\n");
1081 if(nopan
&& nowrap
) {
1082 if(var
->yres
!= var
->yres_virtual
) {
1083 DPRINTK("virtual y resolution != physical y resolution not supported\n");
1087 if(var
->yres
> var
->yres_virtual
) {
1088 DPRINTK("virtual y resolution < physical y resolution not possible\n");
1093 if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_INTERLACED
) {
1094 DPRINTK("interlace not supported\n");
1098 memset(par
, 0, sizeof(struct tdfxfb_par
));
1101 case PCI_DEVICE_ID_3DFX_BANSHEE
:
1102 case PCI_DEVICE_ID_3DFX_VOODOO3
:
1103 par
->width
= (var
->xres
+ 15) & ~15; /* could sometimes be 8 */
1104 par
->width_virt
= par
->width
;
1105 par
->height
= var
->yres
;
1106 par
->height_virt
= var
->yres_virtual
;
1107 par
->bpp
= var
->bits_per_pixel
;
1108 par
->ppitch
= var
->bits_per_pixel
;
1109 par
->lpitch
= par
->width
*par
->ppitch
/8;
1113 if(par
->width
< 320 || par
->width
> 2048) {
1114 DPRINTK("width not supported: %u\n", par
->width
);
1117 if(par
->height
< 200 || par
->height
> 2048) {
1118 DPRINTK("height not supported: %u\n", par
->height
);
1121 if(par
->lpitch
*par
->height_virt
> i
->bufbase_size
) {
1122 DPRINTK("no memory for screen (%ux%ux%u)\n",
1123 par
->width
, par
->height_virt
, par
->bpp
);
1126 par
->pixclock
= PICOS2KHZ(var
->pixclock
);
1127 if(par
->pixclock
> i
->max_pixclock
) {
1128 DPRINTK("pixclock too high (%uKHz)\n", par
->pixclock
);
1132 par
->hdispend
= var
->xres
;
1133 par
->hsyncsta
= par
->hdispend
+ var
->right_margin
;
1134 par
->hsyncend
= par
->hsyncsta
+ var
->hsync_len
;
1135 par
->htotal
= par
->hsyncend
+ var
->left_margin
;
1137 par
->vdispend
= var
->yres
;
1138 par
->vsyncsta
= par
->vdispend
+ var
->lower_margin
;
1139 par
->vsyncend
= par
->vsyncsta
+ var
->vsync_len
;
1140 par
->vtotal
= par
->vsyncend
+ var
->upper_margin
;
1142 if(var
->sync
& FB_SYNC_HOR_HIGH_ACT
)
1143 par
->video
|= TDFXF_HSYNC_ACT_HIGH
;
1145 par
->video
|= TDFXF_HSYNC_ACT_LOW
;
1146 if(var
->sync
& FB_SYNC_VERT_HIGH_ACT
)
1147 par
->video
|= TDFXF_VSYNC_ACT_HIGH
;
1149 par
->video
|= TDFXF_VSYNC_ACT_LOW
;
1150 if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_DOUBLE
)
1151 par
->video
|= TDFXF_LINE_DOUBLE
;
1152 if(var
->activate
== FB_ACTIVATE_NOW
)
1153 par
->video
|= TDFXF_VIDEO_ENABLE
;
1156 if(var
->accel_flags
& FB_ACCELF_TEXT
)
1157 par
->accel_flags
= FB_ACCELF_TEXT
;
1159 par
->accel_flags
= 0;
1164 static int tdfxfb_encode_var(struct fb_var_screeninfo
* var
,
1165 const struct tdfxfb_par
* par
,
1166 const struct fb_info_tdfx
* info
) {
1167 struct fb_var_screeninfo v
;
1169 memset(&v
, 0, sizeof(struct fb_var_screeninfo
));
1170 v
.xres_virtual
= par
->width_virt
;
1171 v
.yres_virtual
= par
->height_virt
;
1172 v
.xres
= par
->width
;
1173 v
.yres
= par
->height
;
1174 v
.right_margin
= par
->hsyncsta
- par
->hdispend
;
1175 v
.hsync_len
= par
->hsyncend
- par
->hsyncsta
;
1176 v
.left_margin
= par
->htotal
- par
->hsyncend
;
1177 v
.lower_margin
= par
->vsyncsta
- par
->vdispend
;
1178 v
.vsync_len
= par
->vsyncend
- par
->vsyncsta
;
1179 v
.upper_margin
= par
->vtotal
- par
->vsyncend
;
1180 v
.bits_per_pixel
= par
->bpp
;
1183 v
.red
.length
= v
.green
.length
= v
.blue
.length
= 8;
1197 v
.red
.length
= v
.green
.length
= v
.blue
.length
= 8;
1200 v
.height
= v
.width
= -1;
1201 v
.pixclock
= KHZ2PICOS(par
->pixclock
);
1202 if((par
->video
& TDFXF_HSYNC_MASK
) == TDFXF_HSYNC_ACT_HIGH
)
1203 v
.sync
|= FB_SYNC_HOR_HIGH_ACT
;
1204 if((par
->video
& TDFXF_VSYNC_MASK
) == TDFXF_VSYNC_ACT_HIGH
)
1205 v
.sync
|= FB_SYNC_VERT_HIGH_ACT
;
1206 if(par
->video
& TDFXF_LINE_DOUBLE
)
1207 v
.vmode
= FB_VMODE_DOUBLE
;
1212 static int tdfxfb_open(struct fb_info
* info
,
1218 static int tdfxfb_release(struct fb_info
* info
,
1225 static int tdfxfb_encode_fix(struct fb_fix_screeninfo
* fix
,
1226 const struct tdfxfb_par
* par
,
1227 const struct fb_info_tdfx
* info
) {
1228 memset(fix
, 0, sizeof(struct fb_fix_screeninfo
));
1231 case PCI_DEVICE_ID_3DFX_BANSHEE
:
1232 case PCI_DEVICE_ID_3DFX_VOODOO3
:
1233 if (info
->dev
== PCI_DEVICE_ID_3DFX_BANSHEE
)
1234 strcpy(fix
->id
, "3Dfx Banshee");
1236 strcpy(fix
->id
, "3Dfx Voodoo3");
1237 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1238 fix
->smem_start
= (char*)info
->bufbase_phys
;
1239 fix
->smem_len
= info
->bufbase_size
;
1240 fix
->mmio_start
= (char*)info
->regbase_phys
;
1241 fix
->mmio_len
= info
->regbase_size
;
1243 fix
->smem_start
= info
->bufbase_phys
;
1244 fix
->smem_len
= info
->bufbase_size
;
1245 fix
->mmio_start
= info
->regbase_phys
;
1246 fix
->mmio_len
= info
->regbase_size
;
1248 fix
->accel
= FB_ACCEL_3DFX_BANSHEE
;
1249 fix
->type
= FB_TYPE_PACKED_PIXELS
;
1251 fix
->line_length
= par
->lpitch
;
1252 fix
->visual
= par
->bpp
== 8
1253 ? FB_VISUAL_PSEUDOCOLOR
1254 : FB_VISUAL_DIRECTCOLOR
;
1257 fix
->ypanstep
= (nowrap
&& nopan
) ? 0 : 1;
1258 fix
->ywrapstep
= nowrap
? 0 : 1;
1268 static int tdfxfb_get_fix(struct fb_fix_screeninfo
*fix
,
1270 struct fb_info
*fb
) {
1271 const struct fb_info_tdfx
*info
= (struct fb_info_tdfx
*)fb
;
1272 struct tdfxfb_par par
;
1275 par
= info
->default_par
;
1277 tdfxfb_decode_var(&fb_display
[con
].var
, &par
, info
);
1278 tdfxfb_encode_fix(fix
, &par
, info
);
1282 static int tdfxfb_get_var(struct fb_var_screeninfo
*var
,
1284 struct fb_info
*fb
) {
1285 const struct fb_info_tdfx
*info
= (struct fb_info_tdfx
*)fb
;
1288 tdfxfb_encode_var(var
, &info
->default_par
, info
);
1290 *var
= fb_display
[con
].var
;
1294 static void tdfxfb_set_disp(struct display
*disp
,
1295 struct fb_info_tdfx
*info
,
1298 DPRINTK("actually, %s using acceleration!\n",
1299 noaccel
? "NOT" : "");
1302 #ifdef FBCON_HAS_CFB8
1304 info
->dispsw
= noaccel
? fbcon_cfb8
: fbcon_banshee8
;
1305 disp
->dispsw
= &info
->dispsw
;
1308 #ifdef FBCON_HAS_CFB16
1310 info
->dispsw
= noaccel
? fbcon_cfb16
: fbcon_banshee16
;
1311 disp
->dispsw
= &info
->dispsw
;
1312 disp
->dispsw_data
= info
->fbcon_cmap
.cfb16
;
1315 #ifdef FBCON_HAS_CFB32
1317 info
->dispsw
= noaccel
? fbcon_cfb32
: fbcon_banshee32
;
1318 disp
->dispsw
= &info
->dispsw
;
1319 disp
->dispsw_data
= info
->fbcon_cmap
.cfb32
;
1323 info
->dispsw
= fbcon_dummy
;
1324 disp
->dispsw
= &info
->dispsw
;
1328 static int tdfxfb_set_var(struct fb_var_screeninfo
*var
,
1330 struct fb_info
*fb
) {
1331 struct fb_info_tdfx
*info
= (struct fb_info_tdfx
*)fb
;
1332 struct tdfxfb_par par
;
1333 struct display
*display
;
1334 int oldxres
, oldyres
, oldvxres
, oldvyres
, oldbpp
, oldaccel
, accel
, err
;
1335 int activate
= var
->activate
;
1338 display
= &fb_display
[con
];
1340 display
= fb
->disp
; /* used during initialization */
1342 if((err
= tdfxfb_decode_var(var
, &par
, info
)))
1345 tdfxfb_encode_var(var
, &par
, info
);
1347 if((activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) {
1348 oldxres
= display
->var
.xres
;
1349 oldyres
= display
->var
.yres
;
1350 oldvxres
= display
->var
.xres_virtual
;
1351 oldvyres
= display
->var
.yres_virtual
;
1352 oldbpp
= display
->var
.bits_per_pixel
;
1353 oldaccel
= display
->var
.accel_flags
;
1354 display
->var
= *var
;
1356 oldxres
!= var
->xres
||
1357 oldyres
!= var
->yres
||
1358 oldvxres
!= var
->xres_virtual
||
1359 oldvyres
!= var
->yres_virtual
||
1360 oldbpp
!= var
->bits_per_pixel
||
1361 oldaccel
!= var
->accel_flags
) {
1362 struct fb_fix_screeninfo fix
;
1364 tdfxfb_encode_fix(&fix
, &par
, info
);
1365 display
->screen_base
= (char *)info
->bufbase_virt
;
1366 display
->visual
= fix
.visual
;
1367 display
->type
= fix
.type
;
1368 display
->type_aux
= fix
.type_aux
;
1369 display
->ypanstep
= fix
.ypanstep
;
1370 display
->ywrapstep
= fix
.ywrapstep
;
1371 display
->line_length
= fix
.line_length
;
1372 display
->next_line
= fix
.line_length
;
1373 display
->can_soft_blank
= 1;
1374 display
->inverse
= inverse
;
1375 accel
= var
->accel_flags
& FB_ACCELF_TEXT
;
1376 tdfxfb_set_disp(display
, info
, par
.bpp
, accel
);
1378 if(nopan
&& nowrap
) {
1379 display
->scrollmode
= SCROLL_YREDRAW
;
1380 #ifdef FBCON_HAS_CFB8
1381 fbcon_banshee8
.bmove
= fbcon_redraw_bmove
;
1383 #ifdef FBCON_HAS_CFB16
1384 fbcon_banshee16
.bmove
= fbcon_redraw_bmove
;
1386 #ifdef FBCON_HAS_CFB32
1387 fbcon_banshee32
.bmove
= fbcon_redraw_bmove
;
1390 if (info
->fb_info
.changevar
)
1391 (*info
->fb_info
.changevar
)(con
);
1393 if(!info
->fb_info
.display_fg
||
1394 info
->fb_info
.display_fg
->vc_num
== con
||
1396 tdfxfb_set_par(&par
, info
);
1397 if(oldbpp
!= var
->bits_per_pixel
|| con
< 0) {
1398 if((err
= fb_alloc_cmap(&display
->cmap
, 0, 0)))
1400 tdfxfb_install_cmap(con
, &info
->fb_info
);
1407 static int tdfxfb_pan_display(struct fb_var_screeninfo
* var
,
1409 struct fb_info
* fb
) {
1410 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)fb
;
1413 if(nowrap
&& nopan
) {
1418 if(var
->yoffset
< 0)
1420 if(nopan
&& var
->yoffset
> var
->yres_virtual
)
1422 if(nowrap
&& var
->yoffset
+ var
->yres
> var
->yres_virtual
)
1425 i
->current_par
.baseline
= var
->yoffset
;
1427 addr
= var
->yoffset
*i
->current_par
.lpitch
;
1428 tdfx_outl(VIDDESKSTART
, addr
);
1429 tdfx_outl(SRCBASE
, addr
);
1430 tdfx_outl(DSTBASE
, addr
);
1435 static int tdfxfb_get_cmap(struct fb_cmap
*cmap
,
1438 struct fb_info
*fb
) {
1439 if(!fb
->display_fg
|| con
== fb
->display_fg
->vc_num
) {
1440 /* current console? */
1441 return fb_get_cmap(cmap
, kspc
, tdfxfb_getcolreg
, fb
);
1442 } else if(fb_display
[con
].cmap
.len
) {
1443 /* non default colormap? */
1444 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
1446 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
1447 fb_copy_cmap(fb_default_cmap(size
), cmap
, kspc
? 0 : 2);
1452 static int tdfxfb_set_cmap(struct fb_cmap
*cmap
,
1455 struct fb_info
*fb
) {
1457 struct display
*disp
;
1460 disp
= &fb_display
[con
];
1463 if(!disp
->cmap
.len
) { /* no colormap allocated? */
1464 int size
= disp
->var
.bits_per_pixel
== 16 ? 32 : 256;
1465 if((err
= fb_alloc_cmap(&disp
->cmap
, size
, 0)))
1468 if(!fb
->display_fg
|| con
== fb
->display_fg
->vc_num
) {
1469 /* current console? */
1470 return fb_set_cmap(cmap
, kspc
, tdfxfb_setcolreg
, fb
);
1472 fb_copy_cmap(cmap
, &disp
->cmap
, kspc
? 0 : 1);
1477 static int tdfxfb_ioctl(struct inode
*inode
,
1482 struct fb_info
*fb
) {
1486 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1487 __initfunc(void tdfxfb_init(void)) {
1489 int __init
tdfxfb_init(void) {
1491 struct pci_dev
*pdev
= NULL
;
1492 struct fb_var_screeninfo var
;
1495 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1496 if(!pcibios_present()) return;
1498 if(!pcibios_present()) return -ENXIO
;
1501 for(pdev
= pci_devices
; pdev
; pdev
= pdev
->next
) {
1502 if(((pdev
->class >> 16) == PCI_BASE_CLASS_DISPLAY
) &&
1503 (pdev
->vendor
== PCI_VENDOR_ID_3DFX
) &&
1504 ((pdev
->device
== PCI_DEVICE_ID_3DFX_BANSHEE
) ||
1505 (pdev
->device
== PCI_DEVICE_ID_3DFX_VOODOO3
))) {
1507 fb_info
.dev
= pdev
->device
;
1508 fb_info
.max_pixclock
=
1509 pdev
->device
== PCI_DEVICE_ID_3DFX_BANSHEE
1510 ? BANSHEE_MAX_PIXCLOCK
1511 : VOODOO3_MAX_PIXCLOCK
;
1513 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1514 fb_info
.regbase_phys
= pdev
->base_address
[0] & PCI_BASE_ADDRESS_MEM_MASK
;
1515 fb_info
.regbase_size
= 1 << 25;
1516 fb_info
.regbase_virt
=
1517 (__u32
)ioremap_nocache(fb_info
.regbase_phys
, 1 << 25);
1518 if(!fb_info
.regbase_virt
) {
1519 if (fb_info
.dev
== PCI_DEVICE_ID_3DFX_BANSHEE
)
1520 printk("fb: Can't remap Banshee register area.\n");
1522 printk("fb: Can't remap Voodoo3 register area.\n");
1526 fb_info
.bufbase_phys
= pdev
->base_address
[1] & PCI_BASE_ADDRESS_MEM_MASK
;
1527 if(!(fb_info
.bufbase_size
= tdfx_lfb_size())) {
1528 if (fb_info
.dev
== PCI_DEVICE_ID_3DFX_BANSHEE
)
1529 printk("fb: Can't count Banshee memory.\n");
1531 printk("fb: Can't count Voodoo3 memory.\n");
1532 iounmap((void*)fb_info
.regbase_virt
);
1535 fb_info
.bufbase_virt
=
1536 (__u32
)ioremap_nocache(fb_info
.bufbase_phys
, 1 << 25);
1537 if(!fb_info
.regbase_virt
) {
1538 if (fb_info
.dev
== PCI_DEVICE_ID_3DFX_BANSHEE
)
1539 printk("fb: Can't remap Banshee framebuffer.\n");
1541 printk("fb: Can't remap Voodoo3 framebuffer.\n");
1542 iounmap((void*)fb_info
.regbase_virt
);
1546 fb_info
.regbase_phys
= pdev
->resource
[0].start
;
1547 fb_info
.regbase_size
= 1 << 25;
1548 fb_info
.regbase_virt
=
1549 (__u32
)ioremap_nocache(fb_info
.regbase_phys
, 1 << 25);
1550 if(!fb_info
.regbase_virt
) {
1551 if (fb_info
.dev
== PCI_DEVICE_ID_3DFX_BANSHEE
)
1552 printk("fb: Can't remap Banshee register area.\n");
1554 printk("fb: Can't remap Voodoo3 register area.\n");
1558 fb_info
.bufbase_phys
= pdev
->resource
[1].start
;
1559 if(!(fb_info
.bufbase_size
= tdfx_lfb_size())) {
1560 iounmap((void*)fb_info
.regbase_virt
);
1561 if (fb_info
.dev
== PCI_DEVICE_ID_3DFX_BANSHEE
)
1562 printk("fb: Can't count Banshee memory.\n");
1564 printk("fb: Can't count Voodoo3 memory.\n");
1567 fb_info
.bufbase_virt
=
1568 (__u32
)ioremap_nocache(fb_info
.bufbase_phys
, 1 << 25);
1569 if(!fb_info
.regbase_virt
) {
1570 if (fb_info
.dev
== PCI_DEVICE_ID_3DFX_BANSHEE
)
1571 printk("fb: Can't remap Banshee framebuffer.\n");
1573 printk("fb: Can't remap Voodoo3 framebuffer.\n");
1574 iounmap((void*)fb_info
.regbase_virt
);
1579 if (fb_info
.dev
== PCI_DEVICE_ID_3DFX_BANSHEE
)
1580 printk("fb: Banshee memory = %ldK\n", fb_info
.bufbase_size
>> 10);
1582 printk("fb: Voodoo3 memory = %ldK\n", fb_info
.bufbase_size
>> 10);
1584 /* clear framebuffer memory */
1585 memset_io(fb_info
.bufbase_virt
, 0, fb_info
.bufbase_size
);
1587 if (fb_info
.dev
== PCI_DEVICE_ID_3DFX_BANSHEE
)
1588 strcpy(fb_info
.fb_info
.modename
, "3Dfx Banshee");
1590 strcpy(fb_info
.fb_info
.modename
, "3Dfx Voodoo3");
1591 fb_info
.fb_info
.changevar
= NULL
;
1592 fb_info
.fb_info
.node
= -1;
1593 fb_info
.fb_info
.fbops
= &tdfxfb_ops
;
1594 fb_info
.fb_info
.disp
= &fb_info
.disp
;
1595 strcpy(fb_info
.fb_info
.fontname
, fontname
);
1596 fb_info
.fb_info
.switch_con
= &tdfxfb_switch_con
;
1597 fb_info
.fb_info
.updatevar
= &tdfxfb_updatevar
;
1598 fb_info
.fb_info
.blank
= &tdfxfb_blank
;
1599 fb_info
.fb_info
.flags
= FBINFO_FLAG_DEFAULT
;
1601 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1602 var
= default_mode
[default_mode_index
< modes
1603 ? default_mode_index
1606 memset(&var
, 0, sizeof(var
));
1608 !fb_find_mode(&var
, &fb_info
.fb_info
, mode_option
, NULL
, 0, NULL
, 8))
1609 var
= default_mode
[0].var
;
1612 if(noaccel
) var
.accel_flags
&= ~FB_ACCELF_TEXT
;
1613 else var
.accel_flags
|= FB_ACCELF_TEXT
;
1615 if(tdfxfb_decode_var(&var
, &fb_info
.default_par
, &fb_info
)) {
1616 /* ugh -- can't use the mode from the mode db. (or command line),
1617 so try the default */
1620 "can't decode the supplied video mode, using default\n");
1622 var
= default_mode
[0].var
;
1623 if(noaccel
) var
.accel_flags
&= ~FB_ACCELF_TEXT
;
1624 else var
.accel_flags
|= FB_ACCELF_TEXT
;
1626 if(tdfxfb_decode_var(&var
, &fb_info
.default_par
, &fb_info
)) {
1627 printk("tdfxfb: can't decode default video mode\n");
1628 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1636 fb_info
.disp
.screen_base
= (void*)fb_info
.bufbase_virt
;
1637 fb_info
.disp
.visual
=
1638 var
.bits_per_pixel
== 8
1639 ? FB_VISUAL_PSEUDOCOLOR
1640 : FB_VISUAL_DIRECTCOLOR
;
1641 fb_info
.disp
.type
= FB_TYPE_PACKED_PIXELS
;
1642 fb_info
.disp
.type_aux
= 0;
1644 fb_info
.disp
.ypanstep
= (nowrap
&& nopan
) ? 0 : 1;
1645 fb_info
.disp
.ywrapstep
= nowrap
? 0 : 1;
1647 fb_info
.disp
.line_length
=
1648 fb_info
.disp
.next_line
=
1649 var
.xres
*(var
.bits_per_pixel
+ 7)/8;
1650 fb_info
.disp
.can_soft_blank
= 1;
1651 fb_info
.disp
.inverse
= inverse
;
1652 fb_info
.disp
.scrollmode
= SCROLL_YREDRAW
;
1653 fb_info
.disp
.var
= var
;
1654 tdfxfb_set_disp(&fb_info
.disp
, &fb_info
,
1658 for(j
= 0; j
< 16; j
++) {
1660 fb_info
.palette
[j
].red
= default_red
[k
];
1661 fb_info
.palette
[j
].green
= default_grn
[k
];
1662 fb_info
.palette
[j
].blue
= default_blu
[k
];
1665 if(tdfxfb_set_var(&var
, -1, &fb_info
.fb_info
)) {
1666 printk("tdfxfb: can't set default video mode\n");
1667 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1674 if(register_framebuffer(&fb_info
.fb_info
) < 0) {
1675 printk("tdfxfb: can't register framebuffer\n");
1676 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1683 printk("fb%d: %s frame buffer device\n",
1684 GET_FB_IDX(fb_info
.fb_info
.node
),
1685 fb_info
.fb_info
.modename
);
1689 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1697 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1704 void tdfxfb_setup(char *options
,
1708 if(!options
|| !*options
)
1711 for(this_opt
= strtok(options
, ",");
1713 this_opt
= strtok(NULL
, ",")) {
1714 if(!strcmp(this_opt
, "inverse")) {
1717 } else if(!strcmp(this_opt
, "noaccel")) {
1719 } else if(!strcmp(this_opt
, "nopan")) {
1721 } else if(!strcmp(this_opt
, "nowrap")) {
1723 } else if (!strncmp(this_opt
, "font:", 5)) {
1724 strncpy(fontname
, this_opt
+ 5, 40);
1726 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
1728 for(i
= 0; i
< modes
; i
++) {
1729 if(!strcmp(this_opt
, default_mode
[i
].name
)) {
1730 default_mode_index
= i
;
1734 mode_option
= this_opt
;
1740 static int tdfxfb_switch_con(int con
,
1741 struct fb_info
*fb
) {
1742 struct fb_info_tdfx
*info
= (struct fb_info_tdfx
*)fb
;
1743 struct tdfxfb_par par
;
1745 /* Do we have to save the colormap? */
1746 if(fb_display
[currcon
].cmap
.len
)
1747 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, tdfxfb_getcolreg
, fb
);
1751 tdfxfb_decode_var(&fb_display
[con
].var
, &par
, info
);
1752 tdfxfb_set_par(&par
, info
);
1753 tdfxfb_set_disp(&fb_display
[con
],
1756 par
.accel_flags
& FB_ACCELF_TEXT
);
1758 tdfxfb_install_cmap(con
, fb
);
1759 tdfxfb_updatevar(con
, fb
);
1764 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
1765 static void tdfxfb_blank(int blank
,
1766 struct fb_info
*fb
) {
1767 u32 dacmode
, state
= 0, vgablank
= 0;
1769 dacmode
= tdfx_inl(DACMODE
);
1772 case 0: /* Screen: On; HSync: On, VSync: On */
1776 case 1: /* Screen: Off; HSync: On, VSync: On */
1780 case 2: /* Screen: Off; HSync: On, VSync: Off */
1784 case 3: /* Screen: Off; HSync: Off, VSync: On */
1788 case 4: /* Screen: Off; HSync: Off, VSync: Off */
1789 state
= BIT(1) | BIT(3);
1794 dacmode
&= ~(BIT(1) | BIT(3));
1796 tdfx_outl(DACMODE
, dacmode
);
1798 vga_disable_video();
1805 static int tdfxfb_updatevar(int con
,
1806 struct fb_info
* fb
) {
1807 if(con
!= currcon
|| (nowrap
&& nopan
)) {
1810 struct fb_var_screeninfo
* var
= &fb_display
[currcon
].var
;
1811 return tdfxfb_pan_display(var
, con
, fb
);
1815 static int tdfxfb_getcolreg(unsigned regno
,
1820 struct fb_info
* fb
) {
1821 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)fb
;
1824 *red
= i
->palette
[regno
].red
<< 8 | i
->palette
[regno
].red
;
1825 *green
= i
->palette
[regno
].green
<< 8 | i
->palette
[regno
].green
;
1826 *blue
= i
->palette
[regno
].blue
<< 8 | i
->palette
[regno
].blue
;
1832 static int tdfxfb_setcolreg(unsigned regno
,
1837 struct fb_info
* info
) {
1838 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)info
;
1841 switch(i
->current_par
.bpp
) {
1842 #ifdef FBCON_HAS_CFB8
1846 #ifdef FBCON_HAS_CFB16
1848 i
->fbcon_cmap
.cfb16
[regno
] =
1849 (((u32
)red
& 0xf800) >> 0) |
1850 (((u32
)green
& 0xfc00) >> 5) |
1851 (((u32
)blue
& 0xf800) >> 11);
1854 #ifdef FBCON_HAS_CFB32
1856 i
->fbcon_cmap
.cfb32
[regno
] =
1857 (((u32
)red
& 0xff00) << 8) |
1858 (((u32
)green
& 0xff00) << 0) |
1859 (((u32
)blue
& 0xff00) >> 8);
1863 DPRINTK("bad depth %u\n", i
->current_par
.bpp
);
1868 i
->palette
[regno
].red
= red
>> 8;
1869 i
->palette
[regno
].green
= green
>> 8;
1870 i
->palette
[regno
].blue
= blue
>> 8;
1871 if(i
->current_par
.bpp
== 8) {
1872 vga_outb(DAC_IW
, (unsigned char)regno
);
1873 vga_outb(DAC_D
, (unsigned char)(red
>> 8));
1874 vga_outb(DAC_D
, (unsigned char)(green
>> 8));
1875 vga_outb(DAC_D
, (unsigned char)(blue
>> 8));
1881 static void tdfxfb_install_cmap(int con
,
1882 struct fb_info
* info
) {
1883 if(con
!= currcon
) return;
1884 if(fb_display
[con
].cmap
.len
) {
1885 fb_set_cmap(&fb_display
[con
].cmap
, 1, tdfxfb_setcolreg
, info
);
1887 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
1888 fb_set_cmap(fb_default_cmap(size
), 1, tdfxfb_setcolreg
, info
);