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: Tue Nov 2 21:19:47 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. Lots of additions
19 * (proper acceleration, 24 bpp, hardware cursor) and bug fixes by Attila
20 * Kesmarki. Thanks guys!
22 * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
23 * I do wish the next version is a bit more complete. Without the XF86
24 * patches I couldn't have gotten even this far... for instance, the
25 * extensions to the VGA register set go completely unmentioned in the
26 * spec! Also, lots of references are made to the 'SST core', but no
27 * spec is publicly available, AFAIK.
29 * The structure of this driver comes pretty much from the Permedia
30 * driver by Ilario Nardinocchi, which in turn is based on skeletonfb.
33 * - support for 16/32 bpp needs fixing (funky bootup penguin)
34 * - multihead support (basically need to support an array of fb_infos)
35 * - banshee and voodoo3 now supported -- any others? afaik, the original
36 * voodoo was a 3d-only card, so we won't consider that. what about
38 * - support other architectures (PPC, Alpha); does the fact that the VGA
39 * core can be accessed only thru I/O (not memory mapped) complicate
44 * 0.1.3 (released 1999-11-02) added Attila's panning support, code
45 * reorg, hwcursor address page size alignment
46 * (for mmaping both frame buffer and regs),
47 * and my changes to get rid of hardcoded
48 * VGA i/o register locations (uses PCI
49 * configuration info now)
50 * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and
52 * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga.
53 * 0.1.0 (released 1999-10-06) initial version
57 #include <linux/config.h>
58 #include <linux/module.h>
59 #include <linux/kernel.h>
60 #include <linux/errno.h>
61 #include <linux/string.h>
63 #include <linux/tty.h>
64 #include <linux/malloc.h>
65 #include <linux/vmalloc.h>
66 #include <linux/delay.h>
67 #include <linux/interrupt.h>
69 #include <linux/selection.h>
70 #include <linux/console.h>
71 #include <linux/init.h>
72 #include <linux/pci.h>
73 #include <linux/nvram.h>
75 #include <linux/vt_kern.h>
77 #include <linux/timer.h>
83 #include <video/fbcon.h>
84 #include <video/fbcon-cfb8.h>
85 #include <video/fbcon-cfb16.h>
86 #include <video/fbcon-cfb24.h>
87 #include <video/fbcon-cfb32.h>
89 #include <linux/spinlock.h>
91 /* membase0 register offsets */
94 #define SIPMONITOR 0x08
95 #define LFBMEMORYCONFIG 0x0c
96 #define MISCINIT0 0x10
97 #define MISCINIT1 0x14
98 #define DRAMINIT0 0x18
99 #define DRAMINIT1 0x1c
101 #define TMUGBEINIT 0x24
102 #define VGAINIT0 0x28
103 #define VGAINIT1 0x2c
104 #define DRAMCOMMAND 0x30
105 #define DRAMDATA 0x34
108 #define PLLCTRL0 0x40
109 #define PLLCTRL1 0x44
110 #define PLLCTRL2 0x48
114 #define RGBMAXDELTA 0x58
115 #define VIDPROCCFG 0x5c
116 #define HWCURPATADDR 0x60
117 #define HWCURLOC 0x64
120 #define VIDINFORMAT 0x70
121 #define VIDINSTATUS 0x74
122 #define VIDSERPARPORT 0x78
123 #define VIDINXDELTA 0x7c
124 #define VIDININITERR 0x80
125 #define VIDINYDELTA 0x84
126 #define VIDPIXBUFTHOLD 0x88
127 #define VIDCHRMIN 0x8c
128 #define VIDCHRMAX 0x90
129 #define VIDCURLIN 0x94
130 #define VIDSCREENSIZE 0x98
131 #define VIDOVRSTARTCRD 0x9c
132 #define VIDOVRENDCRD 0xa0
133 #define VIDOVRDUDX 0xa4
134 #define VIDOVRDUDXOFF 0xa8
135 #define VIDOVRDVDY 0xac
137 #define VIDOVRDVDYOFF 0xe0
138 #define VIDDESKSTART 0xe4
139 #define VIDDESKSTRIDE 0xe8
140 #define VIDINADDR0 0xec
141 #define VIDINADDR1 0xf0
142 #define VIDINADDR2 0xf4
143 #define VIDINSTRIDE 0xf8
144 #define VIDCUROVRSTART 0xfc
146 #define INTCTRL (0x00100000 + 0x04)
147 #define CLIP0MIN (0x00100000 + 0x08)
148 #define CLIP0MAX (0x00100000 + 0x0c)
149 #define DSTBASE (0x00100000 + 0x10)
150 #define DSTFORMAT (0x00100000 + 0x14)
151 #define SRCBASE (0x00100000 + 0x34)
152 #define COMMANDEXTRA_2D (0x00100000 + 0x38)
153 #define CLIP1MIN (0x00100000 + 0x4c)
154 #define CLIP1MAX (0x00100000 + 0x50)
155 #define SRCFORMAT (0x00100000 + 0x54)
156 #define SRCSIZE (0x00100000 + 0x58)
157 #define SRCXY (0x00100000 + 0x5c)
158 #define COLORBACK (0x00100000 + 0x60)
159 #define COLORFORE (0x00100000 + 0x64)
160 #define DSTSIZE (0x00100000 + 0x68)
161 #define DSTXY (0x00100000 + 0x6c)
162 #define COMMAND_2D (0x00100000 + 0x70)
163 #define LAUNCH_2D (0x00100000 + 0x80)
165 #define COMMAND_3D (0x00200000 + 0x120)
167 /* register bitfields (not all, only as needed) */
169 #define BIT(x) (1UL << (x))
171 /* COMMAND_2D reg. values */
172 #define ROP_COPY 0xcc // src
173 #define ROP_INVERT 0x55 // NOT dst
174 #define ROP_XOR 0x66 // src XOR dst
176 #define AUTOINC_DSTX BIT(10)
177 #define AUTOINC_DSTY BIT(11)
178 #define COMMAND_2D_FILLRECT 0x05
179 #define COMMAND_2D_S2S_BITBLT 0x01 // screen to screen
180 #define COMMAND_2D_H2S_BITBLT 0x03 // host to screen
183 #define COMMAND_3D_NOP 0x00
184 #define STATUS_RETRACE BIT(6)
185 #define STATUS_BUSY BIT(9)
186 #define MISCINIT1_CLUT_INV BIT(0)
187 #define MISCINIT1_2DBLOCK_DIS BIT(15)
188 #define DRAMINIT0_SGRAM_NUM BIT(26)
189 #define DRAMINIT0_SGRAM_TYPE BIT(27)
190 #define DRAMINIT1_MEM_SDRAM BIT(30)
191 #define VGAINIT0_VGA_DISABLE BIT(0)
192 #define VGAINIT0_EXT_TIMING BIT(1)
193 #define VGAINIT0_8BIT_DAC BIT(2)
194 #define VGAINIT0_EXT_ENABLE BIT(6)
195 #define VGAINIT0_WAKEUP_3C3 BIT(8)
196 #define VGAINIT0_LEGACY_DISABLE BIT(9)
197 #define VGAINIT0_ALT_READBACK BIT(10)
198 #define VGAINIT0_FAST_BLINK BIT(11)
199 #define VGAINIT0_EXTSHIFTOUT BIT(12)
200 #define VGAINIT0_DECODE_3C6 BIT(13)
201 #define VGAINIT0_SGRAM_HBLANK_DISABLE BIT(22)
202 #define VGAINIT1_MASK 0x1fffff
203 #define VIDCFG_VIDPROC_ENABLE BIT(0)
204 #define VIDCFG_CURS_X11 BIT(1)
205 #define VIDCFG_HALF_MODE BIT(4)
206 #define VIDCFG_DESK_ENABLE BIT(7)
207 #define VIDCFG_CLUT_BYPASS BIT(10)
208 #define VIDCFG_2X BIT(26)
209 #define VIDCFG_HWCURSOR_ENABLE BIT(27)
210 #define VIDCFG_PIXFMT_SHIFT 18
211 #define DACMODE_2X BIT(0)
213 /* VGA rubbish, need to change this for multihead support */
225 #ifndef FB_ACCEL_3DFX_BANSHEE
226 #define FB_ACCEL_3DFX_BANSHEE 31
229 #define TDFXF_HSYNC_ACT_HIGH 0x01
230 #define TDFXF_HSYNC_ACT_LOW 0x02
231 #define TDFXF_VSYNC_ACT_HIGH 0x04
232 #define TDFXF_VSYNC_ACT_LOW 0x08
233 #define TDFXF_LINE_DOUBLE 0x10
234 #define TDFXF_VIDEO_ENABLE 0x20
236 #define TDFXF_HSYNC_MASK 0x03
237 #define TDFXF_VSYNC_MASK 0x0c
239 //#define TDFXFB_DEBUG
241 #define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b)
243 #define DPRINTK(a,b...)
246 #define PICOS2KHZ(a) (1000000000UL/(a))
247 #define KHZ2PICOS(a) (1000000000UL/(a))
249 #define BANSHEE_MAX_PIXCLOCK 270000.0
250 #define VOODOO3_MAX_PIXCLOCK 300000.0
254 unsigned char att
[21];
255 unsigned char crt
[25];
256 unsigned char gra
[ 9];
257 unsigned char misc
[1];
258 unsigned char seq
[ 5];
260 /* Banshee extensions */
261 unsigned char ext
[2];
262 unsigned long vidcfg
;
263 unsigned long vidpll
;
264 unsigned long mempll
;
265 unsigned long gfxpll
;
266 unsigned long dacmode
;
267 unsigned long vgainit0
;
268 unsigned long vgainit1
;
269 unsigned long screensize
;
270 unsigned long stride
;
271 unsigned long cursloc
;
272 unsigned long curspataddr
;
273 unsigned long cursc0
;
274 unsigned long cursc1
;
275 unsigned long startaddr
;
276 unsigned long clip0min
;
277 unsigned long clip0max
;
278 unsigned long clip1min
;
279 unsigned long clip1max
;
280 unsigned long srcbase
;
281 unsigned long dstbase
;
293 u32 lpitch
; /* line pitch, in bytes */
294 u32 ppitch
; /* pixel pitch, in bits */
312 struct fb_info_tdfx
{
313 struct fb_info fb_info
;
318 unsigned long regbase_phys
;
320 unsigned long regbase_size
;
321 unsigned long bufbase_phys
;
323 unsigned long bufbase_size
;
324 unsigned long iobase
;
326 struct { unsigned red
, green
, blue
, pad
; } palette
[256];
327 struct tdfxfb_par default_par
;
328 struct tdfxfb_par current_par
;
330 #if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)
332 #ifdef FBCON_HAS_CFB16
335 #ifdef FBCON_HAS_CFB24
338 #ifdef FBCON_HAS_CFB32
348 unsigned long enable
,disable
;
349 unsigned long cursorimage
;
350 struct timer_list timer
;
360 * Frame buffer device API
362 static int tdfxfb_get_fix(struct fb_fix_screeninfo
* fix
,
365 static int tdfxfb_get_var(struct fb_var_screeninfo
* var
,
368 static int tdfxfb_set_var(struct fb_var_screeninfo
* var
,
371 static int tdfxfb_pan_display(struct fb_var_screeninfo
* var
,
374 static int tdfxfb_get_cmap(struct fb_cmap
*cmap
,
377 struct fb_info
* info
);
378 static int tdfxfb_set_cmap(struct fb_cmap
* cmap
,
381 struct fb_info
* info
);
382 static int tdfxfb_ioctl(struct inode
* inode
,
387 struct fb_info
* info
);
390 * Interface to the low level console driver
392 static int tdfxfb_switch_con(int con
,
394 static int tdfxfb_updatevar(int con
,
396 static void tdfxfb_blank(int blank
,
402 static void tdfxfb_set_par(const struct tdfxfb_par
* par
,
405 static int tdfxfb_decode_var(const struct fb_var_screeninfo
*var
,
406 struct tdfxfb_par
*par
,
407 const struct fb_info_tdfx
*info
);
408 static int tdfxfb_encode_var(struct fb_var_screeninfo
* var
,
409 const struct tdfxfb_par
* par
,
410 const struct fb_info_tdfx
* info
);
411 static int tdfxfb_encode_fix(struct fb_fix_screeninfo
* fix
,
412 const struct tdfxfb_par
* par
,
413 const struct fb_info_tdfx
* info
);
414 static void tdfxfb_set_dispsw(struct display
* disp
,
415 struct fb_info_tdfx
* info
,
418 static int tdfxfb_getcolreg(u_int regno
,
424 static int tdfxfb_setcolreg(u_int regno
,
430 static void tdfxfb_install_cmap(struct display
*d
,
431 struct fb_info
*info
);
433 static void tdfxfb_hwcursor_init(void);
434 static void tdfxfb_createcursorshape(struct display
* p
);
435 static void tdfxfb_createcursor(struct display
* p
);
438 * do_xxx: Hardware-specific functions
440 static void do_pan_var(struct fb_var_screeninfo
* var
, struct fb_info_tdfx
*i
);
441 static void do_flashcursor(unsigned long ptr
);
442 static void do_bitblt(u32 curx
, u32 cury
, u32 dstx
,u32 dsty
,
443 u32 width
, u32 height
,u32 stride
,u32 bpp
);
444 static void do_fillrect(u32 x
, u32 y
, u32 w
,u32 h
,
445 u32 color
,u32 stride
,u32 bpp
,u32 rop
);
446 static void do_putc(u32 fgx
, u32 bgx
,struct display
*p
,
447 int c
, int yy
,int xx
);
448 static void do_putcs(u32 fgx
, u32 bgx
,struct display
*p
,
449 const unsigned short *s
,int count
, int yy
,int xx
);
450 static u32
do_calc_pll(int freq
, int* freq_out
);
451 static void do_write_regs(struct banshee_reg
* reg
);
452 static unsigned long do_lfb_size(void);
455 * Interface used by the world
457 int tdfxfb_init(void);
458 void tdfxfb_setup(char *options
,
461 static int currcon
= 0;
463 static struct fb_ops tdfxfb_ops
= {
465 fb_get_fix
: tdfxfb_get_fix
,
466 fb_get_var
: tdfxfb_get_var
,
467 fb_set_var
: tdfxfb_set_var
,
468 fb_get_cmap
: tdfxfb_get_cmap
,
469 fb_set_cmap
: tdfxfb_set_cmap
,
470 fb_pan_display
: tdfxfb_pan_display
,
471 fb_ioctl
: tdfxfb_ioctl
,
476 struct fb_var_screeninfo var
;
479 /* 2.3.x kernels have a fb mode database, so supply only one backup default */
480 struct mode default_mode
[] = {
481 { "640x480-8@60", /* @ 60 Hz */
483 640, 480, 640, 1024, 0, 0, 8, 0,
484 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
485 0, FB_ACTIVATE_NOW
, -1, -1, FB_ACCELF_TEXT
,
486 39722, 40, 24, 32, 11, 96, 2,
487 0, FB_VMODE_NONINTERLACED
492 static struct fb_info_tdfx fb_info
;
494 static int noaccel
= 0;
495 static int nopan
= 0;
496 static int nowrap
= 1; // not implemented (yet)
497 static int inverse
= 0;
499 static int nomtrr
= 0;
501 static int nohwcursor
= 0;
502 static char __initdata fontname
[40] = { 0 };
503 static const char *mode_option __initdata
= NULL
;
505 /* -------------------------------------------------------------------------
506 * Hardware-specific funcions
507 * ------------------------------------------------------------------------- */
510 static inline u8
vga_inb(u32 reg
) { return inb(reg
); }
511 static inline u16
vga_inw(u32 reg
) { return inw(reg
); }
512 static inline u16
vga_inl(u32 reg
) { return inl(reg
); }
514 static inline void vga_outb(u32 reg
, u8 val
) { outb(val
, reg
); }
515 static inline void vga_outw(u32 reg
, u16 val
) { outw(val
, reg
); }
516 static inline void vga_outl(u32 reg
, u32 val
) { outl(val
, reg
); }
518 static inline u8
vga_inb(u32 reg
) {
519 return inb(fb_info
.iobase
+ reg
- 0x300);
521 static inline u16
vga_inw(u32 reg
) {
522 return inw(fb_info
.iobase
+ reg
- 0x300);
524 static inline u16
vga_inl(u32 reg
) {
525 return inl(fb_info
.iobase
+ reg
- 0x300);
528 static inline void vga_outb(u32 reg
, u8 val
) {
529 outb(val
, fb_info
.iobase
+ reg
- 0x300);
531 static inline void vga_outw(u32 reg
, u16 val
) {
532 outw(val
, fb_info
.iobase
+ reg
- 0x300);
534 static inline void vga_outl(u32 reg
, u32 val
) {
535 outl(val
, fb_info
.iobase
+ reg
- 0x300);
539 static inline void gra_outb(u32 idx
, u8 val
) {
540 vga_outb(GRA_I
, idx
); vga_outb(GRA_D
, val
);
543 static inline u8
gra_inb(u32 idx
) {
544 vga_outb(GRA_I
, idx
); return vga_inb(GRA_D
);
547 static inline void seq_outb(u32 idx
, u8 val
) {
548 vga_outb(SEQ_I
, idx
); vga_outb(SEQ_D
, val
);
551 static inline u8
seq_inb(u32 idx
) {
552 vga_outb(SEQ_I
, idx
); return vga_inb(SEQ_D
);
555 static inline void crt_outb(u32 idx
, u8 val
) {
556 vga_outb(CRT_I
, idx
); vga_outb(CRT_D
, val
);
559 static inline u8
crt_inb(u32 idx
) {
560 vga_outb(CRT_I
, idx
); return vga_inb(CRT_D
);
563 static inline void att_outb(u32 idx
, u8 val
) {
565 tmp
= vga_inb(IS1_R
);
566 vga_outb(ATT_IW
, idx
);
567 vga_outb(ATT_IW
, val
);
570 static inline u8
att_inb(u32 idx
) {
572 tmp
= vga_inb(IS1_R
);
573 vga_outb(ATT_IW
, idx
);
574 return vga_inb(ATT_IW
);
577 static inline void vga_disable_video(void) {
579 s
= seq_inb(0x01) | 0x20;
580 seq_outb(0x00, 0x01);
582 seq_outb(0x00, 0x03);
585 static inline void vga_enable_video(void) {
587 s
= seq_inb(0x01) & 0xdf;
588 seq_outb(0x00, 0x01);
590 seq_outb(0x00, 0x03);
593 static inline void vga_disable_palette(void) {
595 vga_outb(ATT_IW
, 0x00);
598 static inline void vga_enable_palette(void) {
600 vga_outb(ATT_IW
, 0x20);
603 static inline u32
tdfx_inl(unsigned int reg
) {
604 return readl(fb_info
.regbase_virt
+ reg
);
607 static inline void tdfx_outl(unsigned int reg
, u32 val
) {
608 writel(val
, fb_info
.regbase_virt
+ reg
);
611 static inline void banshee_make_room(int size
) {
612 while((tdfx_inl(STATUS
) & 0x1f) < size
);
615 static inline void banshee_wait_idle(void) {
618 banshee_make_room(1);
619 tdfx_outl(COMMAND_3D
, COMMAND_3D_NOP
);
622 i
= (tdfx_inl(STATUS
) & STATUS_BUSY
) ? 0 : i
+ 1;
627 * Set the color of a palette entry in 8bpp mode
629 static inline void do_setpalentry(unsigned regno
, u32 c
) {
630 banshee_make_room(2); tdfx_outl(DACADDR
, regno
); tdfx_outl(DACDATA
, c
); }
633 * Set the starting position of the visible screen to var->yoffset
635 static void do_pan_var(struct fb_var_screeninfo
* var
, struct fb_info_tdfx
*i
)
638 addr
= var
->yoffset
*i
->current_par
.lpitch
;
639 banshee_make_room(1);
640 tdfx_outl(VIDDESKSTART
, addr
);
644 * Invert the hardware cursor image (timerfunc)
646 static void do_flashcursor(unsigned long ptr
)
648 struct fb_info_tdfx
* i
=(struct fb_info_tdfx
*)ptr
;
649 spin_lock(&i
->DAClock
);
650 banshee_make_room(1);
651 tdfx_outl( VIDPROCCFG
, tdfx_inl(VIDPROCCFG
) ^ VIDCFG_HWCURSOR_ENABLE
);
652 i
->cursor
.timer
.expires
=jiffies
+HZ
/2;
653 add_timer(&i
->cursor
.timer
);
654 spin_unlock(&i
->DAClock
);
658 * FillRect 2D command (solidfill or invert (via ROP_XOR))
660 static void do_fillrect(u32 x
, u32 y
, u32 w
, u32 h
,
661 u32 color
, u32 stride
, u32 bpp
, u32 rop
) {
663 u32 fmt
= stride
| ((bpp
+((bpp
==8) ? 0 : 8)) << 13);
665 banshee_make_room(5);
666 tdfx_outl(DSTFORMAT
, fmt
);
667 tdfx_outl(COLORFORE
, color
);
668 tdfx_outl(COMMAND_2D
, COMMAND_2D_FILLRECT
| (rop
<< 24));
669 tdfx_outl(DSTSIZE
, w
| (h
<< 16));
670 tdfx_outl(LAUNCH_2D
, x
| (y
<< 16));
675 * Screen-to-Screen BitBlt 2D command (for the bmove fb op.)
678 static void do_bitblt(u32 curx
,
687 u32 blitcmd
= COMMAND_2D_S2S_BITBLT
| (ROP_COPY
<< 24);
688 u32 fmt
= stride
| ((bpp
+((bpp
==8) ? 0 : 8)) << 13);
703 banshee_make_room(6);
705 tdfx_outl(SRCFORMAT
, fmt
);
706 tdfx_outl(DSTFORMAT
, fmt
);
707 tdfx_outl(COMMAND_2D
, blitcmd
);
708 tdfx_outl(DSTSIZE
, width
| (height
<< 16));
709 tdfx_outl(DSTXY
, dstx
| (dsty
<< 16));
710 tdfx_outl(LAUNCH_2D
, curx
| (cury
<< 16));
714 static void do_putc(u32 fgx
, u32 bgx
,
716 int c
, int yy
,int xx
)
719 int stride
=fb_info
.current_par
.lpitch
;
720 u32 bpp
=fb_info
.current_par
.bpp
;
721 int fw
=(fontwidth(p
)+7)>>3;
722 u8
*chardata
=p
->fontdata
+(c
&p
->charmask
)*fontheight(p
)*fw
;
723 u32 fmt
= stride
| ((bpp
+((bpp
==8) ? 0 : 8)) << 13);
728 banshee_make_room(8+((fontheight(p
)*fw
+3)>>2) );
729 tdfx_outl(COLORFORE
, fgx
);
730 tdfx_outl(COLORBACK
, bgx
);
732 tdfx_outl(DSTXY
, xx
| (yy
<< 16));
733 tdfx_outl(COMMAND_2D
, COMMAND_2D_H2S_BITBLT
| (ROP_COPY
<< 24));
734 tdfx_outl(SRCFORMAT
, 0x400000);
735 tdfx_outl(DSTFORMAT
, fmt
);
736 tdfx_outl(DSTSIZE
, fontwidth(p
) | (fontheight(p
) << 16));
741 tdfx_outl(LAUNCH_2D
,*(u32
*)chardata
);
747 case 1: tdfx_outl(LAUNCH_2D
,*chardata
); break;
748 case 2: tdfx_outl(LAUNCH_2D
,*(u16
*)chardata
); break;
749 case 3: tdfx_outl(LAUNCH_2D
,*(u16
*)chardata
| ((chardata
[3]) << 24)); break;
754 tdfx_outl(LAUNCH_2D
,*(u32
*)chardata
);
758 if (i
) tdfx_outl(LAUNCH_2D
,*(u16
*)chardata
);
761 // Is there a font with width more that 16 pixels ?
762 for (i
=fontheight(p
);i
>0;i
--) {
763 tdfx_outl(LAUNCH_2D
,*(u32
*)chardata
);
771 static void do_putcs(u32 fgx
, u32 bgx
,
773 const unsigned short *s
,
774 int count
, int yy
,int xx
)
777 int stride
=fb_info
.current_par
.lpitch
;
778 u32 bpp
=fb_info
.current_par
.bpp
;
779 int fw
=(fontwidth(p
)+7)>>3;
782 int regsneed
=1+((h
*fw
+3)>>2);
783 u32 fmt
= stride
| ((bpp
+((bpp
==8) ? 0 : 8)) << 13);
787 banshee_make_room(8);
789 tdfx_outl(COMMAND_3D
, COMMAND_3D_NOP
);
790 tdfx_outl(COLORFORE
, fgx
);
791 tdfx_outl(COLORBACK
, bgx
);
792 tdfx_outl(SRCFORMAT
, 0x400000);
793 tdfx_outl(DSTFORMAT
, fmt
);
794 tdfx_outl(DSTSIZE
, w
| (h
<< 16));
796 tdfx_outl(COMMAND_2D
, COMMAND_2D_H2S_BITBLT
| (ROP_COPY
<< 24));
799 u8
*chardata
=p
->fontdata
+(scr_readw(s
++) & p
->charmask
)*h
*fw
;
801 banshee_make_room(regsneed
);
802 tdfx_outl(DSTXY
, xx
| yy
);
809 tdfx_outl(LAUNCH_2D
,*(u32
*)chardata
);
815 case 1: tdfx_outl(LAUNCH_2D
,*chardata
); break;
816 case 2: tdfx_outl(LAUNCH_2D
,*(u16
*)chardata
); break;
817 case 3: tdfx_outl(LAUNCH_2D
,*(u16
*)chardata
| ((chardata
[3]) << 24)); break;
822 tdfx_outl(LAUNCH_2D
,*(u32
*)chardata
);
826 if (i
) tdfx_outl(LAUNCH_2D
,*(u16
*)chardata
);
829 // Is there a font with width more that 16 pixels ?
831 tdfx_outl(LAUNCH_2D
,*(u32
*)chardata
);
840 static u32
do_calc_pll(int freq
, int* freq_out
) {
841 int m
, n
, k
, best_m
, best_n
, best_k
, f_cur
, best_error
;
844 /* this really could be done with more intelligence --
845 255*63*4 = 64260 iterations is silly */
847 best_n
= best_m
= best_k
= 0;
848 for(n
= 1; n
< 256; n
++) {
849 for(m
= 1; m
< 64; m
++) {
850 for(k
= 0; k
< 4; k
++) {
851 f_cur
= fref
*(n
+ 2)/(m
+ 2)/(1 << k
);
852 if(abs(f_cur
- freq
) < best_error
) {
853 best_error
= abs(f_cur
-freq
);
864 *freq_out
= fref
*(n
+ 2)/(m
+ 2)/(1 << k
);
866 return (n
<< 8) | (m
<< 2) | k
;
869 static void do_write_regs(struct banshee_reg
* reg
) {
874 tdfx_outl(MISCINIT1
, tdfx_inl(MISCINIT1
) | 0x01);
876 crt_outb(0x11, crt_inb(0x11) & 0x7f); /* CRT unprotect */
878 banshee_make_room(3);
879 tdfx_outl(VGAINIT1
, reg
->vgainit1
& 0x001FFFFF);
880 tdfx_outl(VIDPROCCFG
, reg
->vidcfg
& ~0x00000001);
882 tdfx_outl(PLLCTRL1
, reg
->mempll
);
883 tdfx_outl(PLLCTRL2
, reg
->gfxpll
);
885 tdfx_outl(PLLCTRL0
, reg
->vidpll
);
887 vga_outb(MISC_W
, reg
->misc
[0x00] | 0x01);
889 for(i
= 0; i
< 5; i
++)
890 seq_outb(i
, reg
->seq
[i
]);
892 for(i
= 0; i
< 25; i
++)
893 crt_outb(i
, reg
->crt
[i
]);
895 for(i
= 0; i
< 9; i
++)
896 gra_outb(i
, reg
->gra
[i
]);
898 for(i
= 0; i
< 21; i
++)
899 att_outb(i
, reg
->att
[i
]);
901 crt_outb(0x1a, reg
->ext
[0]);
902 crt_outb(0x1b, reg
->ext
[1]);
904 vga_enable_palette();
907 banshee_make_room(11);
908 tdfx_outl(VGAINIT0
, reg
->vgainit0
);
909 tdfx_outl(DACMODE
, reg
->dacmode
);
910 tdfx_outl(VIDDESKSTRIDE
, reg
->stride
);
912 tdfx_outl(HWCURPATADDR
, 0);
914 tdfx_outl(HWCURPATADDR
, reg
->curspataddr
);
915 tdfx_outl(HWCURC0
, reg
->cursc0
);
916 tdfx_outl(HWCURC1
, reg
->cursc1
);
917 tdfx_outl(HWCURLOC
, reg
->cursloc
);
920 tdfx_outl(VIDSCREENSIZE
, reg
->screensize
);
921 tdfx_outl(VIDDESKSTART
, reg
->startaddr
);
922 tdfx_outl(VIDPROCCFG
, reg
->vidcfg
);
923 tdfx_outl(VGAINIT1
, reg
->vgainit1
);
925 banshee_make_room(8);
926 tdfx_outl(SRCBASE
, reg
->srcbase
);
927 tdfx_outl(DSTBASE
, reg
->dstbase
);
928 tdfx_outl(COMMANDEXTRA_2D
, 0);
929 tdfx_outl(CLIP0MIN
, 0);
930 tdfx_outl(CLIP0MAX
, 0x0fff0fff);
931 tdfx_outl(CLIP1MIN
, 0);
932 tdfx_outl(CLIP1MAX
, 0x0fff0fff);
938 static unsigned long do_lfb_size(void) {
945 if(!((fb_info
.dev
== PCI_DEVICE_ID_3DFX_BANSHEE
) ||
946 (fb_info
.dev
== PCI_DEVICE_ID_3DFX_VOODOO3
)))
949 draminit0
= tdfx_inl(DRAMINIT0
);
950 draminit1
= tdfx_inl(DRAMINIT1
);
952 sgram_p
= (draminit1
& DRAMINIT1_MEM_SDRAM
) ? 0 : 1;
955 (((draminit0
& DRAMINIT0_SGRAM_NUM
) ? 2 : 1) *
956 ((draminit0
& DRAMINIT0_SGRAM_TYPE
) ? 8 : 4) * 1024 * 1024) :
959 /* disable block writes for SDRAM (why?) */
960 miscinit1
= tdfx_inl(MISCINIT1
);
961 miscinit1
|= sgram_p
? 0 : MISCINIT1_2DBLOCK_DIS
;
962 miscinit1
|= MISCINIT1_CLUT_INV
;
964 banshee_make_room(1);
965 tdfx_outl(MISCINIT1
, miscinit1
);
970 /* -------------------------------------------------------------------------
971 * Hardware independent part, interface to the world
972 * ------------------------------------------------------------------------- */
974 #define tdfx_cfb24_putc tdfx_cfb32_putc
975 #define tdfx_cfb24_putcs tdfx_cfb32_putcs
976 #define tdfx_cfb24_clear tdfx_cfb32_clear
978 static void tdfx_cfbX_clear_margins(struct vc_data
* conp
, struct display
* p
,
981 unsigned int cw
=fontwidth(p
);
982 unsigned int ch
=fontheight(p
);
983 unsigned int rw
=p
->var
.xres
% cw
; // it be in a non-standard mode or not?
984 unsigned int bh
=p
->var
.yres
% ch
;
985 unsigned int rs
=p
->var
.xres
- rw
;
986 unsigned int bs
=p
->var
.yres
- bh
;
988 if (!bottom_only
&& rw
) {
989 do_fillrect( p
->var
.xoffset
+rs
, 0,
990 rw
, p
->var
.yres_virtual
, 0,
991 fb_info
.current_par
.lpitch
,
992 fb_info
.current_par
.bpp
, ROP_COPY
);
996 do_fillrect( p
->var
.xoffset
, p
->var
.yoffset
+bs
,
998 fb_info
.current_par
.lpitch
,
999 fb_info
.current_par
.bpp
, ROP_COPY
);
1002 static void tdfx_cfbX_bmove(struct display
* p
,
1009 do_bitblt(fontwidth(p
)*sx
,
1014 fontheight(p
)*height
,
1015 fb_info
.current_par
.lpitch
,
1016 fb_info
.current_par
.bpp
);
1018 static void tdfx_cfb8_putc(struct vc_data
* conp
,
1020 int c
, int yy
,int xx
)
1023 fgx
=attr_fgcol(p
, c
);
1024 bgx
=attr_bgcol(p
, c
);
1025 do_putc( fgx
,bgx
,p
,c
,yy
,xx
);
1028 static void tdfx_cfb16_putc(struct vc_data
* conp
,
1030 int c
, int yy
,int xx
)
1033 fgx
=((u16
*)p
->dispsw_data
)[attr_fgcol(p
,c
)];
1034 bgx
=((u16
*)p
->dispsw_data
)[attr_bgcol(p
,c
)];
1035 do_putc( fgx
,bgx
,p
,c
,yy
,xx
);
1038 static void tdfx_cfb32_putc(struct vc_data
* conp
,
1040 int c
, int yy
,int xx
)
1043 fgx
=((u32
*)p
->dispsw_data
)[attr_fgcol(p
,c
)];
1044 bgx
=((u32
*)p
->dispsw_data
)[attr_bgcol(p
,c
)];
1045 do_putc( fgx
,bgx
,p
,c
,yy
,xx
);
1047 static void tdfx_cfb8_putcs(struct vc_data
* conp
,
1049 const unsigned short *s
,int count
,int yy
,int xx
)
1052 fgx
=attr_fgcol(p
, *s
);
1053 bgx
=attr_bgcol(p
, *s
);
1054 do_putcs( fgx
,bgx
,p
,s
,count
,yy
,xx
);
1056 static void tdfx_cfb16_putcs(struct vc_data
* conp
,
1058 const unsigned short *s
,int count
,int yy
,int xx
)
1061 fgx
=((u16
*)p
->dispsw_data
)[attr_fgcol(p
,*s
)];
1062 bgx
=((u16
*)p
->dispsw_data
)[attr_bgcol(p
,*s
)];
1063 do_putcs( fgx
,bgx
,p
,s
,count
,yy
,xx
);
1065 static void tdfx_cfb32_putcs(struct vc_data
* conp
,
1067 const unsigned short *s
,int count
,int yy
,int xx
)
1070 fgx
=((u32
*)p
->dispsw_data
)[attr_fgcol(p
,*s
)];
1071 bgx
=((u32
*)p
->dispsw_data
)[attr_bgcol(p
,*s
)];
1072 do_putcs( fgx
,bgx
,p
,s
,count
,yy
,xx
);
1075 static void tdfx_cfb8_clear(struct vc_data
* conp
,
1083 bg
= attr_bgcol_ec(p
,conp
);
1084 do_fillrect(fontwidth(p
)*sx
,
1087 fontheight(p
)*height
,
1089 fb_info
.current_par
.lpitch
,
1090 fb_info
.current_par
.bpp
,ROP_COPY
);
1093 static void tdfx_cfb16_clear(struct vc_data
* conp
,
1101 bg
= ((u16
*)p
->dispsw_data
)[attr_bgcol_ec(p
,conp
)];
1102 do_fillrect(fontwidth(p
)*sx
,
1105 fontheight(p
)*height
,
1107 fb_info
.current_par
.lpitch
,
1108 fb_info
.current_par
.bpp
,ROP_COPY
);
1111 static void tdfx_cfb32_clear(struct vc_data
* conp
,
1119 bg
= ((u32
*)p
->dispsw_data
)[attr_bgcol_ec(p
,conp
)];
1120 do_fillrect(fontwidth(p
)*sx
,
1123 fontheight(p
)*height
,
1125 fb_info
.current_par
.lpitch
,
1126 fb_info
.current_par
.bpp
,ROP_COPY
);
1128 static void tdfx_cfbX_revc(struct display
*p
, int xx
, int yy
)
1130 int bpp
=fb_info
.current_par
.bpp
;
1132 do_fillrect( xx
* fontwidth(p
), yy
* fontheight(p
),
1133 fontwidth(p
), fontheight(p
),
1134 (bpp
==8) ? 0x0f : 0xffffffff,
1135 fb_info
.current_par
.lpitch
, bpp
, ROP_XOR
);
1138 static void tdfx_cfbX_cursor(struct display
*p
, int mode
, int x
, int y
)
1140 unsigned long flags
;
1142 struct fb_info_tdfx
*info
=(struct fb_info_tdfx
*)p
->fb_info
;
1144 tip
=p
->conp
->vc_cursor_type
& CUR_HWMASK
;
1145 if (mode
==CM_ERASE
) {
1146 if (info
->cursor
.state
!= CM_ERASE
) {
1147 spin_lock_irqsave(&info
->DAClock
,flags
);
1148 info
->cursor
.state
=CM_ERASE
;
1149 del_timer(&(info
->cursor
.timer
));
1150 tdfx_outl(VIDPROCCFG
,info
->cursor
.disable
);
1151 spin_unlock_irqrestore(&info
->DAClock
,flags
);
1155 if ((p
->conp
->vc_cursor_type
& CUR_HWMASK
) != info
->cursor
.type
)
1156 tdfxfb_createcursor(p
);
1159 y
-= p
->var
.yoffset
;
1160 spin_lock_irqsave(&info
->DAClock
,flags
);
1161 if ((x
!=info
->cursor
.x
) ||
1162 (y
!=info
->cursor
.y
) ||
1163 (info
->cursor
.redraw
)) {
1166 info
->cursor
.redraw
=0;
1169 banshee_make_room(2);
1170 tdfx_outl(VIDPROCCFG
, info
->cursor
.disable
);
1171 tdfx_outl(HWCURLOC
, (y
<< 16) + x
);
1172 /* fix cursor color - XFree86 forgets to restore it properly */
1173 tdfx_outl(HWCURC0
, 0);
1174 tdfx_outl(HWCURC1
, 0xffffff);
1176 info
->cursor
.state
= CM_DRAW
;
1177 mod_timer(&info
->cursor
.timer
,jiffies
+HZ
/2);
1178 banshee_make_room(1);
1179 tdfx_outl(VIDPROCCFG
, info
->cursor
.enable
);
1180 spin_unlock_irqrestore(&info
->DAClock
,flags
);
1183 #ifdef FBCON_HAS_CFB8
1184 static struct display_switch fbcon_banshee8
= {
1185 setup
: fbcon_cfb8_setup
,
1186 bmove
: tdfx_cfbX_bmove
,
1187 clear
: tdfx_cfb8_clear
,
1188 putc
: tdfx_cfb8_putc
,
1189 putcs
: tdfx_cfb8_putcs
,
1190 revc
: tdfx_cfbX_revc
,
1191 cursor
: tdfx_cfbX_cursor
,
1192 clear_margins
: tdfx_cfbX_clear_margins
,
1193 fontwidthmask
: FONTWIDTH(8)
1196 #ifdef FBCON_HAS_CFB16
1197 static struct display_switch fbcon_banshee16
= {
1198 setup
: fbcon_cfb16_setup
,
1199 bmove
: tdfx_cfbX_bmove
,
1200 clear
: tdfx_cfb16_clear
,
1201 putc
: tdfx_cfb16_putc
,
1202 putcs
: tdfx_cfb16_putcs
,
1203 revc
: tdfx_cfbX_revc
,
1204 cursor
: tdfx_cfbX_cursor
,
1205 clear_margins
: tdfx_cfbX_clear_margins
,
1206 fontwidthmask
: FONTWIDTH(8)
1209 #ifdef FBCON_HAS_CFB24
1210 static struct display_switch fbcon_banshee24
= {
1211 setup
: fbcon_cfb24_setup
,
1212 bmove
: tdfx_cfbX_bmove
,
1213 clear
: tdfx_cfb24_clear
,
1214 putc
: tdfx_cfb24_putc
,
1215 putcs
: tdfx_cfb24_putcs
,
1216 revc
: tdfx_cfbX_revc
,
1217 cursor
: tdfx_cfbX_cursor
,
1218 clear_margins
: tdfx_cfbX_clear_margins
,
1219 fontwidthmask
: FONTWIDTH(8)
1222 #ifdef FBCON_HAS_CFB32
1223 static struct display_switch fbcon_banshee32
= {
1224 setup
: fbcon_cfb32_setup
,
1225 bmove
: tdfx_cfbX_bmove
,
1226 clear
: tdfx_cfb32_clear
,
1227 putc
: tdfx_cfb32_putc
,
1228 putcs
: tdfx_cfb32_putcs
,
1229 revc
: tdfx_cfbX_revc
,
1230 cursor
: tdfx_cfbX_cursor
,
1231 clear_margins
: tdfx_cfbX_clear_margins
,
1232 fontwidthmask
: FONTWIDTH(8)
1236 /* ------------------------------------------------------------------------- */
1238 static void tdfxfb_set_par(const struct tdfxfb_par
* par
,
1239 struct fb_info_tdfx
* info
) {
1240 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)info
;
1241 struct banshee_reg reg
;
1243 u32 hd
, hs
, he
, ht
, hbs
, hbe
;
1244 u32 vd
, vs
, ve
, vt
, vbs
, vbe
;
1249 memset(®
, 0, sizeof(reg
));
1251 cpp
= (par
->bpp
+ 7)/8;
1253 wd
= (par
->hdispend
>> 3) - 1;
1255 hd
= (par
->hdispend
>> 3) - 1;
1256 hs
= (par
->hsyncsta
>> 3) - 1;
1257 he
= (par
->hsyncend
>> 3) - 1;
1258 ht
= (par
->htotal
>> 3) - 1;
1262 vd
= par
->vdispend
- 1;
1263 vs
= par
->vsyncsta
- 1;
1264 ve
= par
->vsyncend
- 1;
1265 vt
= par
->vtotal
- 2;
1269 /* this is all pretty standard VGA register stuffing */
1272 (par
->hdispend
< 400 ? 0xa0 :
1273 par
->hdispend
< 480 ? 0x60 :
1274 par
->hdispend
< 768 ? 0xe0 : 0x20);
1276 reg
.gra
[0x00] = 0x00;
1277 reg
.gra
[0x01] = 0x00;
1278 reg
.gra
[0x02] = 0x00;
1279 reg
.gra
[0x03] = 0x00;
1280 reg
.gra
[0x04] = 0x00;
1281 reg
.gra
[0x05] = 0x40;
1282 reg
.gra
[0x06] = 0x05;
1283 reg
.gra
[0x07] = 0x0f;
1284 reg
.gra
[0x08] = 0xff;
1286 reg
.att
[0x00] = 0x00;
1287 reg
.att
[0x01] = 0x01;
1288 reg
.att
[0x02] = 0x02;
1289 reg
.att
[0x03] = 0x03;
1290 reg
.att
[0x04] = 0x04;
1291 reg
.att
[0x05] = 0x05;
1292 reg
.att
[0x06] = 0x06;
1293 reg
.att
[0x07] = 0x07;
1294 reg
.att
[0x08] = 0x08;
1295 reg
.att
[0x09] = 0x09;
1296 reg
.att
[0x0a] = 0x0a;
1297 reg
.att
[0x0b] = 0x0b;
1298 reg
.att
[0x0c] = 0x0c;
1299 reg
.att
[0x0d] = 0x0d;
1300 reg
.att
[0x0e] = 0x0e;
1301 reg
.att
[0x0f] = 0x0f;
1302 reg
.att
[0x10] = 0x41;
1303 reg
.att
[0x11] = 0x00;
1304 reg
.att
[0x12] = 0x0f;
1305 reg
.att
[0x13] = 0x00;
1306 reg
.att
[0x14] = 0x00;
1308 reg
.seq
[0x00] = 0x03;
1309 reg
.seq
[0x01] = 0x01; /* fixme: clkdiv2? */
1310 reg
.seq
[0x02] = 0x0f;
1311 reg
.seq
[0x03] = 0x00;
1312 reg
.seq
[0x04] = 0x0e;
1314 reg
.crt
[0x00] = ht
- 4;
1316 reg
.crt
[0x02] = hbs
;
1317 reg
.crt
[0x03] = 0x80 | (hbe
& 0x1f);
1320 ((hbe
& 0x20) << 2) |
1324 ((vs
& 0x200) >> 2) |
1325 ((vd
& 0x200) >> 3) |
1326 ((vt
& 0x200) >> 4) |
1328 ((vbs
& 0x100) >> 5) |
1329 ((vs
& 0x100) >> 6) |
1330 ((vd
& 0x100) >> 7) |
1331 ((vt
& 0x100) >> 8);
1332 reg
.crt
[0x08] = 0x00;
1335 ((vbs
& 0x200) >> 4);
1336 reg
.crt
[0x0a] = 0x00;
1337 reg
.crt
[0x0b] = 0x00;
1338 reg
.crt
[0x0c] = 0x00;
1339 reg
.crt
[0x0d] = 0x00;
1340 reg
.crt
[0x0e] = 0x00;
1341 reg
.crt
[0x0f] = 0x00;
1348 reg
.crt
[0x14] = 0x00;
1349 reg
.crt
[0x15] = vbs
;
1350 reg
.crt
[0x16] = vbe
+ 1;
1351 reg
.crt
[0x17] = 0xc3;
1352 reg
.crt
[0x18] = 0xff;
1354 /* Banshee's nonvga stuff */
1355 reg
.ext
[0x00] = (((ht
& 0x100) >> 8) |
1356 ((hd
& 0x100) >> 6) |
1357 ((hbs
& 0x100) >> 4) |
1358 ((hbe
& 0x40) >> 1) |
1359 ((hs
& 0x100) >> 2) |
1360 ((he
& 0x20) << 2));
1361 reg
.ext
[0x01] = (((vt
& 0x400) >> 10) |
1362 ((vd
& 0x400) >> 8) |
1363 ((vbs
& 0x400) >> 6) |
1364 ((vbe
& 0x400) >> 4));
1368 VGAINIT0_EXT_ENABLE
|
1369 VGAINIT0_WAKEUP_3C3
|
1370 VGAINIT0_ALT_READBACK
|
1371 VGAINIT0_EXTSHIFTOUT
;
1372 reg
.vgainit1
= tdfx_inl(VGAINIT1
) & 0x1fffff;
1375 VIDCFG_VIDPROC_ENABLE
|
1376 VIDCFG_DESK_ENABLE
|
1378 ((cpp
- 1) << VIDCFG_PIXFMT_SHIFT
) |
1379 (cpp
!= 1 ? VIDCFG_CLUT_BYPASS
: 0);
1381 fb_info
.cursor
.enable
=reg
.vidcfg
| VIDCFG_HWCURSOR_ENABLE
;
1382 fb_info
.cursor
.disable
=reg
.vidcfg
;
1384 reg
.stride
= par
->width
*cpp
;
1388 reg
.cursc1
= 0xffffff;
1390 reg
.curspataddr
= fb_info
.cursor
.cursorimage
;
1392 reg
.startaddr
= par
->baseline
*reg
.stride
;
1393 reg
.srcbase
= reg
.startaddr
;
1394 reg
.dstbase
= reg
.startaddr
;
1397 freq
= par
->pixclock
;
1399 reg
.dacmode
&= ~DACMODE_2X
;
1400 reg
.vidcfg
&= ~VIDCFG_2X
;
1401 if(freq
> i
->max_pixclock
/2) {
1402 freq
= freq
> i
->max_pixclock
? i
->max_pixclock
: freq
;
1403 reg
.dacmode
|= DACMODE_2X
;
1404 reg
.vidcfg
|= VIDCFG_2X
;
1406 reg
.vidpll
= do_calc_pll(freq
, &fout
);
1408 reg
.mempll
= do_calc_pll(..., &fout
);
1409 reg
.gfxpll
= do_calc_pll(..., &fout
);
1412 reg
.screensize
= par
->width
| (par
->height
<< 12);
1413 reg
.vidcfg
&= ~VIDCFG_HALF_MODE
;
1415 do_write_regs(®
);
1417 i
->current_par
= *par
;
1421 static int tdfxfb_decode_var(const struct fb_var_screeninfo
* var
,
1422 struct tdfxfb_par
* par
,
1423 const struct fb_info_tdfx
* info
) {
1424 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)info
;
1426 if(var
->bits_per_pixel
!= 8 &&
1427 var
->bits_per_pixel
!= 16 &&
1428 var
->bits_per_pixel
!= 24 &&
1429 var
->bits_per_pixel
!= 32) {
1430 DPRINTK("depth not supported: %u\n", var
->bits_per_pixel
);
1434 if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_INTERLACED
) {
1435 DPRINTK("interlace not supported\n");
1440 DPRINTK("xoffset not supported\n");
1444 if(var
->xres
!= var
->xres_virtual
) {
1445 DPRINTK("virtual x resolution != physical x resolution not supported\n");
1449 if(var
->yres
> var
->yres_virtual
) {
1450 DPRINTK("virtual y resolution < physical y resolution not possible\n");
1454 /* fixme: does Voodoo3 support interlace? Banshee doesn't */
1455 if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_INTERLACED
) {
1456 DPRINTK("interlace not supported\n");
1460 memset(par
, 0, sizeof(struct tdfxfb_par
));
1463 case PCI_DEVICE_ID_3DFX_BANSHEE
:
1464 case PCI_DEVICE_ID_3DFX_VOODOO3
:
1465 par
->width
= (var
->xres
+ 15) & ~15; /* could sometimes be 8 */
1466 par
->width_virt
= par
->width
;
1467 par
->height
= var
->yres
;
1468 par
->height_virt
= var
->yres_virtual
;
1469 par
->bpp
= var
->bits_per_pixel
;
1470 par
->ppitch
= var
->bits_per_pixel
;
1471 par
->lpitch
= par
->width
* ((par
->ppitch
+7)>>3);
1472 par
->cmap_len
= (par
->bpp
== 8) ? 256 : 16;
1476 if(par
->width
< 320 || par
->width
> 2048) {
1477 DPRINTK("width not supported: %u\n", par
->width
);
1480 if(par
->height
< 200 || par
->height
> 2048) {
1481 DPRINTK("height not supported: %u\n", par
->height
);
1484 if(par
->lpitch
*par
->height_virt
> i
->bufbase_size
) {
1485 DPRINTK("no memory for screen (%ux%ux%u)\n",
1486 par
->width
, par
->height_virt
, par
->bpp
);
1489 par
->pixclock
= PICOS2KHZ(var
->pixclock
);
1490 if(par
->pixclock
> i
->max_pixclock
) {
1491 DPRINTK("pixclock too high (%uKHz)\n", par
->pixclock
);
1495 par
->hdispend
= var
->xres
;
1496 par
->hsyncsta
= par
->hdispend
+ var
->right_margin
;
1497 par
->hsyncend
= par
->hsyncsta
+ var
->hsync_len
;
1498 par
->htotal
= par
->hsyncend
+ var
->left_margin
;
1500 par
->vdispend
= var
->yres
;
1501 par
->vsyncsta
= par
->vdispend
+ var
->lower_margin
;
1502 par
->vsyncend
= par
->vsyncsta
+ var
->vsync_len
;
1503 par
->vtotal
= par
->vsyncend
+ var
->upper_margin
;
1505 if(var
->sync
& FB_SYNC_HOR_HIGH_ACT
)
1506 par
->video
|= TDFXF_HSYNC_ACT_HIGH
;
1508 par
->video
|= TDFXF_HSYNC_ACT_LOW
;
1509 if(var
->sync
& FB_SYNC_VERT_HIGH_ACT
)
1510 par
->video
|= TDFXF_VSYNC_ACT_HIGH
;
1512 par
->video
|= TDFXF_VSYNC_ACT_LOW
;
1513 if((var
->vmode
& FB_VMODE_MASK
) == FB_VMODE_DOUBLE
)
1514 par
->video
|= TDFXF_LINE_DOUBLE
;
1515 if(var
->activate
== FB_ACTIVATE_NOW
)
1516 par
->video
|= TDFXF_VIDEO_ENABLE
;
1519 if(var
->accel_flags
& FB_ACCELF_TEXT
)
1520 par
->accel_flags
= FB_ACCELF_TEXT
;
1522 par
->accel_flags
= 0;
1527 static int tdfxfb_encode_var(struct fb_var_screeninfo
* var
,
1528 const struct tdfxfb_par
* par
,
1529 const struct fb_info_tdfx
* info
) {
1530 struct fb_var_screeninfo v
;
1532 memset(&v
, 0, sizeof(struct fb_var_screeninfo
));
1533 v
.xres_virtual
= par
->width_virt
;
1534 v
.yres_virtual
= par
->height_virt
;
1535 v
.xres
= par
->width
;
1536 v
.yres
= par
->height
;
1537 v
.right_margin
= par
->hsyncsta
- par
->hdispend
;
1538 v
.hsync_len
= par
->hsyncend
- par
->hsyncsta
;
1539 v
.left_margin
= par
->htotal
- par
->hsyncend
;
1540 v
.lower_margin
= par
->vsyncsta
- par
->vdispend
;
1541 v
.vsync_len
= par
->vsyncend
- par
->vsyncsta
;
1542 v
.upper_margin
= par
->vtotal
- par
->vsyncend
;
1543 v
.bits_per_pixel
= par
->bpp
;
1546 v
.red
.length
= v
.green
.length
= v
.blue
.length
= 8;
1560 v
.red
.length
= v
.green
.length
= v
.blue
.length
= 8;
1565 v
.red
.length
= v
.green
.length
= v
.blue
.length
= 8;
1568 v
.height
= v
.width
= -1;
1569 v
.pixclock
= KHZ2PICOS(par
->pixclock
);
1570 if((par
->video
& TDFXF_HSYNC_MASK
) == TDFXF_HSYNC_ACT_HIGH
)
1571 v
.sync
|= FB_SYNC_HOR_HIGH_ACT
;
1572 if((par
->video
& TDFXF_VSYNC_MASK
) == TDFXF_VSYNC_ACT_HIGH
)
1573 v
.sync
|= FB_SYNC_VERT_HIGH_ACT
;
1574 if(par
->video
& TDFXF_LINE_DOUBLE
)
1575 v
.vmode
= FB_VMODE_DOUBLE
;
1580 static int tdfxfb_encode_fix(struct fb_fix_screeninfo
* fix
,
1581 const struct tdfxfb_par
* par
,
1582 const struct fb_info_tdfx
* info
) {
1583 memset(fix
, 0, sizeof(struct fb_fix_screeninfo
));
1586 case PCI_DEVICE_ID_3DFX_BANSHEE
:
1587 case PCI_DEVICE_ID_3DFX_VOODOO3
:
1589 info
->dev
== PCI_DEVICE_ID_3DFX_BANSHEE
1592 fix
->smem_start
= info
->bufbase_phys
;
1593 fix
->smem_len
= info
->bufbase_size
;
1594 fix
->mmio_start
= info
->regbase_phys
;
1595 fix
->mmio_len
= info
->regbase_size
;
1596 fix
->accel
= FB_ACCEL_3DFX_BANSHEE
;
1597 fix
->type
= FB_TYPE_PACKED_PIXELS
;
1599 fix
->line_length
= par
->lpitch
;
1600 fix
->visual
= (par
->bpp
== 8)
1601 ? FB_VISUAL_PSEUDOCOLOR
1602 : FB_VISUAL_DIRECTCOLOR
;
1605 fix
->ypanstep
= nopan
? 0 : 1;
1606 fix
->ywrapstep
= nowrap
? 0 : 1;
1616 static int tdfxfb_get_fix(struct fb_fix_screeninfo
*fix
,
1618 struct fb_info
*fb
) {
1619 const struct fb_info_tdfx
*info
= (struct fb_info_tdfx
*)fb
;
1620 struct tdfxfb_par par
;
1623 par
= info
->default_par
;
1625 tdfxfb_decode_var(&fb_display
[con
].var
, &par
, info
);
1626 tdfxfb_encode_fix(fix
, &par
, info
);
1630 static int tdfxfb_get_var(struct fb_var_screeninfo
*var
,
1632 struct fb_info
*fb
) {
1633 const struct fb_info_tdfx
*info
= (struct fb_info_tdfx
*)fb
;
1636 tdfxfb_encode_var(var
, &info
->default_par
, info
);
1638 *var
= fb_display
[con
].var
;
1642 static void tdfxfb_set_dispsw(struct display
*disp
,
1643 struct fb_info_tdfx
*info
,
1647 if (disp
->dispsw
&& disp
->conp
)
1648 fb_con
.con_cursor(disp
->conp
, CM_ERASE
);
1650 #ifdef FBCON_HAS_CFB8
1652 disp
->dispsw
= noaccel
? &fbcon_cfb8
: &fbcon_banshee8
;
1653 if (nohwcursor
) fbcon_banshee8
.cursor
= NULL
;
1656 #ifdef FBCON_HAS_CFB16
1658 disp
->dispsw
= noaccel
? &fbcon_cfb16
: &fbcon_banshee16
;
1659 disp
->dispsw_data
= info
->fbcon_cmap
.cfb16
;
1660 if (nohwcursor
) fbcon_banshee16
.cursor
= NULL
;
1663 #ifdef FBCON_HAS_CFB24
1665 disp
->dispsw
= noaccel
? &fbcon_cfb24
: &fbcon_banshee24
;
1666 disp
->dispsw_data
= info
->fbcon_cmap
.cfb24
;
1667 if (nohwcursor
) fbcon_banshee24
.cursor
= NULL
;
1670 #ifdef FBCON_HAS_CFB32
1672 disp
->dispsw
= noaccel
? &fbcon_cfb32
: &fbcon_banshee32
;
1673 disp
->dispsw_data
= info
->fbcon_cmap
.cfb32
;
1674 if (nohwcursor
) fbcon_banshee32
.cursor
= NULL
;
1678 disp
->dispsw
= &fbcon_dummy
;
1683 static int tdfxfb_set_var(struct fb_var_screeninfo
*var
,
1685 struct fb_info
*fb
) {
1686 struct fb_info_tdfx
*info
= (struct fb_info_tdfx
*)fb
;
1687 struct tdfxfb_par par
;
1688 struct display
*display
;
1689 int oldxres
, oldyres
, oldvxres
, oldvyres
, oldbpp
, oldaccel
, accel
, err
;
1690 int activate
= var
->activate
;
1694 display
= &fb_display
[con
];
1696 display
= fb
->disp
; /* used during initialization */
1698 if((err
= tdfxfb_decode_var(var
, &par
, info
)))
1701 tdfxfb_encode_var(var
, &par
, info
);
1703 if((activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) {
1704 oldxres
= display
->var
.xres
;
1705 oldyres
= display
->var
.yres
;
1706 oldvxres
= display
->var
.xres_virtual
;
1707 oldvyres
= display
->var
.yres_virtual
;
1708 oldbpp
= display
->var
.bits_per_pixel
;
1709 oldaccel
= display
->var
.accel_flags
;
1710 display
->var
= *var
;
1712 oldxres
!= var
->xres
||
1713 oldyres
!= var
->yres
||
1714 oldvxres
!= var
->xres_virtual
||
1715 oldvyres
!= var
->yres_virtual
||
1716 oldbpp
!= var
->bits_per_pixel
||
1717 oldaccel
!= var
->accel_flags
) {
1718 struct fb_fix_screeninfo fix
;
1720 tdfxfb_encode_fix(&fix
, &par
, info
);
1721 display
->screen_base
= info
->bufbase_virt
;
1722 display
->visual
= fix
.visual
;
1723 display
->type
= fix
.type
;
1724 display
->type_aux
= fix
.type_aux
;
1725 display
->ypanstep
= fix
.ypanstep
;
1726 display
->ywrapstep
= fix
.ywrapstep
;
1727 display
->line_length
= fix
.line_length
;
1728 display
->next_line
= fix
.line_length
;
1729 display
->can_soft_blank
= 1;
1730 display
->inverse
= inverse
;
1731 accel
= var
->accel_flags
& FB_ACCELF_TEXT
;
1732 tdfxfb_set_dispsw(display
, info
, par
.bpp
, accel
);
1734 if(nopan
) display
->scrollmode
= SCROLL_YREDRAW
;
1736 if (info
->fb_info
.changevar
)
1737 (*info
->fb_info
.changevar
)(con
);
1739 if (var
->bits_per_pixel
==8)
1740 for(j
= 0; j
< 16; j
++) {
1742 fb_info
.palette
[j
].red
= default_red
[k
];
1743 fb_info
.palette
[j
].green
= default_grn
[k
];
1744 fb_info
.palette
[j
].blue
= default_blu
[k
];
1747 del_timer(&(info
->cursor
.timer
));
1748 fb_info
.cursor
.state
=CM_ERASE
;
1749 if(!info
->fb_info
.display_fg
||
1750 info
->fb_info
.display_fg
->vc_num
== con
||
1752 tdfxfb_set_par(&par
, info
);
1754 if (display
&& display
->conp
)
1755 tdfxfb_createcursor( display
);
1756 info
->cursor
.redraw
=1;
1757 if(oldbpp
!= var
->bits_per_pixel
|| con
< 0) {
1758 if((err
= fb_alloc_cmap(&display
->cmap
, 0, 0)))
1760 tdfxfb_install_cmap(display
, &(info
->fb_info
));
1767 static int tdfxfb_pan_display(struct fb_var_screeninfo
* var
,
1769 struct fb_info
* fb
) {
1770 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)fb
;
1772 if(nopan
) return -EINVAL
;
1773 if(var
->xoffset
) return -EINVAL
;
1774 if(var
->yoffset
> var
->yres_virtual
) return -EINVAL
;
1776 (var
->yoffset
+ var
->yres
> var
->yres_virtual
)) return -EINVAL
;
1781 fb_display
[con
].var
.xoffset
=var
->xoffset
;
1782 fb_display
[con
].var
.yoffset
=var
->yoffset
;
1786 static int tdfxfb_get_cmap(struct fb_cmap
*cmap
,
1789 struct fb_info
*fb
) {
1791 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)fb
;
1792 struct display
*d
=(con
<0) ? fb
->disp
: fb_display
+ con
;
1794 if(con
== currcon
) {
1795 /* current console? */
1796 return fb_get_cmap(cmap
, kspc
, tdfxfb_getcolreg
, fb
);
1797 } else if(d
->cmap
.len
) {
1798 /* non default colormap? */
1799 fb_copy_cmap(&d
->cmap
, cmap
, kspc
? 0 : 2);
1801 fb_copy_cmap(fb_default_cmap(i
->current_par
.cmap_len
), cmap
, kspc
? 0 : 2);
1806 static int tdfxfb_set_cmap(struct fb_cmap
*cmap
,
1809 struct fb_info
*fb
) {
1810 struct display
*d
=(con
<0) ? fb
->disp
: fb_display
+ con
;
1811 struct fb_info_tdfx
*i
= (struct fb_info_tdfx
*)fb
;
1813 int cmap_len
= (i
->current_par
.bpp
== 8) ? 256 : 16;
1814 if (d
->cmap
.len
!=cmap_len
) {
1816 if((err
= fb_alloc_cmap(&d
->cmap
, cmap_len
, 0)))
1819 if(con
== currcon
) {
1820 /* current console? */
1821 return fb_set_cmap(cmap
, kspc
, tdfxfb_setcolreg
, fb
);
1823 fb_copy_cmap(cmap
, &d
->cmap
, kspc
? 0 : 1);
1828 static int tdfxfb_ioctl(struct inode
*inode
,
1833 struct fb_info
*fb
) {
1834 /* These IOCTLs ar just for testing only...
1846 int __init
tdfxfb_init(void) {
1847 struct pci_dev
*pdev
= NULL
;
1848 struct fb_var_screeninfo var
;
1850 while ((pdev
= pci_find_device(PCI_VENDOR_ID_3DFX
, PCI_ANY_ID
, pdev
))) {
1851 if(((pdev
->class >> 16) == PCI_BASE_CLASS_DISPLAY
) &&
1852 ((pdev
->device
== PCI_DEVICE_ID_3DFX_BANSHEE
) ||
1853 (pdev
->device
== PCI_DEVICE_ID_3DFX_VOODOO3
))) {
1854 char* name
= pdev
->device
== PCI_DEVICE_ID_3DFX_BANSHEE
1858 fb_info
.dev
= pdev
->device
;
1859 fb_info
.max_pixclock
=
1860 pdev
->device
== PCI_DEVICE_ID_3DFX_BANSHEE
1861 ? BANSHEE_MAX_PIXCLOCK
1862 : VOODOO3_MAX_PIXCLOCK
;
1864 fb_info
.regbase_phys
= pci_resource_start(pdev
, 0);
1865 fb_info
.regbase_size
= 1 << 24;
1866 fb_info
.regbase_virt
= ioremap_nocache(fb_info
.regbase_phys
, 1 << 24);
1867 if(!fb_info
.regbase_virt
) {
1868 printk("fb: Can't remap %s register area.\n", name
);
1872 fb_info
.bufbase_phys
= pci_resource_start (pdev
, 1);
1873 if(!(fb_info
.bufbase_size
= do_lfb_size())) {
1874 iounmap(fb_info
.regbase_virt
);
1875 printk("fb: Can't count %s memory.\n", name
);
1878 fb_info
.bufbase_virt
= ioremap_nocache(fb_info
.bufbase_phys
, fb_info
.bufbase_size
);
1879 if(!fb_info
.regbase_virt
) {
1880 printk("fb: Can't remap %s framebuffer.\n", name
);
1881 iounmap(fb_info
.regbase_virt
);
1885 fb_info
.iobase
= pci_resource_start (pdev
, 2);
1887 printk("fb: %s memory = %ldK\n", name
, fb_info
.bufbase_size
>> 10);
1891 fb_info
.mtrr_idx
= mtrr_add(fb_info
.bufbase_phys
, fb_info
.bufbase_size
,
1892 MTRR_TYPE_WRCOMB
, 1);
1893 printk("fb: MTRR's turned on\n");
1897 /* clear framebuffer memory */
1898 memset_io(fb_info
.bufbase_virt
, 0, fb_info
.bufbase_size
);
1900 if (!nohwcursor
) tdfxfb_hwcursor_init();
1902 init_timer(&fb_info
.cursor
.timer
);
1903 fb_info
.cursor
.timer
.function
= do_flashcursor
;
1904 fb_info
.cursor
.timer
.data
= (unsigned long)(&fb_info
);
1905 fb_info
.cursor
.state
= CM_ERASE
;
1906 spin_lock_init(&fb_info
.DAClock
);
1908 strcpy(fb_info
.fb_info
.modename
, "3Dfx ");
1909 strcat(fb_info
.fb_info
.modename
, name
);
1910 fb_info
.fb_info
.changevar
= NULL
;
1911 fb_info
.fb_info
.node
= -1;
1912 fb_info
.fb_info
.fbops
= &tdfxfb_ops
;
1913 fb_info
.fb_info
.disp
= &fb_info
.disp
;
1914 strcpy(fb_info
.fb_info
.fontname
, fontname
);
1915 fb_info
.fb_info
.switch_con
= &tdfxfb_switch_con
;
1916 fb_info
.fb_info
.updatevar
= &tdfxfb_updatevar
;
1917 fb_info
.fb_info
.blank
= &tdfxfb_blank
;
1918 fb_info
.fb_info
.flags
= FBINFO_FLAG_DEFAULT
;
1920 memset(&var
, 0, sizeof(var
));
1922 !fb_find_mode(&var
, &fb_info
.fb_info
, mode_option
, NULL
, 0, NULL
, 8))
1923 var
= default_mode
[0].var
;
1925 if(noaccel
) var
.accel_flags
&= ~FB_ACCELF_TEXT
;
1926 else var
.accel_flags
|= FB_ACCELF_TEXT
;
1928 if(tdfxfb_decode_var(&var
, &fb_info
.default_par
, &fb_info
)) {
1929 /* ugh -- can't use the mode from the mode db. (or command line),
1930 so try the default */
1933 "can't decode the supplied video mode, using default\n");
1935 var
= default_mode
[0].var
;
1936 if(noaccel
) var
.accel_flags
&= ~FB_ACCELF_TEXT
;
1937 else var
.accel_flags
|= FB_ACCELF_TEXT
;
1939 if(tdfxfb_decode_var(&var
, &fb_info
.default_par
, &fb_info
)) {
1940 /* this is getting really bad!... */
1941 printk("tdfxfb: can't decode default video mode\n");
1946 fb_info
.disp
.screen_base
= fb_info
.bufbase_virt
;
1947 fb_info
.disp
.var
= var
;
1949 if(tdfxfb_set_var(&var
, -1, &fb_info
.fb_info
)) {
1950 printk("tdfxfb: can't set default video mode\n");
1954 if(register_framebuffer(&fb_info
.fb_info
) < 0) {
1955 printk("tdfxfb: can't register framebuffer\n");
1959 printk("fb%d: %s frame buffer device\n",
1960 GET_FB_IDX(fb_info
.fb_info
.node
),
1961 fb_info
.fb_info
.modename
);
1963 /* FIXME: module cannot be unloaded */
1964 /* verify tdfxfb_exit before removing this */
1971 /* hmm, no frame suitable buffer found ... */
1976 * tdfxfb_exit - Driver cleanup
1978 * Releases all resources allocated during the
1979 * course of the driver's lifetime.
1981 * FIXME - do results of fb_alloc_cmap need disposal?
1983 static void __exit
tdfxfb_exit (void)
1985 unregister_framebuffer(&fb_info
.fb_info
);
1986 del_timer_sync(&fb_info
.cursor
.timer
);
1990 mtrr_del(fb_info
.mtrr_idx
, fb_info
.bufbase_phys
, fb_info
.bufbase_size
);
1991 printk("fb: MTRR's turned off\n");
1995 iounmap(fb_info
.regbase_virt
);
1996 iounmap(fb_info
.bufbase_virt
);
1999 MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>");
2000 MODULE_DESCRIPTION("3Dfx framebuffer device driver");
2003 module_init(tdfxfb_init
);
2005 module_exit(tdfxfb_exit
);
2009 void tdfxfb_setup(char *options
,
2013 if(!options
|| !*options
)
2016 for(this_opt
= strtok(options
, ",");
2018 this_opt
= strtok(NULL
, ",")) {
2019 if(!strcmp(this_opt
, "inverse")) {
2022 } else if(!strcmp(this_opt
, "noaccel")) {
2023 noaccel
= nopan
= nowrap
= nohwcursor
= 1;
2024 } else if(!strcmp(this_opt
, "nopan")) {
2026 } else if(!strcmp(this_opt
, "nowrap")) {
2028 } else if (!strcmp(this_opt
, "nohwcursor")) {
2031 } else if (!strcmp(this_opt
, "nomtrr")) {
2034 } else if (!strncmp(this_opt
, "font:", 5)) {
2035 strncpy(fontname
, this_opt
+ 5, 40);
2037 mode_option
= this_opt
;
2043 static int tdfxfb_switch_con(int con
,
2044 struct fb_info
*fb
) {
2045 struct fb_info_tdfx
*info
= (struct fb_info_tdfx
*)fb
;
2046 struct tdfxfb_par par
;
2047 int old_con
= currcon
;
2050 /* Do we have to save the colormap? */
2052 if(fb_display
[currcon
].cmap
.len
)
2053 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, tdfxfb_getcolreg
, fb
);
2056 fb_display
[currcon
].var
.activate
= FB_ACTIVATE_NOW
;
2057 tdfxfb_decode_var(&fb_display
[con
].var
, &par
, info
);
2058 if (old_con
>=0 && vt_cons
[old_con
]->vc_mode
!=KD_GRAPHICS
) {
2059 /* check if we have to change video registers */
2060 struct tdfxfb_par old_par
;
2061 tdfxfb_decode_var(&fb_display
[old_con
].var
, &old_par
, info
);
2062 if (!memcmp(&par
,&old_par
,sizeof(par
)))
2063 set_par
= 0; /* avoid flicker */
2066 tdfxfb_set_par(&par
, info
);
2068 if (fb_display
[con
].dispsw
&& fb_display
[con
].conp
)
2069 fb_con
.con_cursor(fb_display
[con
].conp
, CM_ERASE
);
2071 del_timer(&(info
->cursor
.timer
));
2072 fb_info
.cursor
.state
=CM_ERASE
;
2075 if (fb_display
[con
].conp
)
2076 tdfxfb_createcursor( &fb_display
[con
] );
2078 info
->cursor
.redraw
=1;
2080 tdfxfb_set_dispsw(&fb_display
[con
],
2083 par
.accel_flags
& FB_ACCELF_TEXT
);
2085 tdfxfb_install_cmap(&fb_display
[con
], fb
);
2086 tdfxfb_updatevar(con
, fb
);
2091 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
2092 static void tdfxfb_blank(int blank
,
2093 struct fb_info
*fb
) {
2094 u32 dacmode
, state
= 0, vgablank
= 0;
2096 dacmode
= tdfx_inl(DACMODE
);
2099 case 0: /* Screen: On; HSync: On, VSync: On */
2103 case 1: /* Screen: Off; HSync: On, VSync: On */
2107 case 2: /* Screen: Off; HSync: On, VSync: Off */
2111 case 3: /* Screen: Off; HSync: Off, VSync: On */
2115 case 4: /* Screen: Off; HSync: Off, VSync: Off */
2116 state
= BIT(1) | BIT(3);
2121 dacmode
&= ~(BIT(1) | BIT(3));
2123 banshee_make_room(1);
2124 tdfx_outl(DACMODE
, dacmode
);
2126 vga_disable_video();
2133 static int tdfxfb_updatevar(int con
,
2134 struct fb_info
* fb
) {
2136 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)fb
;
2137 if ((con
==currcon
) && (!nopan
))
2138 do_pan_var(&fb_display
[con
].var
,i
);
2142 static int tdfxfb_getcolreg(unsigned regno
,
2147 struct fb_info
* fb
) {
2148 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)fb
;
2150 if (regno
> i
->current_par
.cmap_len
) return 1;
2152 *red
= i
->palette
[regno
].red
;
2153 *green
= i
->palette
[regno
].green
;
2154 *blue
= i
->palette
[regno
].blue
;
2160 static int tdfxfb_setcolreg(unsigned regno
,
2165 struct fb_info
* info
) {
2166 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)info
;
2168 if (regno
>= i
->current_par
.cmap_len
) return 1;
2170 i
->palette
[regno
].red
= red
;
2171 i
->palette
[regno
].green
= green
;
2172 i
->palette
[regno
].blue
= blue
;
2174 switch(i
->current_par
.bpp
) {
2175 #ifdef FBCON_HAS_CFB8
2177 rgbcol
=(((u32
)red
& 0xff00) << 8) |
2178 (((u32
)green
& 0xff00) << 0) |
2179 (((u32
)blue
& 0xff00) >> 8);
2180 do_setpalentry(regno
,rgbcol
);
2183 #ifdef FBCON_HAS_CFB16
2185 i
->fbcon_cmap
.cfb16
[regno
] =
2186 (((u32
)red
& 0xf800) >> 0) |
2187 (((u32
)green
& 0xfc00) >> 5) |
2188 (((u32
)blue
& 0xf800) >> 11);
2191 #ifdef FBCON_HAS_CFB24
2193 i
->fbcon_cmap
.cfb24
[regno
] =
2194 (((u32
)red
& 0xff00) << 8) |
2195 (((u32
)green
& 0xff00) << 0) |
2196 (((u32
)blue
& 0xff00) >> 8);
2199 #ifdef FBCON_HAS_CFB32
2201 i
->fbcon_cmap
.cfb32
[regno
] =
2202 (((u32
)red
& 0xff00) << 8) |
2203 (((u32
)green
& 0xff00) << 0) |
2204 (((u32
)blue
& 0xff00) >> 8);
2208 DPRINTK("bad depth %u\n", i
->current_par
.bpp
);
2214 static void tdfxfb_install_cmap(struct display
*d
,struct fb_info
*info
)
2216 struct fb_info_tdfx
* i
= (struct fb_info_tdfx
*)info
;
2219 fb_set_cmap(&(d
->cmap
), 1, tdfxfb_setcolreg
, info
);
2221 fb_set_cmap(fb_default_cmap(i
->current_par
.cmap_len
), 1,
2222 tdfxfb_setcolreg
, info
);
2226 static void tdfxfb_createcursorshape(struct display
* p
)
2228 unsigned int h
,cu
,cd
;
2232 if (cd
>= 10) cd
--;
2233 fb_info
.cursor
.type
=p
->conp
->vc_cursor_type
& CUR_HWMASK
;
2234 switch (fb_info
.cursor
.type
) {
2241 case CUR_LOWER_THIRD
:
2244 case CUR_LOWER_HALF
:
2247 case CUR_TWO_THIRDS
:
2256 fb_info
.cursor
.w
=fontwidth(p
);
2257 fb_info
.cursor
.u
=cu
;
2258 fb_info
.cursor
.d
=cd
;
2261 static void tdfxfb_createcursor(struct display
*p
)
2268 tdfxfb_createcursorshape(p
);
2269 xline
= (1 << fb_info
.cursor
.w
)-1;
2270 cursorbase
=(u8
*)fb_info
.bufbase_virt
;
2271 h
=fb_info
.cursor
.cursorimage
;
2273 to
=fb_info
.cursor
.u
;
2274 for (i
= 0; i
< to
; i
++) {
2275 writel(0, cursorbase
+h
);
2276 writel(0, cursorbase
+h
+4);
2277 writel(~0, cursorbase
+h
+8);
2278 writel(~0, cursorbase
+h
+12);
2282 to
= fb_info
.cursor
.d
;
2284 for (; i
< to
; i
++) {
2285 writel(xline
, cursorbase
+h
);
2286 writel(0, cursorbase
+h
+4);
2287 writel(~0, cursorbase
+h
+8);
2288 writel(~0, cursorbase
+h
+12);
2292 for (; i
< 64; i
++) {
2293 writel(0, cursorbase
+h
);
2294 writel(0, cursorbase
+h
+4);
2295 writel(~0, cursorbase
+h
+8);
2296 writel(~0, cursorbase
+h
+12);
2301 static void tdfxfb_hwcursor_init(void)
2304 start
= (fb_info
.bufbase_size
-1024) & PAGE_MASK
;
2305 fb_info
.bufbase_size
=start
;
2306 fb_info
.cursor
.cursorimage
=fb_info
.bufbase_size
;
2307 printk("tdfxfb: reserving 1024 bytes for the hwcursor at %p\n",
2308 fb_info
.regbase_virt
+fb_info
.cursor
.cursorimage
);