1/*
2 *
3 * tdfxfb.c
4 *
5 * Author: Hannu Mallat <hmallat@cc.hut.fi>
6 *
7 * Copyright � 1999 Hannu Mallat
8 * All rights reserved
9 *
10 * Created      : Thu Sep 23 18:17:43 1999, hmallat
11 * Last modified: Tue Nov  2 21:19:47 1999, hmallat
12 *
13 * Lots of the information here comes from the Daryll Strauss' Banshee
14 * patches to the XF86 server, and the rest comes from the 3dfx
15 * Banshee specification. I'm very much indebted to Daryll for his
16 * work on the X server.
17 *
18 * Voodoo3 support was contributed Harold Oga. Lots of additions
19 * (proper acceleration, 24 bpp, hardware cursor) and bug fixes by Attila
20 * Kesmarki. Thanks guys!
21 *
22 * Voodoo1 and Voodoo2 support aren't relevant to this driver as they
23 * behave very differently from the Voodoo3/4/5. For anyone wanting to
24 * use frame buffer on the Voodoo1/2, see the sstfb driver (which is
25 * located at http://www.sourceforge.net/projects/sstfb).
26 *
27 * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
28 * I do wish the next version is a bit more complete. Without the XF86
29 * patches I couldn't have gotten even this far... for instance, the
30 * extensions to the VGA register set go completely unmentioned in the
31 * spec! Also, lots of references are made to the 'SST core', but no
32 * spec is publicly available, AFAIK.
33 *
34 * The structure of this driver comes pretty much from the Permedia
35 * driver by Ilario Nardinocchi, which in turn is based on skeletonfb.
36 *
37 * TODO:
38 * - support for 16/32 bpp needs fixing (funky bootup penguin)
39 * - multihead support (basically need to support an array of fb_infos)
40 * - support other architectures (PPC, Alpha); does the fact that the VGA
41 *   core can be accessed only thru I/O (not memory mapped) complicate
42 *   things?
43 *
44 * Version history:
45 *
46 * 0.1.4 (released 2002-05-28) ported over to new fbdev api by James Simmons
47 *
48 * 0.1.3 (released 1999-11-02) added Attila's panning support, code
49 *			       reorg, hwcursor address page size alignment
50 *                             (for mmaping both frame buffer and regs),
51 *                             and my changes to get rid of hardcoded
52 *                             VGA i/o register locations (uses PCI
53 *                             configuration info now)
54 * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and
55 *                             improvements
56 * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga.
57 * 0.1.0 (released 1999-10-06) initial version
58 *
59 */
60
61#include <linux/module.h>
62#include <linux/kernel.h>
63#include <linux/errno.h>
64#include <linux/string.h>
65#include <linux/mm.h>
66#include <linux/slab.h>
67#include <linux/delay.h>
68#include <linux/interrupt.h>
69#include <linux/fb.h>
70#include <linux/init.h>
71#include <linux/pci.h>
72#include <linux/nvram.h>
73#include <asm/io.h>
74#include <linux/timer.h>
75#include <linux/spinlock.h>
76
77#include <video/tdfx.h>
78
79#undef TDFXFB_DEBUG
80#ifdef TDFXFB_DEBUG
81#define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b)
82#else
83#define DPRINTK(a,b...)
84#endif
85
86#define BANSHEE_MAX_PIXCLOCK 270000
87#define VOODOO3_MAX_PIXCLOCK 300000
88#define VOODOO5_MAX_PIXCLOCK 350000
89
90static struct fb_fix_screeninfo tdfx_fix __devinitdata = {
91	.id =		"3Dfx",
92	.type =		FB_TYPE_PACKED_PIXELS,
93	.visual =	FB_VISUAL_PSEUDOCOLOR,
94	.ypanstep =	1,
95	.ywrapstep =	1,
96	.accel =	FB_ACCEL_3DFX_BANSHEE
97};
98
99static struct fb_var_screeninfo tdfx_var __devinitdata = {
100	/* "640x480, 8 bpp @ 60 Hz */
101	.xres =		640,
102	.yres =		480,
103	.xres_virtual =	640,
104	.yres_virtual =	1024,
105	.bits_per_pixel =8,
106	.red =		{0, 8, 0},
107	.blue =		{0, 8, 0},
108	.green =	{0, 8, 0},
109	.activate =	FB_ACTIVATE_NOW,
110	.height =	-1,
111	.width =	-1,
112	.accel_flags =	FB_ACCELF_TEXT,
113	.pixclock =	39722,
114	.left_margin =	40,
115	.right_margin =	24,
116	.upper_margin =	32,
117	.lower_margin =	11,
118	.hsync_len =	96,
119	.vsync_len =	2,
120	.vmode =	FB_VMODE_NONINTERLACED
121};
122
123/*
124 * PCI driver prototypes
125 */
126static int __devinit tdfxfb_probe(struct pci_dev *pdev,
127				  const struct pci_device_id *id);
128static void __devexit tdfxfb_remove(struct pci_dev *pdev);
129
130static struct pci_device_id tdfxfb_id_table[] = {
131	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE,
132	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
133	  0xff0000, 0 },
134	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3,
135	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
136	  0xff0000, 0 },
137	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5,
138	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
139	  0xff0000, 0 },
140	{ 0, }
141};
142
143static struct pci_driver tdfxfb_driver = {
144	.name		= "tdfxfb",
145	.id_table 	= tdfxfb_id_table,
146	.probe 		= tdfxfb_probe,
147	.remove 	= __devexit_p(tdfxfb_remove),
148};
149
150MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
151
152/*
153 *  Frame buffer device API
154 */
155static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb);
156static int tdfxfb_set_par(struct fb_info *info);
157static int tdfxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
158			    u_int transp, struct fb_info *info);
159static int tdfxfb_blank(int blank, struct fb_info *info);
160static int tdfxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
161static int banshee_wait_idle(struct fb_info *info);
162#ifdef CONFIG_FB_3DFX_ACCEL
163static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
164static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
165static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image);
166#endif /* CONFIG_FB_3DFX_ACCEL */
167
168static struct fb_ops tdfxfb_ops = {
169	.owner		= THIS_MODULE,
170	.fb_check_var	= tdfxfb_check_var,
171	.fb_set_par	= tdfxfb_set_par,
172	.fb_setcolreg	= tdfxfb_setcolreg,
173	.fb_blank	= tdfxfb_blank,
174	.fb_pan_display	= tdfxfb_pan_display,
175	.fb_sync	= banshee_wait_idle,
176#ifdef CONFIG_FB_3DFX_ACCEL
177	.fb_fillrect	= tdfxfb_fillrect,
178	.fb_copyarea	= tdfxfb_copyarea,
179	.fb_imageblit	= tdfxfb_imageblit,
180#else
181	.fb_fillrect	= cfb_fillrect,
182	.fb_copyarea	= cfb_copyarea,
183	.fb_imageblit	= cfb_imageblit,
184#endif
185};
186
187/*
188 * do_xxx: Hardware-specific functions
189 */
190static u32 do_calc_pll(int freq, int *freq_out);
191static void  do_write_regs(struct fb_info *info, struct banshee_reg *reg);
192static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short);
193
194/*
195 * Driver data
196 */
197static int  nopan   = 0;
198static int  nowrap  = 1;      // not implemented (yet)
199static char *mode_option __devinitdata = NULL;
200
201/* -------------------------------------------------------------------------
202 *                      Hardware-specific funcions
203 * ------------------------------------------------------------------------- */
204
205#ifdef VGA_REG_IO
206static inline  u8 vga_inb(struct tdfx_par *par, u32 reg) { return inb(reg); }
207
208static inline void vga_outb(struct tdfx_par *par, u32 reg,  u8 val) { outb(val, reg); }
209#else
210static inline  u8 vga_inb(struct tdfx_par *par, u32 reg) {
211	return inb(par->iobase + reg - 0x300);
212}
213static inline void vga_outb(struct tdfx_par *par, u32 reg,  u8 val) {
214	outb(val, par->iobase + reg - 0x300);
215}
216#endif
217
218static inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val) {
219	vga_outb(par, GRA_I, idx); vga_outb(par, GRA_D, val);
220}
221
222static inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val) {
223	vga_outb(par, SEQ_I, idx); vga_outb(par, SEQ_D, val);
224}
225
226static inline u8 seq_inb(struct tdfx_par *par, u32 idx) {
227	vga_outb(par, SEQ_I, idx); return vga_inb(par, SEQ_D);
228}
229
230static inline void crt_outb(struct tdfx_par *par, u32 idx, u8 val) {
231	vga_outb(par, CRT_I, idx); vga_outb(par, CRT_D, val);
232}
233
234static inline u8 crt_inb(struct tdfx_par *par, u32 idx) {
235	vga_outb(par, CRT_I, idx); return vga_inb(par, CRT_D);
236}
237
238static inline void att_outb(struct tdfx_par *par, u32 idx, u8 val)
239{
240	unsigned char tmp;
241
242	tmp = vga_inb(par, IS1_R);
243	vga_outb(par, ATT_IW, idx);
244	vga_outb(par, ATT_IW, val);
245}
246
247static inline void vga_disable_video(struct tdfx_par *par)
248{
249	unsigned char s;
250
251	s = seq_inb(par, 0x01) | 0x20;
252	seq_outb(par, 0x00, 0x01);
253	seq_outb(par, 0x01, s);
254	seq_outb(par, 0x00, 0x03);
255}
256
257static inline void vga_enable_video(struct tdfx_par *par)
258{
259	unsigned char s;
260
261	s = seq_inb(par, 0x01) & 0xdf;
262	seq_outb(par, 0x00, 0x01);
263	seq_outb(par, 0x01, s);
264	seq_outb(par, 0x00, 0x03);
265}
266
267static inline void vga_enable_palette(struct tdfx_par *par)
268{
269	vga_inb(par, IS1_R);
270	vga_outb(par, ATT_IW, 0x20);
271}
272
273static inline u32 tdfx_inl(struct tdfx_par *par, unsigned int reg)
274{
275	return readl(par->regbase_virt + reg);
276}
277
278static inline void tdfx_outl(struct tdfx_par *par, unsigned int reg, u32 val)
279{
280	writel(val, par->regbase_virt + reg);
281}
282
283static inline void banshee_make_room(struct tdfx_par *par, int size)
284{
285	/* Note: The Voodoo3's onboard FIFO has 32 slots. This loop
286	 * won't quit if you ask for more. */
287	while((tdfx_inl(par, STATUS) & 0x1f) < size-1);
288}
289
290static int banshee_wait_idle(struct fb_info *info)
291{
292	struct tdfx_par *par = info->par;
293	int i = 0;
294
295	banshee_make_room(par, 1);
296	tdfx_outl(par, COMMAND_3D, COMMAND_3D_NOP);
297
298	while(1) {
299		i = (tdfx_inl(par, STATUS) & STATUS_BUSY) ? 0 : i + 1;
300		if(i == 3) break;
301	}
302	return 0;
303}
304
305/*
306 * Set the color of a palette entry in 8bpp mode
307 */
308static inline void do_setpalentry(struct tdfx_par *par, unsigned regno, u32 c)
309{
310	banshee_make_room(par, 2);
311	tdfx_outl(par, DACADDR, regno);
312	tdfx_outl(par, DACDATA, c);
313}
314
315static u32 do_calc_pll(int freq, int* freq_out)
316{
317	int m, n, k, best_m, best_n, best_k, best_error;
318	int fref = 14318;
319
320	best_error = freq;
321	best_n = best_m = best_k = 0;
322
323	for (k = 3; k >= 0; k--) {
324		for (m = 63; m >= 0; m--) {
325			/*
326			 * Estimate value of n that produces target frequency
327			 * with current m and k
328			 */
329			int n_estimated = (freq * (m + 2) * (1 << k) / fref) - 2;
330
331			/* Search neighborhood of estimated n */
332			for (n = max(0, n_estimated - 1);
333					n <= min(255, n_estimated + 1); n++) {
334				/*
335				 * Calculate PLL freqency with current m, k and
336				 * estimated n
337				 */
338				int f = fref * (n + 2) / (m + 2) / (1 << k);
339				int error = abs (f - freq);
340
341				/*
342				 *  If this is the closest we've come to the
343				 * target frequency then remember n, m and k
344				 */
345				if (error  < best_error) {
346					best_error = error;
347					best_n     = n;
348					best_m     = m;
349					best_k     = k;
350				}
351			}
352		}
353	}
354
355	n = best_n;
356	m = best_m;
357	k = best_k;
358	*freq_out = fref*(n + 2)/(m + 2)/(1 << k);
359
360	return (n << 8) | (m << 2) | k;
361}
362
363static void do_write_regs(struct fb_info *info, struct banshee_reg* reg)
364{
365	struct tdfx_par *par = info->par;
366	int i;
367
368	banshee_wait_idle(info);
369
370	tdfx_outl(par, MISCINIT1, tdfx_inl(par, MISCINIT1) | 0x01);
371
372	crt_outb(par, 0x11, crt_inb(par, 0x11) & 0x7f); /* CRT unprotect */
373
374	banshee_make_room(par, 3);
375	tdfx_outl(par, VGAINIT1,	reg->vgainit1 &  0x001FFFFF);
376	tdfx_outl(par, VIDPROCCFG,	reg->vidcfg   & ~0x00000001);
377	tdfx_outl(par, PLLCTRL0,	reg->vidpll);
378
379	vga_outb(par, MISC_W, reg->misc[0x00] | 0x01);
380
381	for (i = 0; i < 5; i++)
382		seq_outb(par, i, reg->seq[i]);
383
384	for (i = 0; i < 25; i++)
385		crt_outb(par, i, reg->crt[i]);
386
387	for (i = 0; i < 9; i++)
388		gra_outb(par, i, reg->gra[i]);
389
390	for (i = 0; i < 21; i++)
391		att_outb(par, i, reg->att[i]);
392
393	crt_outb(par, 0x1a, reg->ext[0]);
394	crt_outb(par, 0x1b, reg->ext[1]);
395
396	vga_enable_palette(par);
397	vga_enable_video(par);
398
399	banshee_make_room(par, 11);
400	tdfx_outl(par, 	VGAINIT0,      reg->vgainit0);
401	tdfx_outl(par,	DACMODE,       reg->dacmode);
402	tdfx_outl(par,	VIDDESKSTRIDE, reg->stride);
403	tdfx_outl(par,	HWCURPATADDR,  0);
404
405	tdfx_outl(par,	VIDSCREENSIZE,reg->screensize);
406	tdfx_outl(par,	VIDDESKSTART,	reg->startaddr);
407	tdfx_outl(par,	VIDPROCCFG,	reg->vidcfg);
408	tdfx_outl(par,	VGAINIT1,	reg->vgainit1);
409	tdfx_outl(par,	MISCINIT0,	reg->miscinit0);
410
411	banshee_make_room(par,	8);
412	tdfx_outl(par,	SRCBASE,         reg->srcbase);
413	tdfx_outl(par,	DSTBASE,         reg->dstbase);
414	tdfx_outl(par,	COMMANDEXTRA_2D, 0);
415	tdfx_outl(par,	CLIP0MIN,        0);
416	tdfx_outl(par,	CLIP0MAX,        0x0fff0fff);
417	tdfx_outl(par,	CLIP1MIN,        0);
418	tdfx_outl(par,	CLIP1MAX,        0x0fff0fff);
419	tdfx_outl(par,	SRCXY,	   0);
420
421	banshee_wait_idle(info);
422}
423
424static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id)
425{
426	u32 draminit0;
427	u32 draminit1;
428	u32 miscinit1;
429
430	int num_chips;
431	int chip_size; /* in MB */
432	u32 lfbsize;
433	int has_sgram;
434
435	draminit0 = tdfx_inl(par, DRAMINIT0);
436	draminit1 = tdfx_inl(par, DRAMINIT1);
437
438	num_chips = (draminit0 & DRAMINIT0_SGRAM_NUM) ? 8 : 4;
439
440	if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) {
441		/* Banshee/Voodoo3 */
442		has_sgram = draminit1 & DRAMINIT1_MEM_SDRAM;
443		chip_size = has_sgram ? ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 2 : 1)
444				      : 2;
445	} else {
446		/* Voodoo4/5 */
447		has_sgram = 0;
448		chip_size = 1 << ((draminit0 & DRAMINIT0_SGRAM_TYPE_MASK) >> DRAMINIT0_SGRAM_TYPE_SHIFT);
449	}
450	lfbsize = num_chips * chip_size * 1024 * 1024;
451
452	/* disable block writes for SDRAM */
453	miscinit1 = tdfx_inl(par, MISCINIT1);
454	miscinit1 |= has_sgram ? 0 : MISCINIT1_2DBLOCK_DIS;
455	miscinit1 |= MISCINIT1_CLUT_INV;
456
457	banshee_make_room(par, 1);
458	tdfx_outl(par, MISCINIT1, miscinit1);
459	return lfbsize;
460}
461
462/* ------------------------------------------------------------------------- */
463
464static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info)
465{
466	struct tdfx_par *par = info->par;
467	u32 lpitch;
468
469	if (var->bits_per_pixel != 8  && var->bits_per_pixel != 16 &&
470	    var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
471		DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
472		return -EINVAL;
473	}
474
475	if (var->xres != var->xres_virtual)
476		var->xres_virtual = var->xres;
477
478	if (var->yres > var->yres_virtual)
479		var->yres_virtual = var->yres;
480
481	if (var->xoffset) {
482		DPRINTK("xoffset not supported\n");
483		return -EINVAL;
484	}
485
486	/* Banshee doesn't support interlace, but Voodoo4/5 and probably Voodoo3 do. */
487	/* no direct information about device id now? use max_pixclock for this... */
488	if (((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) &&
489			(par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) {
490		DPRINTK("interlace not supported\n");
491		return -EINVAL;
492	}
493
494	var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
495	lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
496
497	if (var->xres < 320 || var->xres > 2048) {
498		DPRINTK("width not supported: %u\n", var->xres);
499		return -EINVAL;
500	}
501
502	if (var->yres < 200 || var->yres > 2048) {
503		DPRINTK("height not supported: %u\n", var->yres);
504		return -EINVAL;
505	}
506
507	if (lpitch * var->yres_virtual > info->fix.smem_len) {
508		var->yres_virtual = info->fix.smem_len/lpitch;
509		if (var->yres_virtual < var->yres) {
510			DPRINTK("no memory for screen (%ux%ux%u)\n",
511			var->xres, var->yres_virtual, var->bits_per_pixel);
512			return -EINVAL;
513		}
514	}
515
516	if (PICOS2KHZ(var->pixclock) > par->max_pixclock) {
517		DPRINTK("pixclock too high (%ldKHz)\n",PICOS2KHZ(var->pixclock));
518		return -EINVAL;
519	}
520
521	switch(var->bits_per_pixel) {
522		case 8:
523			var->red.length = var->green.length = var->blue.length = 8;
524			break;
525		case 16:
526			var->red.offset   = 11;
527			var->red.length   = 5;
528			var->green.offset = 5;
529			var->green.length = 6;
530			var->blue.offset  = 0;
531			var->blue.length  = 5;
532			break;
533		case 24:
534			var->red.offset=16;
535			var->green.offset=8;
536			var->blue.offset=0;
537			var->red.length = var->green.length = var->blue.length = 8;
538		case 32:
539			var->red.offset   = 16;
540			var->green.offset = 8;
541			var->blue.offset  = 0;
542			var->red.length = var->green.length = var->blue.length = 8;
543			break;
544	}
545	var->height = var->width = -1;
546
547	var->accel_flags = FB_ACCELF_TEXT;
548
549	DPRINTK("Checking graphics mode at %dx%d depth %d\n",  var->xres, var->yres, var->bits_per_pixel);
550	return 0;
551}
552
553static int tdfxfb_set_par(struct fb_info *info)
554{
555	struct tdfx_par *par = info->par;
556	u32 hdispend, hsyncsta, hsyncend, htotal;
557	u32 hd, hs, he, ht, hbs, hbe;
558	u32 vd, vs, ve, vt, vbs, vbe;
559	struct banshee_reg reg;
560	int fout, freq;
561	u32 wd, cpp;
562
563	par->baseline  = 0;
564
565	memset(&reg, 0, sizeof(reg));
566	cpp = (info->var.bits_per_pixel + 7)/8;
567
568	reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE | VIDCFG_CURS_X11 | ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) | (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
569
570	/* PLL settings */
571	freq = PICOS2KHZ(info->var.pixclock);
572
573	reg.dacmode = 0;
574	reg.vidcfg  &= ~VIDCFG_2X;
575
576	hdispend = info->var.xres;
577	hsyncsta = hdispend + info->var.right_margin;
578	hsyncend = hsyncsta + info->var.hsync_len;
579	htotal   = hsyncend + info->var.left_margin;
580
581	if (freq > par->max_pixclock/2) {
582		freq = freq > par->max_pixclock ? par->max_pixclock : freq;
583		reg.dacmode |= DACMODE_2X;
584		reg.vidcfg  |= VIDCFG_2X;
585		hdispend >>= 1;
586		hsyncsta >>= 1;
587		hsyncend >>= 1;
588		htotal   >>= 1;
589	}
590
591	hd  = wd = (hdispend >> 3) - 1;
592	hs  = (hsyncsta >> 3) - 1;
593	he  = (hsyncend >> 3) - 1;
594	ht  = (htotal >> 3) - 1;
595	hbs = hd;
596	hbe = ht;
597
598	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
599		vbs = vd = (info->var.yres << 1) - 1;
600		vs  = vd + (info->var.lower_margin << 1);
601		ve  = vs + (info->var.vsync_len << 1);
602		vbe = vt = ve + (info->var.upper_margin << 1) - 1;
603	} else {
604		vbs = vd = info->var.yres - 1;
605		vs  = vd + info->var.lower_margin;
606		ve  = vs + info->var.vsync_len;
607		vbe = vt = ve + info->var.upper_margin - 1;
608	}
609
610	/* this is all pretty standard VGA register stuffing */
611	reg.misc[0x00] = 0x0f |
612			(info->var.xres < 400 ? 0xa0 :
613			 info->var.xres < 480 ? 0x60 :
614			 info->var.xres < 768 ? 0xe0 : 0x20);
615
616	reg.gra[0x00] = 0x00;
617	reg.gra[0x01] = 0x00;
618	reg.gra[0x02] = 0x00;
619	reg.gra[0x03] = 0x00;
620	reg.gra[0x04] = 0x00;
621	reg.gra[0x05] = 0x40;
622	reg.gra[0x06] = 0x05;
623	reg.gra[0x07] = 0x0f;
624	reg.gra[0x08] = 0xff;
625
626	reg.att[0x00] = 0x00;
627	reg.att[0x01] = 0x01;
628	reg.att[0x02] = 0x02;
629	reg.att[0x03] = 0x03;
630	reg.att[0x04] = 0x04;
631	reg.att[0x05] = 0x05;
632	reg.att[0x06] = 0x06;
633	reg.att[0x07] = 0x07;
634	reg.att[0x08] = 0x08;
635	reg.att[0x09] = 0x09;
636	reg.att[0x0a] = 0x0a;
637	reg.att[0x0b] = 0x0b;
638	reg.att[0x0c] = 0x0c;
639	reg.att[0x0d] = 0x0d;
640	reg.att[0x0e] = 0x0e;
641	reg.att[0x0f] = 0x0f;
642	reg.att[0x10] = 0x41;
643	reg.att[0x11] = 0x00;
644	reg.att[0x12] = 0x0f;
645	reg.att[0x13] = 0x00;
646	reg.att[0x14] = 0x00;
647
648	reg.seq[0x00] = 0x03;
649	reg.seq[0x01] = 0x01;
650	reg.seq[0x02] = 0x0f;
651	reg.seq[0x03] = 0x00;
652	reg.seq[0x04] = 0x0e;
653
654	reg.crt[0x00] = ht - 4;
655	reg.crt[0x01] = hd;
656	reg.crt[0x02] = hbs;
657	reg.crt[0x03] = 0x80 | (hbe & 0x1f);
658	reg.crt[0x04] = hs;
659	reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
660	reg.crt[0x06] = vt;
661	reg.crt[0x07] = ((vs & 0x200) >> 2) |
662			((vd & 0x200) >> 3) |
663			((vt & 0x200) >> 4) | 0x10 |
664			((vbs & 0x100) >> 5) |
665			((vs  & 0x100) >> 6) |
666			((vd  & 0x100) >> 7) |
667			((vt  & 0x100) >> 8);
668	reg.crt[0x08] = 0x00;
669	reg.crt[0x09] = 0x40 | ((vbs & 0x200) >> 4);
670	reg.crt[0x0a] = 0x00;
671	reg.crt[0x0b] = 0x00;
672	reg.crt[0x0c] = 0x00;
673	reg.crt[0x0d] = 0x00;
674	reg.crt[0x0e] = 0x00;
675	reg.crt[0x0f] = 0x00;
676	reg.crt[0x10] = vs;
677	reg.crt[0x11] = (ve & 0x0f) | 0x20;
678	reg.crt[0x12] = vd;
679	reg.crt[0x13] = wd;
680	reg.crt[0x14] = 0x00;
681	reg.crt[0x15] = vbs;
682	reg.crt[0x16] = vbe + 1;
683	reg.crt[0x17] = 0xc3;
684	reg.crt[0x18] = 0xff;
685
686	/* Banshee's nonvga stuff */
687	reg.ext[0x00] = (((ht  & 0x100) >> 8) |
688			((hd  & 0x100) >> 6) |
689			((hbs & 0x100) >> 4) |
690			((hbe &  0x40) >> 1) |
691			((hs  & 0x100) >> 2) |
692			((he  &  0x20) << 2));
693	reg.ext[0x01] = (((vt  & 0x400) >> 10) |
694			((vd  & 0x400) >>  8) |
695			((vbs & 0x400) >>  6) |
696			((vbe & 0x400) >>  4));
697
698	reg.vgainit0 = 	VGAINIT0_8BIT_DAC     |
699			VGAINIT0_EXT_ENABLE   |
700			VGAINIT0_WAKEUP_3C3   |
701			VGAINIT0_ALT_READBACK |
702			VGAINIT0_EXTSHIFTOUT;
703	reg.vgainit1 = tdfx_inl(par, VGAINIT1) & 0x1fffff;
704
705	reg.cursloc   = 0;
706
707	reg.cursc0    = 0;
708	reg.cursc1    = 0xffffff;
709
710	reg.stride    = info->var.xres * cpp;
711	reg.startaddr = par->baseline * reg.stride;
712	reg.srcbase   = reg.startaddr;
713	reg.dstbase   = reg.startaddr;
714
715	/* PLL settings */
716	freq = PICOS2KHZ(info->var.pixclock);
717
718	reg.dacmode &= ~DACMODE_2X;
719	reg.vidcfg  &= ~VIDCFG_2X;
720	if (freq > par->max_pixclock/2) {
721		freq = freq > par->max_pixclock ? par->max_pixclock : freq;
722		reg.dacmode |= DACMODE_2X;
723		reg.vidcfg  |= VIDCFG_2X;
724	}
725	reg.vidpll = do_calc_pll(freq, &fout);
726
727	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
728		reg.screensize = info->var.xres | (info->var.yres << 13);
729		reg.vidcfg |= VIDCFG_HALF_MODE;
730		reg.crt[0x09] |= 0x80;
731	} else {
732		reg.screensize = info->var.xres | (info->var.yres << 12);
733		reg.vidcfg &= ~VIDCFG_HALF_MODE;
734	}
735	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
736		reg.vidcfg |= VIDCFG_INTERLACE;
737	reg.miscinit0 = tdfx_inl(par, MISCINIT0);
738
739#if defined(__BIG_ENDIAN)
740	switch (info->var.bits_per_pixel) {
741		case 8:
742		case 24:
743			reg.miscinit0 &= ~(1 << 30);
744			reg.miscinit0 &= ~(1 << 31);
745			break;
746		case 16:
747			reg.miscinit0 |= (1 << 30);
748			reg.miscinit0 |= (1 << 31);
749			break;
750		case 32:
751			reg.miscinit0 |= (1 << 30);
752			reg.miscinit0 &= ~(1 << 31);
753			break;
754	}
755#endif
756	do_write_regs(info, &reg);
757
758	/* Now change fb_fix_screeninfo according to changes in par */
759	info->fix.line_length = info->var.xres * ((info->var.bits_per_pixel + 7)>>3);
760	info->fix.visual = (info->var.bits_per_pixel == 8)
761				? FB_VISUAL_PSEUDOCOLOR
762				: FB_VISUAL_TRUECOLOR;
763	DPRINTK("Graphics mode is now set at %dx%d depth %d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel);
764	return 0;
765}
766
767/* A handy macro shamelessly pinched from matroxfb */
768#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
769
770static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
771			    unsigned blue,unsigned transp,struct fb_info *info)
772{
773	struct tdfx_par *par = info->par;
774	u32 rgbcol;
775
776	if (regno >= info->cmap.len || regno > 255) return 1;
777
778	switch (info->fix.visual) {
779	case FB_VISUAL_PSEUDOCOLOR:
780		rgbcol =(((u32)red   & 0xff00) << 8) |
781			(((u32)green & 0xff00) << 0) |
782			(((u32)blue  & 0xff00) >> 8);
783		do_setpalentry(par, regno, rgbcol);
784		break;
785	/* Truecolor has no hardware color palettes. */
786	case FB_VISUAL_TRUECOLOR:
787		if (regno < 16) {
788			rgbcol = (CNVT_TOHW( red, info->var.red.length) <<
789				  info->var.red.offset) |
790				(CNVT_TOHW( green, info->var.green.length) <<
791				 info->var.green.offset) |
792				(CNVT_TOHW( blue, info->var.blue.length) <<
793				 info->var.blue.offset) |
794				(CNVT_TOHW( transp, info->var.transp.length) <<
795				 info->var.transp.offset);
796			par->palette[regno] = rgbcol;
797		}
798
799		break;
800	default:
801		DPRINTK("bad depth %u\n", info->var.bits_per_pixel);
802		break;
803	}
804
805	return 0;
806}
807
808/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
809static int tdfxfb_blank(int blank, struct fb_info *info)
810{
811	struct tdfx_par *par = info->par;
812	u32 dacmode, state = 0, vgablank = 0;
813
814	dacmode = tdfx_inl(par, DACMODE);
815
816	switch (blank) {
817		case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */
818			state    = 0;
819			vgablank = 0;
820			break;
821		case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */
822			state    = 0;
823			vgablank = 1;
824			break;
825		case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */
826			state    = BIT(3);
827			vgablank = 1;
828			break;
829		case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */
830			state    = BIT(1);
831			vgablank = 1;
832			break;
833		case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */
834			state    = BIT(1) | BIT(3);
835			vgablank = 1;
836			break;
837	}
838
839	dacmode &= ~(BIT(1) | BIT(3));
840	dacmode |= state;
841	banshee_make_room(par, 1);
842	tdfx_outl(par, DACMODE, dacmode);
843	if (vgablank)
844		vga_disable_video(par);
845	else
846		vga_enable_video(par);
847	return 0;
848}
849
850/*
851 * Set the starting position of the visible screen to var->yoffset
852 */
853static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
854			      struct fb_info *info)
855{
856	struct tdfx_par *par = info->par;
857	u32 addr;
858
859	if (nopan || var->xoffset || (var->yoffset > var->yres_virtual))
860		return -EINVAL;
861	if ((var->yoffset + var->yres > var->yres_virtual && nowrap))
862		return -EINVAL;
863
864	addr = var->yoffset * info->fix.line_length;
865	banshee_make_room(par, 1);
866	tdfx_outl(par, VIDDESKSTART, addr);
867
868	info->var.xoffset = var->xoffset;
869	info->var.yoffset = var->yoffset;
870	return 0;
871}
872
873#ifdef CONFIG_FB_3DFX_ACCEL
874/*
875 * FillRect 2D command (solidfill or invert (via ROP_XOR))
876 */
877static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
878{
879	struct tdfx_par *par = info->par;
880	u32 bpp = info->var.bits_per_pixel;
881	u32 stride = info->fix.line_length;
882	u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
883	int tdfx_rop;
884
885	if (rect->rop == ROP_COPY)
886		tdfx_rop = TDFX_ROP_COPY;
887	else
888		tdfx_rop = TDFX_ROP_XOR;
889
890	banshee_make_room(par, 5);
891	tdfx_outl(par,	DSTFORMAT, fmt);
892	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
893		tdfx_outl(par,	COLORFORE, rect->color);
894	} else { /* FB_VISUAL_TRUECOLOR */
895		tdfx_outl(par, COLORFORE, par->palette[rect->color]);
896	}
897	tdfx_outl(par,	COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24));
898	tdfx_outl(par,	DSTSIZE,    rect->width | (rect->height << 16));
899	tdfx_outl(par,	LAUNCH_2D,  rect->dx | (rect->dy << 16));
900}
901
902/*
903 * Screen-to-Screen BitBlt 2D command (for the bmove fb op.)
904 */
905static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
906{
907	struct tdfx_par *par = info->par;
908   	u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy;
909	u32 bpp = info->var.bits_per_pixel;
910	u32 stride = info->fix.line_length;
911	u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);
912	u32 fmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
913
914	if (area->sx <= area->dx) {
915		//-X
916		blitcmd |= BIT(14);
917		sx += area->width - 1;
918		dx += area->width - 1;
919	}
920	if (area->sy <= area->dy) {
921		//-Y
922		blitcmd |= BIT(15);
923		sy += area->height - 1;
924		dy += area->height - 1;
925	}
926
927	banshee_make_room(par, 6);
928
929	tdfx_outl(par,	SRCFORMAT, fmt);
930	tdfx_outl(par,	DSTFORMAT, fmt);
931	tdfx_outl(par,	COMMAND_2D, blitcmd);
932	tdfx_outl(par,	DSTSIZE,   area->width | (area->height << 16));
933	tdfx_outl(par,	DSTXY,     dx | (dy << 16));
934	tdfx_outl(par,	LAUNCH_2D, sx | (sy << 16));
935}
936
937static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image)
938{
939	struct tdfx_par *par = info->par;
940	int size = image->height * ((image->width * image->depth + 7)>>3);
941	int fifo_free;
942	int i, stride = info->fix.line_length;
943	u32 bpp = info->var.bits_per_pixel;
944	u32 dstfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
945	u8 *chardata = (u8 *) image->data;
946	u32 srcfmt;
947
948	if (image->depth != 1) {
949		//banshee_make_room(par, 6 + ((size + 3) >> 2));
950		//srcfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13) | 0x400000;
951		cfb_imageblit(info, image);
952		return;
953	} else {
954		banshee_make_room(par, 8);
955		switch (info->fix.visual) {
956			case FB_VISUAL_PSEUDOCOLOR:
957		tdfx_outl(par, COLORFORE, image->fg_color);
958		tdfx_outl(par, COLORBACK, image->bg_color);
959				break;
960			case FB_VISUAL_TRUECOLOR:
961			default:
962				tdfx_outl(par, COLORFORE,
963					  par->palette[image->fg_color]);
964				tdfx_outl(par, COLORBACK,
965					  par->palette[image->bg_color]);
966		}
967#ifdef __BIG_ENDIAN
968		srcfmt = 0x400000 | BIT(20);
969#else
970		srcfmt = 0x400000;
971#endif
972	}
973
974	tdfx_outl(par,	SRCXY,     0);
975	tdfx_outl(par,	DSTXY,     image->dx | (image->dy << 16));
976	tdfx_outl(par,	COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
977	tdfx_outl(par,	SRCFORMAT, srcfmt);
978	tdfx_outl(par,	DSTFORMAT, dstfmt);
979	tdfx_outl(par,	DSTSIZE,   image->width | (image->height << 16));
980
981	/* A count of how many free FIFO entries we've requested.
982	 * When this goes negative, we need to request more. */
983	fifo_free = 0;
984
985	/* Send four bytes at a time of data */
986	for (i = (size >> 2) ; i > 0; i--) {
987		if(--fifo_free < 0) {
988			fifo_free=31;
989			banshee_make_room(par,fifo_free);
990		}
991		tdfx_outl(par,	LAUNCH_2D,*(u32*)chardata);
992		chardata += 4;
993	}
994
995	/* Send the leftovers now */
996	banshee_make_room(par,3);
997	i = size%4;
998	switch (i) {
999		case 0: break;
1000		case 1:  tdfx_outl(par,	LAUNCH_2D,*chardata); break;
1001		case 2:  tdfx_outl(par,	LAUNCH_2D,*(u16*)chardata); break;
1002		case 3:  tdfx_outl(par,	LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
1003	}
1004}
1005#endif /* CONFIG_FB_3DFX_ACCEL */
1006
1007#ifdef TDFX_HARDWARE_CURSOR
1008static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
1009{
1010	struct tdfx_par *par = info->par;
1011	unsigned long flags;
1012
1013	/*
1014	 * If the cursor is not be changed this means either we want the
1015	 * current cursor state (if enable is set) or we want to query what
1016	 * we can do with the cursor (if enable is not set)
1017 	 */
1018	if (!cursor->set) return 0;
1019
1020	/* Too large of a cursor :-( */
1021	if (cursor->image.width > 64 || cursor->image.height > 64)
1022		return -ENXIO;
1023
1024	/*
1025	 * If we are going to be changing things we should disable
1026	 * the cursor first
1027	 */
1028	if (info->cursor.enable) {
1029		spin_lock_irqsave(&par->DAClock, flags);
1030		info->cursor.enable = 0;
1031		del_timer(&(par->hwcursor.timer));
1032		tdfx_outl(par, VIDPROCCFG, par->hwcursor.disable);
1033		spin_unlock_irqrestore(&par->DAClock, flags);
1034	}
1035
1036	/* Disable the Cursor */
1037	if ((cursor->set && FB_CUR_SETCUR) && !cursor->enable)
1038		return 0;
1039
1040	/* fix cursor color - XFree86 forgets to restore it properly */
1041	if (cursor->set && FB_CUR_SETCMAP) {
1042		struct fb_cmap cmap = cursor->image.cmap;
1043		unsigned long bg_color, fg_color;
1044
1045		cmap.len = 2; /* Voodoo 3+ only support 2 color cursors */
1046		fg_color = ((cmap.red[cmap.start] << 16) |
1047			    (cmap.green[cmap.start] << 8)  |
1048			    (cmap.blue[cmap.start]));
1049		bg_color = ((cmap.red[cmap.start+1] << 16) |
1050			    (cmap.green[cmap.start+1] << 8) |
1051			    (cmap.blue[cmap.start+1]));
1052		fb_copy_cmap(&cmap, &info->cursor.image.cmap);
1053		spin_lock_irqsave(&par->DAClock, flags);
1054		banshee_make_room(par, 2);
1055		tdfx_outl(par, HWCURC0, bg_color);
1056		tdfx_outl(par, HWCURC1, fg_color);
1057		spin_unlock_irqrestore(&par->DAClock, flags);
1058	}
1059
1060	if (cursor->set && FB_CUR_SETPOS) {
1061		int x, y;
1062
1063		x = cursor->image.dx;
1064		y = cursor->image.dy;
1065		y -= info->var.yoffset;
1066		info->cursor.image.dx = x;
1067		info->cursor.image.dy = y;
1068		x += 63;
1069		y += 63;
1070		spin_lock_irqsave(&par->DAClock, flags);
1071		banshee_make_room(par, 1);
1072		tdfx_outl(par, HWCURLOC, (y << 16) + x);
1073		spin_unlock_irqrestore(&par->DAClock, flags);
1074	}
1075
1076	/* Not supported so we fake it */
1077	if (cursor->set && FB_CUR_SETHOT) {
1078		info->cursor.hot.x = cursor->hot.x;
1079		info->cursor.hot.y = cursor->hot.y;
1080	}
1081
1082	if (cursor->set && FB_CUR_SETSHAPE) {
1083		/*
1084	 	 * Voodoo 3 and above cards use 2 monochrome cursor patterns.
1085		 *    The reason is so the card can fetch 8 words at a time
1086		 * and are stored on chip for use for the next 8 scanlines.
1087		 * This reduces the number of times for access to draw the
1088		 * cursor for each screen refresh.
1089		 *    Each pattern is a bitmap of 64 bit wide and 64 bit high
1090		 * (total of 8192 bits or 1024 Kbytes). The two patterns are
1091		 * stored in such a way that pattern 0 always resides in the
1092		 * lower half (least significant 64 bits) of a 128 bit word
1093		 * and pattern 1 the upper half. If you examine the data of
1094		 * the cursor image the graphics card uses then from the
1095		 * begining you see line one of pattern 0, line one of
1096		 * pattern 1, line two of pattern 0, line two of pattern 1,
1097		 * etc etc. The linear stride for the cursor is always 16 bytes
1098		 * (128 bits) which is the maximum cursor width times two for
1099		 * the two monochrome patterns.
1100		 */
1101		u8 *cursorbase = (u8 *) info->cursor.image.data;
1102		char *bitmap = (char *)cursor->image.data;
1103		char *mask = (char *) cursor->mask;
1104		int i, j, k, h = 0;
1105
1106		for (i = 0; i < 64; i++) {
1107			if (i < cursor->image.height) {
1108				j = (cursor->image.width + 7) >> 3;
1109				k = 8 - j;
1110
1111				for (;j > 0; j--) {
1112				/* Pattern 0. Copy the cursor bitmap to it */
1113					fb_writeb(*bitmap, cursorbase + h);
1114					bitmap++;
1115				/* Pattern 1. Copy the cursor mask to it */
1116					fb_writeb(*mask, cursorbase + h + 8);
1117					mask++;
1118					h++;
1119				}
1120				for (;k > 0; k--) {
1121					fb_writeb(0, cursorbase + h);
1122					fb_writeb(~0, cursorbase + h + 8);
1123					h++;
1124				}
1125			} else {
1126				fb_writel(0, cursorbase + h);
1127				fb_writel(0, cursorbase + h + 4);
1128				fb_writel(~0, cursorbase + h + 8);
1129				fb_writel(~0, cursorbase + h + 12);
1130				h += 16;
1131			}
1132		}
1133	}
1134	/* Turn the cursor on */
1135	cursor->enable = 1;
1136	info->cursor = *cursor;
1137	mod_timer(&par->hwcursor.timer, jiffies+HZ/2);
1138	spin_lock_irqsave(&par->DAClock, flags);
1139	banshee_make_room(par, 1);
1140	tdfx_outl(par, VIDPROCCFG, par->hwcursor.enable);
1141	spin_unlock_irqrestore(&par->DAClock, flags);
1142	return 0;
1143}
1144#endif
1145
1146/**
1147 *      tdfxfb_probe - Device Initializiation
1148 *
1149 *      @pdev:  PCI Device to initialize
1150 *      @id:    PCI Device ID
1151 *
1152 *      Initializes and allocates resources for PCI device @pdev.
1153 *
1154 */
1155static int __devinit tdfxfb_probe(struct pci_dev *pdev,
1156                                  const struct pci_device_id *id)
1157{
1158	struct tdfx_par *default_par;
1159	struct fb_info *info;
1160	int err, lpitch;
1161
1162	if ((err = pci_enable_device(pdev))) {
1163		printk(KERN_WARNING "tdfxfb: Can't enable pdev: %d\n", err);
1164		return err;
1165	}
1166
1167	info = framebuffer_alloc(sizeof(struct tdfx_par), &pdev->dev);
1168
1169	if (!info)
1170		return -ENOMEM;
1171
1172	default_par = info->par;
1173
1174	/* Configure the default fb_fix_screeninfo first */
1175	switch (pdev->device) {
1176		case PCI_DEVICE_ID_3DFX_BANSHEE:
1177			strcat(tdfx_fix.id, " Banshee");
1178			default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK;
1179			break;
1180		case PCI_DEVICE_ID_3DFX_VOODOO3:
1181			strcat(tdfx_fix.id, " Voodoo3");
1182			default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK;
1183			break;
1184		case PCI_DEVICE_ID_3DFX_VOODOO5:
1185			strcat(tdfx_fix.id, " Voodoo5");
1186			default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK;
1187			break;
1188	}
1189
1190	tdfx_fix.mmio_start = pci_resource_start(pdev, 0);
1191	tdfx_fix.mmio_len = pci_resource_len(pdev, 0);
1192	default_par->regbase_virt = ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len);
1193	if (!default_par->regbase_virt) {
1194		printk("fb: Can't remap %s register area.\n", tdfx_fix.id);
1195		goto out_err;
1196	}
1197
1198	if (!request_mem_region(pci_resource_start(pdev, 0),
1199	    pci_resource_len(pdev, 0), "tdfx regbase")) {
1200		printk(KERN_WARNING "tdfxfb: Can't reserve regbase\n");
1201		goto out_err;
1202	}
1203
1204	tdfx_fix.smem_start = pci_resource_start(pdev, 1);
1205	if (!(tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device))) {
1206		printk("fb: Can't count %s memory.\n", tdfx_fix.id);
1207		release_mem_region(pci_resource_start(pdev, 0),
1208				   pci_resource_len(pdev, 0));
1209		goto out_err;
1210	}
1211
1212	if (!request_mem_region(pci_resource_start(pdev, 1),
1213	     pci_resource_len(pdev, 1), "tdfx smem")) {
1214		printk(KERN_WARNING "tdfxfb: Can't reserve smem\n");
1215		release_mem_region(pci_resource_start(pdev, 0),
1216				   pci_resource_len(pdev, 0));
1217		goto out_err;
1218	}
1219
1220	info->screen_base = ioremap_nocache(tdfx_fix.smem_start,
1221					    tdfx_fix.smem_len);
1222	if (!info->screen_base) {
1223		printk("fb: Can't remap %s framebuffer.\n", tdfx_fix.id);
1224		release_mem_region(pci_resource_start(pdev, 1),
1225				   pci_resource_len(pdev, 1));
1226		release_mem_region(pci_resource_start(pdev, 0),
1227				   pci_resource_len(pdev, 0));
1228		goto out_err;
1229	}
1230
1231	default_par->iobase = pci_resource_start(pdev, 2);
1232
1233	if (!request_region(pci_resource_start(pdev, 2),
1234	    pci_resource_len(pdev, 2), "tdfx iobase")) {
1235		printk(KERN_WARNING "tdfxfb: Can't reserve iobase\n");
1236		release_mem_region(pci_resource_start(pdev, 1),
1237				   pci_resource_len(pdev, 1));
1238		release_mem_region(pci_resource_start(pdev, 0),
1239				   pci_resource_len(pdev, 0));
1240		goto out_err;
1241	}
1242
1243	printk("fb: %s memory = %dK\n", tdfx_fix.id, tdfx_fix.smem_len >> 10);
1244
1245	tdfx_fix.ypanstep	= nopan ? 0 : 1;
1246	tdfx_fix.ywrapstep	= nowrap ? 0 : 1;
1247
1248	info->fbops		= &tdfxfb_ops;
1249	info->fix		= tdfx_fix;
1250	info->pseudo_palette	= default_par->palette;
1251	info->flags		= FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1252#ifdef CONFIG_FB_3DFX_ACCEL
1253	info->flags             |= FBINFO_HWACCEL_FILLRECT |
1254		FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_IMAGEBLIT;
1255#endif
1256
1257	if (!mode_option)
1258		mode_option = "640x480@60";
1259
1260	err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
1261	if (!err || err == 4)
1262		info->var = tdfx_var;
1263
1264	/* maximize virtual vertical length */
1265	lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3);
1266	info->var.yres_virtual = info->fix.smem_len/lpitch;
1267	if (info->var.yres_virtual < info->var.yres)
1268		goto out_err;
1269
1270#ifdef CONFIG_FB_3DFX_ACCEL
1271	if (info->var.yres_virtual > 4096)
1272		info->var.yres_virtual = 4096;
1273#endif /* CONFIG_FB_3DFX_ACCEL */
1274
1275	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
1276		printk(KERN_WARNING "tdfxfb: Can't allocate color map\n");
1277		goto out_err;
1278	}
1279
1280	if (register_framebuffer(info) < 0) {
1281		printk("tdfxfb: can't register framebuffer\n");
1282		fb_dealloc_cmap(&info->cmap);
1283		goto out_err;
1284	}
1285	/*
1286	 * Our driver data
1287	 */
1288	pci_set_drvdata(pdev, info);
1289	return 0;
1290
1291out_err:
1292	/*
1293	 * Cleanup after anything that was remapped/allocated.
1294	 */
1295	if (default_par->regbase_virt)
1296		iounmap(default_par->regbase_virt);
1297	if (info->screen_base)
1298		iounmap(info->screen_base);
1299	framebuffer_release(info);
1300	return -ENXIO;
1301}
1302
1303#ifndef MODULE
1304static void tdfxfb_setup(char *options)
1305{
1306	char* this_opt;
1307
1308	if (!options || !*options)
1309		return;
1310
1311	while ((this_opt = strsep(&options, ",")) != NULL) {
1312		if (!*this_opt)
1313			continue;
1314		if(!strcmp(this_opt, "nopan")) {
1315			nopan = 1;
1316		} else if(!strcmp(this_opt, "nowrap")) {
1317			nowrap = 1;
1318		} else {
1319			mode_option = this_opt;
1320		}
1321	}
1322}
1323#endif
1324
1325/**
1326 *      tdfxfb_remove - Device removal
1327 *
1328 *      @pdev:  PCI Device to cleanup
1329 *
1330 *      Releases all resources allocated during the course of the driver's
1331 *      lifetime for the PCI device @pdev.
1332 *
1333 */
1334static void __devexit tdfxfb_remove(struct pci_dev *pdev)
1335{
1336	struct fb_info *info = pci_get_drvdata(pdev);
1337	struct tdfx_par *par = info->par;
1338
1339	unregister_framebuffer(info);
1340	iounmap(par->regbase_virt);
1341	iounmap(info->screen_base);
1342
1343	/* Clean up after reserved regions */
1344	release_region(pci_resource_start(pdev, 2),
1345		       pci_resource_len(pdev, 2));
1346	release_mem_region(pci_resource_start(pdev, 1),
1347			   pci_resource_len(pdev, 1));
1348	release_mem_region(pci_resource_start(pdev, 0),
1349			   pci_resource_len(pdev, 0));
1350	pci_set_drvdata(pdev, NULL);
1351	framebuffer_release(info);
1352}
1353
1354static int __init tdfxfb_init(void)
1355{
1356#ifndef MODULE
1357	char *option = NULL;
1358
1359	if (fb_get_options("tdfxfb", &option))
1360		return -ENODEV;
1361
1362	tdfxfb_setup(option);
1363#endif
1364        return pci_register_driver(&tdfxfb_driver);
1365}
1366
1367static void __exit tdfxfb_exit(void)
1368{
1369        pci_unregister_driver(&tdfxfb_driver);
1370}
1371
1372MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>");
1373MODULE_DESCRIPTION("3Dfx framebuffer device driver");
1374MODULE_LICENSE("GPL");
1375
1376module_init(tdfxfb_init);
1377module_exit(tdfxfb_exit);
1378