brintos

brintos / linux-shallow public Read only

0
0
Text · 42.2 KiB · 51ebe78 Raw
1667 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *4 * tdfxfb.c5 *6 * Author: Hannu Mallat <hmallat@cc.hut.fi>7 *8 * Copyright © 1999 Hannu Mallat9 * All rights reserved10 *11 * Created      : Thu Sep 23 18:17:43 1999, hmallat12 * Last modified: Tue Nov  2 21:19:47 1999, hmallat13 *14 * I2C part copied from the i2c-voodoo3.c driver by:15 * Frodo Looijaard <frodol@dds.nl>,16 * Philip Edelbrock <phil@netroedge.com>,17 * Ralph Metzler <rjkm@thp.uni-koeln.de>, and18 * Mark D. Studebaker <mdsxyz123@yahoo.com>19 *20 * Lots of the information here comes from the Daryll Strauss' Banshee21 * patches to the XF86 server, and the rest comes from the 3dfx22 * Banshee specification. I'm very much indebted to Daryll for his23 * work on the X server.24 *25 * Voodoo3 support was contributed Harold Oga. Lots of additions26 * (proper acceleration, 24 bpp, hardware cursor) and bug fixes by Attila27 * Kesmarki. Thanks guys!28 *29 * Voodoo1 and Voodoo2 support aren't relevant to this driver as they30 * behave very differently from the Voodoo3/4/5. For anyone wanting to31 * use frame buffer on the Voodoo1/2, see the sstfb driver (which is32 * located at http://www.sourceforge.net/projects/sstfb).33 *34 * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,35 * I do wish the next version is a bit more complete. Without the XF8636 * patches I couldn't have gotten even this far... for instance, the37 * extensions to the VGA register set go completely unmentioned in the38 * spec! Also, lots of references are made to the 'SST core', but no39 * spec is publicly available, AFAIK.40 *41 * The structure of this driver comes pretty much from the Permedia42 * driver by Ilario Nardinocchi, which in turn is based on skeletonfb.43 *44 * TODO:45 * - multihead support (basically need to support an array of fb_infos)46 * - support other architectures (PPC, Alpha); does the fact that the VGA47 *   core can be accessed only thru I/O (not memory mapped) complicate48 *   things?49 *50 * Version history:51 *52 * 0.1.4 (released 2002-05-28)	ported over to new fbdev api by James Simmons53 *54 * 0.1.3 (released 1999-11-02)	added Attila's panning support, code55 *				reorg, hwcursor address page size alignment56 *				(for mmapping both frame buffer and regs),57 *				and my changes to get rid of hardcoded58 *				VGA i/o register locations (uses PCI59 *				configuration info now)60 * 0.1.2 (released 1999-10-19)	added Attila Kesmarki's bug fixes and61 *				improvements62 * 0.1.1 (released 1999-10-07)	added Voodoo3 support by Harold Oga.63 * 0.1.0 (released 1999-10-06)	initial version64 *65 */66 67#include <linux/aperture.h>68#include <linux/module.h>69#include <linux/kernel.h>70#include <linux/errno.h>71#include <linux/string.h>72#include <linux/mm.h>73#include <linux/slab.h>74#include <linux/fb.h>75#include <linux/init.h>76#include <linux/pci.h>77#include <asm/io.h>78 79#include <video/tdfx.h>80 81#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __func__ , ## b)82 83#define BANSHEE_MAX_PIXCLOCK 27000084#define VOODOO3_MAX_PIXCLOCK 30000085#define VOODOO5_MAX_PIXCLOCK 35000086 87static const struct fb_fix_screeninfo tdfx_fix = {88	.type =		FB_TYPE_PACKED_PIXELS,89	.visual =	FB_VISUAL_PSEUDOCOLOR,90	.ypanstep =	1,91	.ywrapstep =	1,92	.accel =	FB_ACCEL_3DFX_BANSHEE93};94 95static const struct fb_var_screeninfo tdfx_var = {96	/* "640x480, 8 bpp @ 60 Hz */97	.xres =		640,98	.yres =		480,99	.xres_virtual =	640,100	.yres_virtual =	1024,101	.bits_per_pixel = 8,102	.red =		{0, 8, 0},103	.blue =		{0, 8, 0},104	.green =	{0, 8, 0},105	.activate =	FB_ACTIVATE_NOW,106	.height =	-1,107	.width =	-1,108	.accel_flags =	FB_ACCELF_TEXT,109	.pixclock =	39722,110	.left_margin =	40,111	.right_margin =	24,112	.upper_margin =	32,113	.lower_margin =	11,114	.hsync_len =	96,115	.vsync_len =	2,116	.vmode =	FB_VMODE_NONINTERLACED117};118 119/*120 * PCI driver prototypes121 */122static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id);123static void tdfxfb_remove(struct pci_dev *pdev);124 125static const struct pci_device_id tdfxfb_id_table[] = {126	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE,127	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,128	  0xff0000, 0 },129	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3,130	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,131	  0xff0000, 0 },132	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5,133	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,134	  0xff0000, 0 },135	{ 0, }136};137 138static struct pci_driver tdfxfb_driver = {139	.name		= "tdfxfb",140	.id_table	= tdfxfb_id_table,141	.probe		= tdfxfb_probe,142	.remove		= tdfxfb_remove,143};144 145MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);146 147/*148 * Driver data149 */150static int nopan;151static int nowrap = 1;      /* not implemented (yet) */152static int hwcursor = 1;153static char *mode_option;154static bool nomtrr;155 156/* -------------------------------------------------------------------------157 *			Hardware-specific funcions158 * ------------------------------------------------------------------------- */159 160static inline u8 vga_inb(struct tdfx_par *par, u32 reg)161{162	return inb(par->iobase + reg - 0x300);163}164 165static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val)166{167	outb(val, par->iobase + reg - 0x300);168}169 170static inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val)171{172	vga_outb(par, GRA_I, idx);173	wmb();174	vga_outb(par, GRA_D, val);175	wmb();176}177 178static inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val)179{180	vga_outb(par, SEQ_I, idx);181	wmb();182	vga_outb(par, SEQ_D, val);183	wmb();184}185 186static inline u8 seq_inb(struct tdfx_par *par, u32 idx)187{188	vga_outb(par, SEQ_I, idx);189	mb();190	return vga_inb(par, SEQ_D);191}192 193static inline void crt_outb(struct tdfx_par *par, u32 idx, u8 val)194{195	vga_outb(par, CRT_I, idx);196	wmb();197	vga_outb(par, CRT_D, val);198	wmb();199}200 201static inline u8 crt_inb(struct tdfx_par *par, u32 idx)202{203	vga_outb(par, CRT_I, idx);204	mb();205	return vga_inb(par, CRT_D);206}207 208static inline void att_outb(struct tdfx_par *par, u32 idx, u8 val)209{210	vga_inb(par, IS1_R);211	vga_outb(par, ATT_IW, idx);212	vga_outb(par, ATT_IW, val);213}214 215static inline void vga_disable_video(struct tdfx_par *par)216{217	unsigned char s;218 219	s = seq_inb(par, 0x01) | 0x20;220	seq_outb(par, 0x00, 0x01);221	seq_outb(par, 0x01, s);222	seq_outb(par, 0x00, 0x03);223}224 225static inline void vga_enable_video(struct tdfx_par *par)226{227	unsigned char s;228 229	s = seq_inb(par, 0x01) & 0xdf;230	seq_outb(par, 0x00, 0x01);231	seq_outb(par, 0x01, s);232	seq_outb(par, 0x00, 0x03);233}234 235static inline void vga_enable_palette(struct tdfx_par *par)236{237	vga_inb(par, IS1_R);238	mb();239	vga_outb(par, ATT_IW, 0x20);240}241 242static inline u32 tdfx_inl(struct tdfx_par *par, unsigned int reg)243{244	return readl(par->regbase_virt + reg);245}246 247static inline void tdfx_outl(struct tdfx_par *par, unsigned int reg, u32 val)248{249	writel(val, par->regbase_virt + reg);250}251 252static inline void banshee_make_room(struct tdfx_par *par, int size)253{254	/* Note: The Voodoo3's onboard FIFO has 32 slots. This loop255	 * won't quit if you ask for more. */256	while ((tdfx_inl(par, STATUS) & 0x1f) < size - 1)257		cpu_relax();258}259 260static int banshee_wait_idle(struct fb_info *info)261{262	struct tdfx_par *par = info->par;263	int i = 0;264 265	banshee_make_room(par, 1);266	tdfx_outl(par, COMMAND_3D, COMMAND_3D_NOP);267 268	do {269		if ((tdfx_inl(par, STATUS) & STATUS_BUSY) == 0)270			i++;271	} while (i < 3);272 273	return 0;274}275 276/*277 * Set the color of a palette entry in 8bpp mode278 */279static inline void do_setpalentry(struct tdfx_par *par, unsigned regno, u32 c)280{281	banshee_make_room(par, 2);282	tdfx_outl(par, DACADDR, regno);283	/* read after write makes it working */284	tdfx_inl(par, DACADDR);285	tdfx_outl(par, DACDATA, c);286}287 288static u32 do_calc_pll(int freq, int *freq_out)289{290	int m, n, k, best_m, best_n, best_k, best_error;291	int fref = 14318;292 293	best_error = freq;294	best_n = best_m = best_k = 0;295 296	for (k = 3; k >= 0; k--) {297		for (m = 63; m >= 0; m--) {298			/*299			 * Estimate value of n that produces target frequency300			 * with current m and k301			 */302			int n_estimated = ((freq * (m + 2) << k) / fref) - 2;303 304			/* Search neighborhood of estimated n */305			for (n = max(0, n_estimated);306				n <= min(255, n_estimated + 1);307				n++) {308				/*309				 * Calculate PLL freqency with current m, k and310				 * estimated n311				 */312				int f = (fref * (n + 2) / (m + 2)) >> k;313				int error = abs(f - freq);314 315				/*316				 * If this is the closest we've come to the317				 * target frequency then remember n, m and k318				 */319				if (error < best_error) {320					best_error = error;321					best_n = n;322					best_m = m;323					best_k = k;324				}325			}326		}327	}328 329	n = best_n;330	m = best_m;331	k = best_k;332	*freq_out = (fref * (n + 2) / (m + 2)) >> k;333 334	return (n << 8) | (m << 2) | k;335}336 337static void do_write_regs(struct fb_info *info, struct banshee_reg *reg)338{339	struct tdfx_par *par = info->par;340	int i;341 342	banshee_wait_idle(info);343 344	tdfx_outl(par, MISCINIT1, tdfx_inl(par, MISCINIT1) | 0x01);345 346	crt_outb(par, 0x11, crt_inb(par, 0x11) & 0x7f); /* CRT unprotect */347 348	banshee_make_room(par, 3);349	tdfx_outl(par, VGAINIT1, reg->vgainit1 & 0x001FFFFF);350	tdfx_outl(par, VIDPROCCFG, reg->vidcfg & ~0x00000001);351#if 0352	tdfx_outl(par, PLLCTRL1, reg->mempll);353	tdfx_outl(par, PLLCTRL2, reg->gfxpll);354#endif355	tdfx_outl(par, PLLCTRL0, reg->vidpll);356 357	vga_outb(par, MISC_W, reg->misc[0x00] | 0x01);358 359	for (i = 0; i < 5; i++)360		seq_outb(par, i, reg->seq[i]);361 362	for (i = 0; i < 25; i++)363		crt_outb(par, i, reg->crt[i]);364 365	for (i = 0; i < 9; i++)366		gra_outb(par, i, reg->gra[i]);367 368	for (i = 0; i < 21; i++)369		att_outb(par, i, reg->att[i]);370 371	crt_outb(par, 0x1a, reg->ext[0]);372	crt_outb(par, 0x1b, reg->ext[1]);373 374	vga_enable_palette(par);375	vga_enable_video(par);376 377	banshee_make_room(par, 9);378	tdfx_outl(par, VGAINIT0, reg->vgainit0);379	tdfx_outl(par, DACMODE, reg->dacmode);380	tdfx_outl(par, VIDDESKSTRIDE, reg->stride);381	tdfx_outl(par, HWCURPATADDR, reg->curspataddr);382 383	tdfx_outl(par, VIDSCREENSIZE, reg->screensize);384	tdfx_outl(par, VIDDESKSTART, reg->startaddr);385	tdfx_outl(par, VIDPROCCFG, reg->vidcfg);386	tdfx_outl(par, VGAINIT1, reg->vgainit1);387	tdfx_outl(par, MISCINIT0, reg->miscinit0);388 389	banshee_make_room(par, 8);390	tdfx_outl(par, SRCBASE, reg->startaddr);391	tdfx_outl(par, DSTBASE, reg->startaddr);392	tdfx_outl(par, COMMANDEXTRA_2D, 0);393	tdfx_outl(par, CLIP0MIN, 0);394	tdfx_outl(par, CLIP0MAX, 0x0fff0fff);395	tdfx_outl(par, CLIP1MIN, 0);396	tdfx_outl(par, CLIP1MAX, 0x0fff0fff);397	tdfx_outl(par, SRCXY, 0);398 399	banshee_wait_idle(info);400}401 402static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id)403{404	u32 draminit0 = tdfx_inl(par, DRAMINIT0);405	u32 draminit1 = tdfx_inl(par, DRAMINIT1);406	u32 miscinit1;407	int num_chips = (draminit0 & DRAMINIT0_SGRAM_NUM) ? 8 : 4;408	int chip_size; /* in MB */409	int has_sgram = draminit1 & DRAMINIT1_MEM_SDRAM;410 411	if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) {412		/* Banshee/Voodoo3 */413		chip_size = 2;414		if (has_sgram && !(draminit0 & DRAMINIT0_SGRAM_TYPE))415			chip_size = 1;416	} else {417		/* Voodoo4/5 */418		has_sgram = 0;419		chip_size = draminit0 & DRAMINIT0_SGRAM_TYPE_MASK;420		chip_size = 1 << (chip_size >> DRAMINIT0_SGRAM_TYPE_SHIFT);421	}422 423	/* disable block writes for SDRAM */424	miscinit1 = tdfx_inl(par, MISCINIT1);425	miscinit1 |= has_sgram ? 0 : MISCINIT1_2DBLOCK_DIS;426	miscinit1 |= MISCINIT1_CLUT_INV;427 428	banshee_make_room(par, 1);429	tdfx_outl(par, MISCINIT1, miscinit1);430	return num_chips * chip_size * 1024l * 1024;431}432 433/* ------------------------------------------------------------------------- */434 435static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)436{437	struct tdfx_par *par = info->par;438	u32 lpitch;439 440	if (var->bits_per_pixel != 8  && var->bits_per_pixel != 16 &&441	    var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {442		DPRINTK("depth not supported: %u\n", var->bits_per_pixel);443		return -EINVAL;444	}445 446	if (var->xres != var->xres_virtual)447		var->xres_virtual = var->xres;448 449	if (var->yres > var->yres_virtual)450		var->yres_virtual = var->yres;451 452	if (var->xoffset) {453		DPRINTK("xoffset not supported\n");454		return -EINVAL;455	}456	var->yoffset = 0;457 458	/*459	 * Banshee doesn't support interlace, but Voodoo4/5 and probably460	 * Voodoo3 do.461	 * no direct information about device id now?462	 *  use max_pixclock for this...463	 */464	if (((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) &&465	    (par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) {466		DPRINTK("interlace not supported\n");467		return -EINVAL;468	}469 470	if (info->monspecs.hfmax && info->monspecs.vfmax &&471	    info->monspecs.dclkmax && fb_validate_mode(var, info) < 0) {472		DPRINTK("mode outside monitor's specs\n");473		return -EINVAL;474	}475 476	var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */477	lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);478 479	if (var->xres < 320 || var->xres > 2048) {480		DPRINTK("width not supported: %u\n", var->xres);481		return -EINVAL;482	}483 484	if (var->yres < 200 || var->yres > 2048) {485		DPRINTK("height not supported: %u\n", var->yres);486		return -EINVAL;487	}488 489	if (lpitch * var->yres_virtual > info->fix.smem_len) {490		var->yres_virtual = info->fix.smem_len / lpitch;491		if (var->yres_virtual < var->yres) {492			DPRINTK("no memory for screen (%ux%ux%u)\n",493				var->xres, var->yres_virtual,494				var->bits_per_pixel);495			return -EINVAL;496		}497	}498 499	if (PICOS2KHZ(var->pixclock) > par->max_pixclock) {500		DPRINTK("pixclock too high (%ldKHz)\n",501			PICOS2KHZ(var->pixclock));502		return -EINVAL;503	}504 505	var->transp.offset = 0;506	var->transp.length = 0;507	switch (var->bits_per_pixel) {508	case 8:509		var->red.length = 8;510		var->red.offset = 0;511		var->green = var->red;512		var->blue = var->red;513		break;514	case 16:515		var->red.offset   = 11;516		var->red.length   = 5;517		var->green.offset = 5;518		var->green.length = 6;519		var->blue.offset  = 0;520		var->blue.length  = 5;521		break;522	case 32:523		var->transp.offset = 24;524		var->transp.length = 8;525		fallthrough;526	case 24:527		var->red.offset = 16;528		var->green.offset = 8;529		var->blue.offset = 0;530		var->red.length = var->green.length = var->blue.length = 8;531		break;532	}533	var->width = -1;534	var->height = -1;535 536	var->accel_flags = FB_ACCELF_TEXT;537 538	DPRINTK("Checking graphics mode at %dx%d depth %d\n",539		var->xres, var->yres, var->bits_per_pixel);540	return 0;541}542 543static int tdfxfb_set_par(struct fb_info *info)544{545	struct tdfx_par *par = info->par;546	u32 hdispend = info->var.xres;547	u32 hsyncsta = hdispend + info->var.right_margin;548	u32 hsyncend = hsyncsta + info->var.hsync_len;549	u32 htotal   = hsyncend + info->var.left_margin;550	u32 hd, hs, he, ht, hbs, hbe;551	u32 vd, vs, ve, vt, vbs, vbe;552	struct banshee_reg reg;553	int fout, freq;554	u32 wd;555	u32 cpp = (info->var.bits_per_pixel + 7) >> 3;556 557	memset(&reg, 0, sizeof(reg));558 559	reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE |560		     VIDCFG_CURS_X11 |561		     ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |562		     (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);563 564	/* PLL settings */565	freq = PICOS2KHZ(info->var.pixclock);566 567	reg.vidcfg &= ~VIDCFG_2X;568 569	if (freq > par->max_pixclock / 2) {570		freq = freq > par->max_pixclock ? par->max_pixclock : freq;571		reg.dacmode |= DACMODE_2X;572		reg.vidcfg  |= VIDCFG_2X;573		hdispend >>= 1;574		hsyncsta >>= 1;575		hsyncend >>= 1;576		htotal   >>= 1;577	}578 579	wd = (hdispend >> 3) - 1;580	hd  = wd;581	hs  = (hsyncsta >> 3) - 1;582	he  = (hsyncend >> 3) - 1;583	ht  = (htotal >> 3) - 1;584	hbs = hd;585	hbe = ht;586 587	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {588		vd = (info->var.yres << 1) - 1;589		vs  = vd + (info->var.lower_margin << 1);590		ve  = vs + (info->var.vsync_len << 1);591		vt = ve + (info->var.upper_margin << 1) - 1;592		reg.screensize = info->var.xres | (info->var.yres << 13);593		reg.vidcfg |= VIDCFG_HALF_MODE;594		reg.crt[0x09] = 0x80;595	} else {596		vd = info->var.yres - 1;597		vs  = vd + info->var.lower_margin;598		ve  = vs + info->var.vsync_len;599		vt = ve + info->var.upper_margin - 1;600		reg.screensize = info->var.xres | (info->var.yres << 12);601		reg.vidcfg &= ~VIDCFG_HALF_MODE;602	}603	vbs = vd;604	vbe = vt;605 606	/* this is all pretty standard VGA register stuffing */607	reg.misc[0x00] = 0x0f |608			(info->var.xres < 400 ? 0xa0 :609			 info->var.xres < 480 ? 0x60 :610			 info->var.xres < 768 ? 0xe0 : 0x20);611 612	reg.gra[0x05] = 0x40;613	reg.gra[0x06] = 0x05;614	reg.gra[0x07] = 0x0f;615	reg.gra[0x08] = 0xff;616 617	reg.att[0x00] = 0x00;618	reg.att[0x01] = 0x01;619	reg.att[0x02] = 0x02;620	reg.att[0x03] = 0x03;621	reg.att[0x04] = 0x04;622	reg.att[0x05] = 0x05;623	reg.att[0x06] = 0x06;624	reg.att[0x07] = 0x07;625	reg.att[0x08] = 0x08;626	reg.att[0x09] = 0x09;627	reg.att[0x0a] = 0x0a;628	reg.att[0x0b] = 0x0b;629	reg.att[0x0c] = 0x0c;630	reg.att[0x0d] = 0x0d;631	reg.att[0x0e] = 0x0e;632	reg.att[0x0f] = 0x0f;633	reg.att[0x10] = 0x41;634	reg.att[0x12] = 0x0f;635 636	reg.seq[0x00] = 0x03;637	reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */638	reg.seq[0x02] = 0x0f;639	reg.seq[0x03] = 0x00;640	reg.seq[0x04] = 0x0e;641 642	reg.crt[0x00] = ht - 4;643	reg.crt[0x01] = hd;644	reg.crt[0x02] = hbs;645	reg.crt[0x03] = 0x80 | (hbe & 0x1f);646	reg.crt[0x04] = hs;647	reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);648	reg.crt[0x06] = vt;649	reg.crt[0x07] = ((vs & 0x200) >> 2) |650			((vd & 0x200) >> 3) |651			((vt & 0x200) >> 4) | 0x10 |652			((vbs & 0x100) >> 5) |653			((vs & 0x100) >> 6) |654			((vd & 0x100) >> 7) |655			((vt & 0x100) >> 8);656	reg.crt[0x09] |= 0x40 | ((vbs & 0x200) >> 4);657	reg.crt[0x10] = vs;658	reg.crt[0x11] = (ve & 0x0f) | 0x20;659	reg.crt[0x12] = vd;660	reg.crt[0x13] = wd;661	reg.crt[0x15] = vbs;662	reg.crt[0x16] = vbe + 1;663	reg.crt[0x17] = 0xc3;664	reg.crt[0x18] = 0xff;665 666	/* Banshee's nonvga stuff */667	reg.ext[0x00] = (((ht & 0x100) >> 8) |668			((hd & 0x100) >> 6) |669			((hbs & 0x100) >> 4) |670			((hbe & 0x40) >> 1) |671			((hs & 0x100) >> 2) |672			((he & 0x20) << 2));673	reg.ext[0x01] = (((vt & 0x400) >> 10) |674			((vd & 0x400) >> 8) |675			((vbs & 0x400) >> 6) |676			((vbe & 0x400) >> 4));677 678	reg.vgainit0 =	VGAINIT0_8BIT_DAC     |679			VGAINIT0_EXT_ENABLE   |680			VGAINIT0_WAKEUP_3C3   |681			VGAINIT0_ALT_READBACK |682			VGAINIT0_EXTSHIFTOUT;683	reg.vgainit1 = tdfx_inl(par, VGAINIT1) & 0x1fffff;684 685	if (hwcursor)686		reg.curspataddr = info->fix.smem_len;687 688	reg.cursloc   = 0;689 690	reg.cursc0    = 0;691	reg.cursc1    = 0xffffff;692 693	reg.stride    = info->var.xres * cpp;694	reg.startaddr = info->var.yoffset * reg.stride695			+ info->var.xoffset * cpp;696 697	reg.vidpll = do_calc_pll(freq, &fout);698#if 0699	reg.mempll = do_calc_pll(..., &fout);700	reg.gfxpll = do_calc_pll(..., &fout);701#endif702 703	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)704		reg.vidcfg |= VIDCFG_INTERLACE;705	reg.miscinit0 = tdfx_inl(par, MISCINIT0);706 707#if defined(__BIG_ENDIAN)708	switch (info->var.bits_per_pixel) {709	case 8:710	case 24:711		reg.miscinit0 &= ~(1 << 30);712		reg.miscinit0 &= ~(1 << 31);713		break;714	case 16:715		reg.miscinit0 |= (1 << 30);716		reg.miscinit0 |= (1 << 31);717		break;718	case 32:719		reg.miscinit0 |= (1 << 30);720		reg.miscinit0 &= ~(1 << 31);721		break;722	}723#endif724	do_write_regs(info, &reg);725 726	/* Now change fb_fix_screeninfo according to changes in par */727	info->fix.line_length = reg.stride;728	info->fix.visual = (info->var.bits_per_pixel == 8)729				? FB_VISUAL_PSEUDOCOLOR730				: FB_VISUAL_TRUECOLOR;731	DPRINTK("Graphics mode is now set at %dx%d depth %d\n",732		info->var.xres, info->var.yres, info->var.bits_per_pixel);733	return 0;734}735 736/* A handy macro shamelessly pinched from matroxfb */737#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)738 739static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green,740			    unsigned blue, unsigned transp,741			    struct fb_info *info)742{743	struct tdfx_par *par = info->par;744	u32 rgbcol;745 746	if (regno >= info->cmap.len || regno > 255)747		return 1;748 749	/* grayscale works only partially under directcolor */750	if (info->var.grayscale) {751		/* grayscale = 0.30*R + 0.59*G + 0.11*B */752		blue = (red * 77 + green * 151 + blue * 28) >> 8;753		green = blue;754		red = blue;755	}756 757	switch (info->fix.visual) {758	case FB_VISUAL_PSEUDOCOLOR:759		rgbcol = (((u32)red   & 0xff00) << 8) |760			 (((u32)green & 0xff00) << 0) |761			 (((u32)blue  & 0xff00) >> 8);762		do_setpalentry(par, regno, rgbcol);763		break;764	/* Truecolor has no hardware color palettes. */765	case FB_VISUAL_TRUECOLOR:766		if (regno < 16) {767			rgbcol = (CNVT_TOHW(red, info->var.red.length) <<768				  info->var.red.offset) |769				(CNVT_TOHW(green, info->var.green.length) <<770				 info->var.green.offset) |771				(CNVT_TOHW(blue, info->var.blue.length) <<772				 info->var.blue.offset) |773				(CNVT_TOHW(transp, info->var.transp.length) <<774				 info->var.transp.offset);775			par->palette[regno] = rgbcol;776		}777 778		break;779	default:780		DPRINTK("bad depth %u\n", info->var.bits_per_pixel);781		break;782	}783 784	return 0;785}786 787/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */788static int tdfxfb_blank(int blank, struct fb_info *info)789{790	struct tdfx_par *par = info->par;791	int vgablank = 1;792	u32 dacmode = tdfx_inl(par, DACMODE);793 794	dacmode &= ~(BIT(1) | BIT(3));795 796	switch (blank) {797	case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */798		vgablank = 0;799		break;800	case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */801		break;802	case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */803		dacmode |= BIT(3);804		break;805	case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */806		dacmode |= BIT(1);807		break;808	case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */809		dacmode |= BIT(1) | BIT(3);810		break;811	}812 813	banshee_make_room(par, 1);814	tdfx_outl(par, DACMODE, dacmode);815	if (vgablank)816		vga_disable_video(par);817	else818		vga_enable_video(par);819	return 0;820}821 822/*823 * Set the starting position of the visible screen to var->yoffset824 */825static int tdfxfb_pan_display(struct fb_var_screeninfo *var,826			      struct fb_info *info)827{828	struct tdfx_par *par = info->par;829	u32 addr = var->yoffset * info->fix.line_length;830 831	if (nopan || var->xoffset)832		return -EINVAL;833 834	banshee_make_room(par, 1);835	tdfx_outl(par, VIDDESKSTART, addr);836 837	return 0;838}839 840#ifdef CONFIG_FB_3DFX_ACCEL841/*842 * FillRect 2D command (solidfill or invert (via ROP_XOR))843 */844static void tdfxfb_fillrect(struct fb_info *info,845			    const struct fb_fillrect *rect)846{847	struct tdfx_par *par = info->par;848	u32 bpp = info->var.bits_per_pixel;849	u32 stride = info->fix.line_length;850	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);851	int tdfx_rop;852	u32 dx = rect->dx;853	u32 dy = rect->dy;854	u32 dstbase = 0;855 856	if (rect->rop == ROP_COPY)857		tdfx_rop = TDFX_ROP_COPY;858	else859		tdfx_rop = TDFX_ROP_XOR;860 861	/* assume always rect->height < 4096 */862	if (dy + rect->height > 4095) {863		dstbase = stride * dy;864		dy = 0;865	}866	/* assume always rect->width < 4096 */867	if (dx + rect->width > 4095) {868		dstbase += dx * bpp >> 3;869		dx = 0;870	}871	banshee_make_room(par, 6);872	tdfx_outl(par, DSTFORMAT, fmt);873	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {874		tdfx_outl(par, COLORFORE, rect->color);875	} else { /* FB_VISUAL_TRUECOLOR */876		tdfx_outl(par, COLORFORE, par->palette[rect->color]);877	}878	tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24));879	tdfx_outl(par, DSTBASE, dstbase);880	tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16));881	tdfx_outl(par, LAUNCH_2D, dx | (dy << 16));882}883 884/*885 * Screen-to-Screen BitBlt 2D command (for the bmove fb op.)886 */887static void tdfxfb_copyarea(struct fb_info *info,888			    const struct fb_copyarea *area)889{890	struct tdfx_par *par = info->par;891	u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy;892	u32 bpp = info->var.bits_per_pixel;893	u32 stride = info->fix.line_length;894	u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);895	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);896	u32 dstbase = 0;897	u32 srcbase = 0;898 899	/* assume always area->height < 4096 */900	if (sy + area->height > 4095) {901		srcbase = stride * sy;902		sy = 0;903	}904	/* assume always area->width < 4096 */905	if (sx + area->width > 4095) {906		srcbase += sx * bpp >> 3;907		sx = 0;908	}909	/* assume always area->height < 4096 */910	if (dy + area->height > 4095) {911		dstbase = stride * dy;912		dy = 0;913	}914	/* assume always area->width < 4096 */915	if (dx + area->width > 4095) {916		dstbase += dx * bpp >> 3;917		dx = 0;918	}919 920	if (area->sx <= area->dx) {921		/* -X */922		blitcmd |= BIT(14);923		sx += area->width - 1;924		dx += area->width - 1;925	}926	if (area->sy <= area->dy) {927		/* -Y */928		blitcmd |= BIT(15);929		sy += area->height - 1;930		dy += area->height - 1;931	}932 933	banshee_make_room(par, 8);934 935	tdfx_outl(par, SRCFORMAT, fmt);936	tdfx_outl(par, DSTFORMAT, fmt);937	tdfx_outl(par, COMMAND_2D, blitcmd);938	tdfx_outl(par, DSTSIZE, area->width | (area->height << 16));939	tdfx_outl(par, DSTXY, dx | (dy << 16));940	tdfx_outl(par, SRCBASE, srcbase);941	tdfx_outl(par, DSTBASE, dstbase);942	tdfx_outl(par, LAUNCH_2D, sx | (sy << 16));943}944 945static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image)946{947	struct tdfx_par *par = info->par;948	int size = image->height * ((image->width * image->depth + 7) >> 3);949	int fifo_free;950	int i, stride = info->fix.line_length;951	u32 bpp = info->var.bits_per_pixel;952	u32 dstfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);953	u8 *chardata = (u8 *) image->data;954	u32 srcfmt;955	u32 dx = image->dx;956	u32 dy = image->dy;957	u32 dstbase = 0;958 959	if (image->depth != 1) {960#ifdef BROKEN_CODE961		banshee_make_room(par, 6 + ((size + 3) >> 2));962		srcfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13) |963			0x400000;964#else965		cfb_imageblit(info, image);966#endif967		return;968	}969	banshee_make_room(par, 9);970	switch (info->fix.visual) {971	case FB_VISUAL_PSEUDOCOLOR:972		tdfx_outl(par, COLORFORE, image->fg_color);973		tdfx_outl(par, COLORBACK, image->bg_color);974		break;975	case FB_VISUAL_TRUECOLOR:976	default:977		tdfx_outl(par, COLORFORE,978			  par->palette[image->fg_color]);979		tdfx_outl(par, COLORBACK,980			  par->palette[image->bg_color]);981	}982#ifdef __BIG_ENDIAN983	srcfmt = 0x400000 | BIT(20);984#else985	srcfmt = 0x400000;986#endif987	/* assume always image->height < 4096 */988	if (dy + image->height > 4095) {989		dstbase = stride * dy;990		dy = 0;991	}992	/* assume always image->width < 4096 */993	if (dx + image->width > 4095) {994		dstbase += dx * bpp >> 3;995		dx = 0;996	}997 998	tdfx_outl(par, DSTBASE, dstbase);999	tdfx_outl(par, SRCXY, 0);1000	tdfx_outl(par, DSTXY, dx | (dy << 16));1001	tdfx_outl(par, COMMAND_2D,1002		  COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));1003	tdfx_outl(par, SRCFORMAT, srcfmt);1004	tdfx_outl(par, DSTFORMAT, dstfmt);1005	tdfx_outl(par, DSTSIZE, image->width | (image->height << 16));1006 1007	/* A count of how many free FIFO entries we've requested.1008	 * When this goes negative, we need to request more. */1009	fifo_free = 0;1010 1011	/* Send four bytes at a time of data */1012	for (i = (size >> 2); i > 0; i--) {1013		if (--fifo_free < 0) {1014			fifo_free = 31;1015			banshee_make_room(par, fifo_free);1016		}1017		tdfx_outl(par, LAUNCH_2D, *(u32 *)chardata);1018		chardata += 4;1019	}1020 1021	/* Send the leftovers now */1022	banshee_make_room(par, 3);1023	switch (size % 4) {1024	case 0:1025		break;1026	case 1:1027		tdfx_outl(par, LAUNCH_2D, *chardata);1028		break;1029	case 2:1030		tdfx_outl(par, LAUNCH_2D, *(u16 *)chardata);1031		break;1032	case 3:1033		tdfx_outl(par, LAUNCH_2D,1034			*(u16 *)chardata | (chardata[3] << 24));1035		break;1036	}1037}1038#endif /* CONFIG_FB_3DFX_ACCEL */1039 1040static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)1041{1042	struct tdfx_par *par = info->par;1043	u32 vidcfg;1044 1045	if (!hwcursor)1046		return -EINVAL;	/* just to force soft_cursor() call */1047 1048	/* Too large of a cursor or wrong bpp :-( */1049	if (cursor->image.width > 64 ||1050	    cursor->image.height > 64 ||1051	    cursor->image.depth > 1)1052		return -EINVAL;1053 1054	vidcfg = tdfx_inl(par, VIDPROCCFG);1055	if (cursor->enable)1056		tdfx_outl(par, VIDPROCCFG, vidcfg | VIDCFG_HWCURSOR_ENABLE);1057	else1058		tdfx_outl(par, VIDPROCCFG, vidcfg & ~VIDCFG_HWCURSOR_ENABLE);1059 1060	/*1061	 * If the cursor is not be changed this means either we want the1062	 * current cursor state (if enable is set) or we want to query what1063	 * we can do with the cursor (if enable is not set)1064	 */1065	if (!cursor->set)1066		return 0;1067 1068	/* fix cursor color - XFree86 forgets to restore it properly */1069	if (cursor->set & FB_CUR_SETCMAP) {1070		struct fb_cmap cmap = info->cmap;1071		u32 bg_idx = cursor->image.bg_color;1072		u32 fg_idx = cursor->image.fg_color;1073		unsigned long bg_color, fg_color;1074 1075		fg_color = (((u32)cmap.red[fg_idx]   & 0xff00) << 8) |1076			   (((u32)cmap.green[fg_idx] & 0xff00) << 0) |1077			   (((u32)cmap.blue[fg_idx]  & 0xff00) >> 8);1078		bg_color = (((u32)cmap.red[bg_idx]   & 0xff00) << 8) |1079			   (((u32)cmap.green[bg_idx] & 0xff00) << 0) |1080			   (((u32)cmap.blue[bg_idx]  & 0xff00) >> 8);1081		banshee_make_room(par, 2);1082		tdfx_outl(par, HWCURC0, bg_color);1083		tdfx_outl(par, HWCURC1, fg_color);1084	}1085 1086	if (cursor->set & FB_CUR_SETPOS) {1087		int x = cursor->image.dx;1088		int y = cursor->image.dy - info->var.yoffset;1089 1090		x += 63;1091		y += 63;1092		banshee_make_room(par, 1);1093		tdfx_outl(par, HWCURLOC, (y << 16) + x);1094	}1095	if (cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {1096		/*1097		 * Voodoo 3 and above cards use 2 monochrome cursor patterns.1098		 *    The reason is so the card can fetch 8 words at a time1099		 * and are stored on chip for use for the next 8 scanlines.1100		 * This reduces the number of times for access to draw the1101		 * cursor for each screen refresh.1102		 *    Each pattern is a bitmap of 64 bit wide and 64 bit high1103		 * (total of 8192 bits or 1024 bytes). The two patterns are1104		 * stored in such a way that pattern 0 always resides in the1105		 * lower half (least significant 64 bits) of a 128 bit word1106		 * and pattern 1 the upper half. If you examine the data of1107		 * the cursor image the graphics card uses then from the1108		 * beginning you see line one of pattern 0, line one of1109		 * pattern 1, line two of pattern 0, line two of pattern 1,1110		 * etc etc. The linear stride for the cursor is always 16 bytes1111		 * (128 bits) which is the maximum cursor width times two for1112		 * the two monochrome patterns.1113		 */1114		u8 __iomem *cursorbase = info->screen_base + info->fix.smem_len;1115		u8 *bitmap = (u8 *)cursor->image.data;1116		u8 *mask = (u8 *)cursor->mask;1117		int i;1118 1119		fb_memset_io(cursorbase, 0, 1024);1120 1121		for (i = 0; i < cursor->image.height; i++) {1122			int h = 0;1123			int j = (cursor->image.width + 7) >> 3;1124 1125			for (; j > 0; j--) {1126				u8 data = *mask ^ *bitmap;1127				if (cursor->rop == ROP_COPY)1128					data = *mask & *bitmap;1129				/* Pattern 0. Copy the cursor mask to it */1130				fb_writeb(*mask, cursorbase + h);1131				mask++;1132				/* Pattern 1. Copy the cursor bitmap to it */1133				fb_writeb(data, cursorbase + h + 8);1134				bitmap++;1135				h++;1136			}1137			cursorbase += 16;1138		}1139	}1140	return 0;1141}1142 1143static const struct fb_ops tdfxfb_ops = {1144	.owner		= THIS_MODULE,1145	__FB_DEFAULT_IOMEM_OPS_RDWR,1146	.fb_check_var	= tdfxfb_check_var,1147	.fb_set_par	= tdfxfb_set_par,1148	.fb_setcolreg	= tdfxfb_setcolreg,1149	.fb_blank	= tdfxfb_blank,1150	.fb_pan_display	= tdfxfb_pan_display,1151	.fb_sync	= banshee_wait_idle,1152	.fb_cursor	= tdfxfb_cursor,1153#ifdef CONFIG_FB_3DFX_ACCEL1154	.fb_fillrect	= tdfxfb_fillrect,1155	.fb_copyarea	= tdfxfb_copyarea,1156	.fb_imageblit	= tdfxfb_imageblit,1157#else1158	__FB_DEFAULT_IOMEM_OPS_DRAW,1159#endif1160	__FB_DEFAULT_IOMEM_OPS_MMAP,1161};1162 1163#ifdef CONFIG_FB_3DFX_I2C1164/* The voo GPIO registers don't have individual masks for each bit1165   so we always have to read before writing. */1166 1167static void tdfxfb_i2c_setscl(void *data, int val)1168{1169	struct tdfxfb_i2c_chan 	*chan = data;1170	struct tdfx_par 	*par = chan->par;1171	unsigned int r;1172 1173	r = tdfx_inl(par, VIDSERPARPORT);1174	if (val)1175		r |= I2C_SCL_OUT;1176	else1177		r &= ~I2C_SCL_OUT;1178	tdfx_outl(par, VIDSERPARPORT, r);1179	tdfx_inl(par, VIDSERPARPORT);	/* flush posted write */1180}1181 1182static void tdfxfb_i2c_setsda(void *data, int val)1183{1184	struct tdfxfb_i2c_chan 	*chan = data;1185	struct tdfx_par 	*par = chan->par;1186	unsigned int r;1187 1188	r = tdfx_inl(par, VIDSERPARPORT);1189	if (val)1190		r |= I2C_SDA_OUT;1191	else1192		r &= ~I2C_SDA_OUT;1193	tdfx_outl(par, VIDSERPARPORT, r);1194	tdfx_inl(par, VIDSERPARPORT);	/* flush posted write */1195}1196 1197/* The GPIO pins are open drain, so the pins always remain outputs.1198   We rely on the i2c-algo-bit routines to set the pins high before1199   reading the input from other chips. */1200 1201static int tdfxfb_i2c_getscl(void *data)1202{1203	struct tdfxfb_i2c_chan 	*chan = data;1204	struct tdfx_par 	*par = chan->par;1205 1206	return (0 != (tdfx_inl(par, VIDSERPARPORT) & I2C_SCL_IN));1207}1208 1209static int tdfxfb_i2c_getsda(void *data)1210{1211	struct tdfxfb_i2c_chan 	*chan = data;1212	struct tdfx_par 	*par = chan->par;1213 1214	return (0 != (tdfx_inl(par, VIDSERPARPORT) & I2C_SDA_IN));1215}1216 1217static void tdfxfb_ddc_setscl(void *data, int val)1218{1219	struct tdfxfb_i2c_chan 	*chan = data;1220	struct tdfx_par 	*par = chan->par;1221	unsigned int r;1222 1223	r = tdfx_inl(par, VIDSERPARPORT);1224	if (val)1225		r |= DDC_SCL_OUT;1226	else1227		r &= ~DDC_SCL_OUT;1228	tdfx_outl(par, VIDSERPARPORT, r);1229	tdfx_inl(par, VIDSERPARPORT);	/* flush posted write */1230}1231 1232static void tdfxfb_ddc_setsda(void *data, int val)1233{1234	struct tdfxfb_i2c_chan 	*chan = data;1235	struct tdfx_par 	*par = chan->par;1236	unsigned int r;1237 1238	r = tdfx_inl(par, VIDSERPARPORT);1239	if (val)1240		r |= DDC_SDA_OUT;1241	else1242		r &= ~DDC_SDA_OUT;1243	tdfx_outl(par, VIDSERPARPORT, r);1244	tdfx_inl(par, VIDSERPARPORT);	/* flush posted write */1245}1246 1247static int tdfxfb_ddc_getscl(void *data)1248{1249	struct tdfxfb_i2c_chan 	*chan = data;1250	struct tdfx_par 	*par = chan->par;1251 1252	return (0 != (tdfx_inl(par, VIDSERPARPORT) & DDC_SCL_IN));1253}1254 1255static int tdfxfb_ddc_getsda(void *data)1256{1257	struct tdfxfb_i2c_chan 	*chan = data;1258	struct tdfx_par 	*par = chan->par;1259 1260	return (0 != (tdfx_inl(par, VIDSERPARPORT) & DDC_SDA_IN));1261}1262 1263static int tdfxfb_setup_ddc_bus(struct tdfxfb_i2c_chan *chan, const char *name,1264				struct device *dev)1265{1266	int rc;1267 1268	strscpy(chan->adapter.name, name, sizeof(chan->adapter.name));1269	chan->adapter.owner		= THIS_MODULE;1270	chan->adapter.algo_data		= &chan->algo;1271	chan->adapter.dev.parent	= dev;1272	chan->algo.setsda		= tdfxfb_ddc_setsda;1273	chan->algo.setscl		= tdfxfb_ddc_setscl;1274	chan->algo.getsda		= tdfxfb_ddc_getsda;1275	chan->algo.getscl		= tdfxfb_ddc_getscl;1276	chan->algo.udelay		= 10;1277	chan->algo.timeout		= msecs_to_jiffies(500);1278	chan->algo.data 		= chan;1279 1280	i2c_set_adapdata(&chan->adapter, chan);1281 1282	rc = i2c_bit_add_bus(&chan->adapter);1283	if (rc == 0)1284		DPRINTK("I2C bus %s registered.\n", name);1285	else1286		chan->par = NULL;1287 1288	return rc;1289}1290 1291static int tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan, const char *name,1292				struct device *dev)1293{1294	int rc;1295 1296	strscpy(chan->adapter.name, name, sizeof(chan->adapter.name));1297	chan->adapter.owner		= THIS_MODULE;1298	chan->adapter.algo_data		= &chan->algo;1299	chan->adapter.dev.parent	= dev;1300	chan->algo.setsda		= tdfxfb_i2c_setsda;1301	chan->algo.setscl		= tdfxfb_i2c_setscl;1302	chan->algo.getsda		= tdfxfb_i2c_getsda;1303	chan->algo.getscl		= tdfxfb_i2c_getscl;1304	chan->algo.udelay		= 10;1305	chan->algo.timeout		= msecs_to_jiffies(500);1306	chan->algo.data 		= chan;1307 1308	i2c_set_adapdata(&chan->adapter, chan);1309 1310	rc = i2c_bit_add_bus(&chan->adapter);1311	if (rc == 0)1312		DPRINTK("I2C bus %s registered.\n", name);1313	else1314		chan->par = NULL;1315 1316	return rc;1317}1318 1319static void tdfxfb_create_i2c_busses(struct fb_info *info)1320{1321	struct tdfx_par *par = info->par;1322 1323	tdfx_outl(par, VIDINFORMAT, 0x8160);1324	tdfx_outl(par, VIDSERPARPORT, 0xcffc0020);1325 1326	par->chan[0].par = par;1327	par->chan[1].par = par;1328 1329	tdfxfb_setup_ddc_bus(&par->chan[0], "Voodoo3-DDC", info->device);1330	tdfxfb_setup_i2c_bus(&par->chan[1], "Voodoo3-I2C", info->device);1331}1332 1333static void tdfxfb_delete_i2c_busses(struct tdfx_par *par)1334{1335	if (par->chan[0].par)1336		i2c_del_adapter(&par->chan[0].adapter);1337	par->chan[0].par = NULL;1338 1339	if (par->chan[1].par)1340		i2c_del_adapter(&par->chan[1].adapter);1341	par->chan[1].par = NULL;1342}1343 1344static int tdfxfb_probe_i2c_connector(struct tdfx_par *par,1345				      struct fb_monspecs *specs)1346{1347	u8 *edid = NULL;1348 1349	DPRINTK("Probe DDC Bus\n");1350	if (par->chan[0].par)1351		edid = fb_ddc_read(&par->chan[0].adapter);1352 1353	if (edid) {1354		fb_edid_to_monspecs(edid, specs);1355		kfree(edid);1356		return 0;1357	}1358	return 1;1359}1360#endif /* CONFIG_FB_3DFX_I2C */1361 1362/**1363 *      tdfxfb_probe - Device Initializiation1364 *1365 *      @pdev:  PCI Device to initialize1366 *      @id:    PCI Device ID1367 *1368 *      Initializes and allocates resources for PCI device @pdev.1369 *1370 */1371static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)1372{1373	struct tdfx_par *default_par;1374	struct fb_info *info;1375	int err, lpitch;1376	struct fb_monspecs *specs;1377	bool found;1378 1379	err = aperture_remove_conflicting_pci_devices(pdev, "tdfxfb");1380	if (err)1381		return err;1382 1383	err = pci_enable_device(pdev);1384	if (err) {1385		printk(KERN_ERR "tdfxfb: Can't enable pdev: %d\n", err);1386		return err;1387	}1388 1389	info = framebuffer_alloc(sizeof(struct tdfx_par), &pdev->dev);1390 1391	if (!info)1392		return -ENOMEM;1393 1394	default_par = info->par;1395	info->fix = tdfx_fix;1396 1397	/* Configure the default fb_fix_screeninfo first */1398	switch (pdev->device) {1399	case PCI_DEVICE_ID_3DFX_BANSHEE:1400		strcpy(info->fix.id, "3Dfx Banshee");1401		default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK;1402		break;1403	case PCI_DEVICE_ID_3DFX_VOODOO3:1404		strcpy(info->fix.id, "3Dfx Voodoo3");1405		default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK;1406		break;1407	case PCI_DEVICE_ID_3DFX_VOODOO5:1408		strcpy(info->fix.id, "3Dfx Voodoo5");1409		default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK;1410		break;1411	}1412 1413	info->fix.mmio_start = pci_resource_start(pdev, 0);1414	info->fix.mmio_len = pci_resource_len(pdev, 0);1415	if (!request_mem_region(info->fix.mmio_start, info->fix.mmio_len,1416				"tdfx regbase")) {1417		printk(KERN_ERR "tdfxfb: Can't reserve regbase\n");1418		goto out_err;1419	}1420 1421	default_par->regbase_virt =1422		ioremap(info->fix.mmio_start, info->fix.mmio_len);1423	if (!default_par->regbase_virt) {1424		printk(KERN_ERR "fb: Can't remap %s register area.\n",1425				info->fix.id);1426		goto out_err_regbase;1427	}1428 1429	info->fix.smem_start = pci_resource_start(pdev, 1);1430	info->fix.smem_len = do_lfb_size(default_par, pdev->device);1431	if (!info->fix.smem_len) {1432		printk(KERN_ERR "fb: Can't count %s memory.\n", info->fix.id);1433		goto out_err_regbase;1434	}1435 1436	if (!request_mem_region(info->fix.smem_start,1437				pci_resource_len(pdev, 1), "tdfx smem")) {1438		printk(KERN_ERR "tdfxfb: Can't reserve smem\n");1439		goto out_err_regbase;1440	}1441 1442	info->screen_base = ioremap_wc(info->fix.smem_start,1443				       info->fix.smem_len);1444	if (!info->screen_base) {1445		printk(KERN_ERR "fb: Can't remap %s framebuffer.\n",1446				info->fix.id);1447		goto out_err_screenbase;1448	}1449 1450	default_par->iobase = pci_resource_start(pdev, 2);1451 1452	if (!request_region(pci_resource_start(pdev, 2),1453			    pci_resource_len(pdev, 2), "tdfx iobase")) {1454		printk(KERN_ERR "tdfxfb: Can't reserve iobase\n");1455		goto out_err_screenbase;1456	}1457 1458	printk(KERN_INFO "fb: %s memory = %dK\n", info->fix.id,1459			info->fix.smem_len >> 10);1460 1461	if (!nomtrr)1462		default_par->wc_cookie= arch_phys_wc_add(info->fix.smem_start,1463							 info->fix.smem_len);1464 1465	info->fix.ypanstep	= nopan ? 0 : 1;1466	info->fix.ywrapstep	= nowrap ? 0 : 1;1467 1468	info->fbops		= &tdfxfb_ops;1469	info->pseudo_palette	= default_par->palette;1470	info->flags		= FBINFO_HWACCEL_YPAN;1471#ifdef CONFIG_FB_3DFX_ACCEL1472	info->flags		|= FBINFO_HWACCEL_FILLRECT |1473				   FBINFO_HWACCEL_COPYAREA |1474				   FBINFO_HWACCEL_IMAGEBLIT |1475				   FBINFO_READS_FAST;1476#endif1477	/* reserve 8192 bits for cursor */1478	/* the 2.4 driver says PAGE_MASK boundary is not enough for Voodoo4 */1479	if (hwcursor)1480		info->fix.smem_len = (info->fix.smem_len - 1024) &1481					(PAGE_MASK << 1);1482	specs = &info->monspecs;1483	found = false;1484	info->var.bits_per_pixel = 8;1485#ifdef CONFIG_FB_3DFX_I2C1486	tdfxfb_create_i2c_busses(info);1487	err = tdfxfb_probe_i2c_connector(default_par, specs);1488 1489	if (!err) {1490		if (specs->modedb == NULL)1491			DPRINTK("Unable to get Mode Database\n");1492		else {1493			const struct fb_videomode *m;1494 1495			fb_videomode_to_modelist(specs->modedb,1496						 specs->modedb_len,1497						 &info->modelist);1498			m = fb_find_best_display(specs, &info->modelist);1499			if (m) {1500				fb_videomode_to_var(&info->var, m);1501				/* fill all other info->var's fields */1502				if (tdfxfb_check_var(&info->var, info) < 0)1503					info->var = tdfx_var;1504				else1505					found = true;1506			}1507		}1508	}1509#endif1510	if (!mode_option && !found)1511		mode_option = "640x480@60";1512 1513	if (mode_option) {1514		err = fb_find_mode(&info->var, info, mode_option,1515				   specs->modedb, specs->modedb_len,1516				   NULL, info->var.bits_per_pixel);1517		if (!err || err == 4)1518			info->var = tdfx_var;1519	}1520 1521	if (found) {1522		fb_destroy_modedb(specs->modedb);1523		specs->modedb = NULL;1524	}1525 1526	/* maximize virtual vertical length */1527	lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3);1528	info->var.yres_virtual = info->fix.smem_len / lpitch;1529	if (info->var.yres_virtual < info->var.yres)1530		goto out_err_iobase;1531 1532	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {1533		printk(KERN_ERR "tdfxfb: Can't allocate color map\n");1534		goto out_err_iobase;1535	}1536 1537	if (register_framebuffer(info) < 0) {1538		printk(KERN_ERR "tdfxfb: can't register framebuffer\n");1539		fb_dealloc_cmap(&info->cmap);1540		goto out_err_iobase;1541	}1542	/*1543	 * Our driver data1544	 */1545	pci_set_drvdata(pdev, info);1546	return 0;1547 1548out_err_iobase:1549#ifdef CONFIG_FB_3DFX_I2C1550	tdfxfb_delete_i2c_busses(default_par);1551#endif1552	arch_phys_wc_del(default_par->wc_cookie);1553	release_region(pci_resource_start(pdev, 2),1554		       pci_resource_len(pdev, 2));1555out_err_screenbase:1556	if (info->screen_base)1557		iounmap(info->screen_base);1558	release_mem_region(info->fix.smem_start, pci_resource_len(pdev, 1));1559out_err_regbase:1560	/*1561	 * Cleanup after anything that was remapped/allocated.1562	 */1563	if (default_par->regbase_virt)1564		iounmap(default_par->regbase_virt);1565	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);1566out_err:1567	framebuffer_release(info);1568	return -ENXIO;1569}1570 1571#ifndef MODULE1572static void __init tdfxfb_setup(char *options)1573{1574	char *this_opt;1575 1576	if (!options || !*options)1577		return;1578 1579	while ((this_opt = strsep(&options, ",")) != NULL) {1580		if (!*this_opt)1581			continue;1582		if (!strcmp(this_opt, "nopan")) {1583			nopan = 1;1584		} else if (!strcmp(this_opt, "nowrap")) {1585			nowrap = 1;1586		} else if (!strncmp(this_opt, "hwcursor=", 9)) {1587			hwcursor = simple_strtoul(this_opt + 9, NULL, 0);1588		} else if (!strncmp(this_opt, "nomtrr", 6)) {1589			nomtrr = 1;1590		} else {1591			mode_option = this_opt;1592		}1593	}1594}1595#endif1596 1597/**1598 *      tdfxfb_remove - Device removal1599 *1600 *      @pdev:  PCI Device to cleanup1601 *1602 *      Releases all resources allocated during the course of the driver's1603 *      lifetime for the PCI device @pdev.1604 *1605 */1606static void tdfxfb_remove(struct pci_dev *pdev)1607{1608	struct fb_info *info = pci_get_drvdata(pdev);1609	struct tdfx_par *par = info->par;1610 1611	unregister_framebuffer(info);1612#ifdef CONFIG_FB_3DFX_I2C1613	tdfxfb_delete_i2c_busses(par);1614#endif1615	arch_phys_wc_del(par->wc_cookie);1616	iounmap(par->regbase_virt);1617	iounmap(info->screen_base);1618 1619	/* Clean up after reserved regions */1620	release_region(pci_resource_start(pdev, 2),1621		       pci_resource_len(pdev, 2));1622	release_mem_region(pci_resource_start(pdev, 1),1623			   pci_resource_len(pdev, 1));1624	release_mem_region(pci_resource_start(pdev, 0),1625			   pci_resource_len(pdev, 0));1626	fb_dealloc_cmap(&info->cmap);1627	framebuffer_release(info);1628}1629 1630static int __init tdfxfb_init(void)1631{1632#ifndef MODULE1633	char *option = NULL;1634#endif1635 1636	if (fb_modesetting_disabled("tdfxfb"))1637		return -ENODEV;1638 1639#ifndef MODULE1640	if (fb_get_options("tdfxfb", &option))1641		return -ENODEV;1642 1643	tdfxfb_setup(option);1644#endif1645	return pci_register_driver(&tdfxfb_driver);1646}1647 1648static void __exit tdfxfb_exit(void)1649{1650	pci_unregister_driver(&tdfxfb_driver);1651}1652 1653MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>");1654MODULE_DESCRIPTION("3Dfx framebuffer device driver");1655MODULE_LICENSE("GPL");1656 1657module_param(hwcursor, int, 0644);1658MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "1659			"(1=enable, 0=disable, default=1)");1660module_param(mode_option, charp, 0);1661MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");1662module_param(nomtrr, bool, 0);1663MODULE_PARM_DESC(nomtrr, "Disable MTRR support (default: enabled)");1664 1665module_init(tdfxfb_init);1666module_exit(tdfxfb_exit);1667