11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tdfxfb.c
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author: Hannu Mallat <hmallat@cc.hut.fi>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
73cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt * Copyright © 1999 Hannu Mallat
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All rights reserved
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Created      : Thu Sep 23 18:17:43 1999, hmallat
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Last modified: Tue Nov  2 21:19:47 1999, hmallat
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
13feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt * I2C part copied from the i2c-voodoo3.c driver by:
14feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt * Frodo Looijaard <frodol@dds.nl>,
15feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt * Philip Edelbrock <phil@netroedge.com>,
16feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt * Ralph Metzler <rjkm@thp.uni-koeln.de>, and
17feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt * Mark D. Studebaker <mdsxyz123@yahoo.com>
18feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt *
198af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt * Lots of the information here comes from the Daryll Strauss' Banshee
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * patches to the XF86 server, and the rest comes from the 3dfx
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Banshee specification. I'm very much indebted to Daryll for his
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * work on the X server.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Voodoo3 support was contributed Harold Oga. Lots of additions
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (proper acceleration, 24 bpp, hardware cursor) and bug fixes by Attila
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Kesmarki. Thanks guys!
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Voodoo1 and Voodoo2 support aren't relevant to this driver as they
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * behave very differently from the Voodoo3/4/5. For anyone wanting to
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * use frame buffer on the Voodoo1/2, see the sstfb driver (which is
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * located at http://www.sourceforge.net/projects/sstfb).
328af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt *
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I do wish the next version is a bit more complete. Without the XF86
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * patches I couldn't have gotten even this far... for instance, the
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * extensions to the VGA register set go completely unmentioned in the
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * spec! Also, lots of references are made to the 'SST core', but no
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * spec is publicly available, AFAIK.
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The structure of this driver comes pretty much from the Permedia
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * driver by Ilario Nardinocchi, which in turn is based on skeletonfb.
428af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt *
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TODO:
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - multihead support (basically need to support an array of fb_infos)
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - support other architectures (PPC, Alpha); does the fact that the VGA
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   core can be accessed only thru I/O (not memory mapped) complicate
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   things?
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version history:
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
513cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt * 0.1.4 (released 2002-05-28)	ported over to new fbdev api by James Simmons
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
533cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt * 0.1.3 (released 1999-11-02)	added Attila's panning support, code
543cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt *				reorg, hwcursor address page size alignment
55af901ca181d92aac3a7dc265144a9081a86d8f39André Goddard Rosa *				(for mmapping both frame buffer and regs),
563cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt *				and my changes to get rid of hardcoded
573cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt *				VGA i/o register locations (uses PCI
583cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt *				configuration info now)
593cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt * 0.1.2 (released 1999-10-19)	added Attila Kesmarki's bug fixes and
603cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt *				improvements
613cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt * 0.1.1 (released 1999-10-07)	added Voodoo3 support by Harold Oga.
623cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt * 0.1.0 (released 1999-10-06)	initial version
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fb.h>
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <video/tdfx.h>
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
795ae121705bed9ea7425daef4d7d29038f7312f3fHarvey Harrison#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __func__ , ## b)
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
810960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt#ifdef CONFIG_MTRR
820960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt#include <asm/mtrr.h>
830960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt#else
840960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt/* duplicate asm/mtrr.h defines to work on archs without mtrr */
850960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt#define MTRR_TYPE_WRCOMB     1
860960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt
870960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Heltstatic inline int mtrr_add(unsigned long base, unsigned long size,
880960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt				unsigned int type, char increment)
890960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt{
900960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt    return -ENODEV;
910960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt}
920960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Heltstatic inline int mtrr_del(int reg, unsigned long base,
930960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt				unsigned long size)
940960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt{
950960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt    return -ENODEV;
960960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt}
970960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt#endif
980960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BANSHEE_MAX_PIXCLOCK 270000
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VOODOO3_MAX_PIXCLOCK 300000
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VOODOO5_MAX_PIXCLOCK 350000
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fb_fix_screeninfo tdfx_fix __devinitdata = {
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.type =		FB_TYPE_PACKED_PIXELS,
1058af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.visual =	FB_VISUAL_PSEUDOCOLOR,
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ypanstep =	1,
1078af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.ywrapstep =	1,
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.accel =	FB_ACCEL_3DFX_BANSHEE
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fb_var_screeninfo tdfx_var __devinitdata = {
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* "640x480, 8 bpp @ 60 Hz */
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres =		640,
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yres =		480,
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres_virtual =	640,
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yres_virtual =	1024,
1178af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.bits_per_pixel = 8,
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.red =		{0, 8, 0},
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.blue =		{0, 8, 0},
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.green =	{0, 8, 0},
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.activate =	FB_ACTIVATE_NOW,
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.height =	-1,
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.width =	-1,
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.accel_flags =	FB_ACCELF_TEXT,
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock =	39722,
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin =	40,
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin =	24,
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.upper_margin =	32,
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lower_margin =	11,
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len =	96,
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vsync_len =	2,
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vmode =	FB_VMODE_NONINTERLACED
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI driver prototypes
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit tdfxfb_probe(struct pci_dev *pdev,
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  const struct pci_device_id *id);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devexit tdfxfb_remove(struct pci_dev *pdev);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id tdfxfb_id_table[] = {
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE,
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  0xff0000, 0 },
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3,
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  0xff0000, 0 },
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5,
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  0xff0000, 0 },
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0, }
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver tdfxfb_driver = {
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "tdfxfb",
1578af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.id_table	= tdfxfb_id_table,
1588af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.probe		= tdfxfb_probe,
1598af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.remove		= __devexit_p(tdfxfb_remove),
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1658af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt * Driver data
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16790b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Heltstatic int nopan;
16890b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Heltstatic int nowrap = 1;      /* not implemented (yet) */
16990b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Heltstatic int hwcursor = 1;
1700960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Heltstatic char *mode_option __devinitdata;
1710960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt/* mtrr option */
17290ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool nomtrr __devinitdata;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1748af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt/* -------------------------------------------------------------------------
1753cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt *			Hardware-specific funcions
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------------------- */
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1788af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic inline u8 vga_inb(struct tdfx_par *par, u32 reg)
1798af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt{
1808af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	return inb(par->iobase + reg - 0x300);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1824f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt
1838af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val)
1848af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt{
1858af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	outb(val, par->iobase + reg - 0x300);
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1888af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val)
1898af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt{
1908af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	vga_outb(par, GRA_I, idx);
191254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	wmb();
1928af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	vga_outb(par, GRA_D, val);
193254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	wmb();
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1968af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val)
1978af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt{
1988af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	vga_outb(par, SEQ_I, idx);
199254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	wmb();
2008af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	vga_outb(par, SEQ_D, val);
201254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	wmb();
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2048af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic inline u8 seq_inb(struct tdfx_par *par, u32 idx)
2058af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt{
2068af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	vga_outb(par, SEQ_I, idx);
207254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	mb();
2088af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	return vga_inb(par, SEQ_D);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2118af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic inline void crt_outb(struct tdfx_par *par, u32 idx, u8 val)
2128af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt{
2138af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	vga_outb(par, CRT_I, idx);
214254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	wmb();
2158af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	vga_outb(par, CRT_D, val);
216254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	wmb();
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2198af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic inline u8 crt_inb(struct tdfx_par *par, u32 idx)
2208af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt{
2218af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	vga_outb(par, CRT_I, idx);
222254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	mb();
2238af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	return vga_inb(par, CRT_D);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2268af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic inline void att_outb(struct tdfx_par *par, u32 idx, u8 val)
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char tmp;
2298af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = vga_inb(par, IS1_R);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vga_outb(par, ATT_IW, idx);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vga_outb(par, ATT_IW, val);
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void vga_disable_video(struct tdfx_par *par)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char s;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s = seq_inb(par, 0x01) | 0x20;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_outb(par, 0x00, 0x01);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_outb(par, 0x01, s);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_outb(par, 0x00, 0x03);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void vga_enable_video(struct tdfx_par *par)
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char s;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s = seq_inb(par, 0x01) & 0xdf;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_outb(par, 0x00, 0x01);
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_outb(par, 0x01, s);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_outb(par, 0x00, 0x03);
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void vga_enable_palette(struct tdfx_par *par)
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vga_inb(par, IS1_R);
258254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	mb();
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vga_outb(par, ATT_IW, 0x20);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2628af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic inline u32 tdfx_inl(struct tdfx_par *par, unsigned int reg)
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return readl(par->regbase_virt + reg);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void tdfx_outl(struct tdfx_par *par, unsigned int reg, u32 val)
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(val, par->regbase_virt + reg);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void banshee_make_room(struct tdfx_par *par, int size)
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Note: The Voodoo3's onboard FIFO has 32 slots. This loop
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * won't quit if you ask for more. */
276f67fd7c10f2eb16e6c70fd99e97a148e19ac5a55Krzysztof Helt	while ((tdfx_inl(par, STATUS) & 0x1f) < size - 1)
277f67fd7c10f2eb16e6c70fd99e97a148e19ac5a55Krzysztof Helt		cpu_relax();
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2793cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int banshee_wait_idle(struct fb_info *info)
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
282a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	struct tdfx_par *par = info->par;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 0;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	banshee_make_room(par, 1);
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tdfx_outl(par, COMMAND_3D, COMMAND_3D_NOP);
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2884f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	do {
2893cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		if ((tdfx_inl(par, STATUS) & STATUS_BUSY) == 0)
2903cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt			i++;
2914f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	} while (i < 3);
2924f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2978af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt * Set the color of a palette entry in 8bpp mode
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void do_setpalentry(struct tdfx_par *par, unsigned regno, u32 c)
3003cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt{
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	banshee_make_room(par, 2);
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tdfx_outl(par, DACADDR, regno);
303254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	/* read after write makes it working */
304254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	tdfx_inl(par, DACADDR);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tdfx_outl(par, DACDATA, c);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3088af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic u32 do_calc_pll(int freq, int *freq_out)
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3100fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond	int m, n, k, best_m, best_n, best_k, best_error;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int fref = 14318;
3128af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	best_error = freq;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	best_n = best_m = best_k = 0;
3150fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond
3160fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond	for (k = 3; k >= 0; k--) {
3170fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond		for (m = 63; m >= 0; m--) {
3180fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond			/*
3190fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond			 * Estimate value of n that produces target frequency
3200fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond			 * with current m and k
3210fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond			 */
3224f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt			int n_estimated = ((freq * (m + 2) << k) / fref) - 2;
3230fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond
3240fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond			/* Search neighborhood of estimated n */
3254f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt			for (n = max(0, n_estimated);
3264f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt				n <= min(255, n_estimated + 1);
3274f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt				n++) {
3280fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond				/*
3290fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond				 * Calculate PLL freqency with current m, k and
3300fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond				 * estimated n
3310fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond				 */
3324f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt				int f = (fref * (n + 2) / (m + 2)) >> k;
3338af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt				int error = abs(f - freq);
3340fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond
3350fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond				/*
3368af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt				 * If this is the closest we've come to the
3370fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond				 * target frequency then remember n, m and k
3380fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond				 */
3398af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt				if (error < best_error) {
3400fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond					best_error = error;
3418af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt					best_n = n;
3428af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt					best_m = m;
3438af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt					best_k = k;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3480fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	n = best_n;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	m = best_m;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	k = best_k;
3524f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	*freq_out = (fref * (n + 2) / (m + 2)) >> k;
3530fbe9cafff72799700713e6a9d5a4ec7191e8d19Richard Drummond
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (n << 8) | (m << 2) | k;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3578af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic void do_write_regs(struct fb_info *info, struct banshee_reg *reg)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
359a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	struct tdfx_par *par = info->par;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	banshee_wait_idle(info);
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tdfx_outl(par, MISCINIT1, tdfx_inl(par, MISCINIT1) | 0x01);
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	crt_outb(par, 0x11, crt_inb(par, 0x11) & 0x7f); /* CRT unprotect */
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	banshee_make_room(par, 3);
3698af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, VGAINIT1, reg->vgainit1 & 0x001FFFFF);
3708af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, VIDPROCCFG, reg->vidcfg & ~0x00000001);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tdfx_outl(par, PLLCTRL1, reg->mempll);
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tdfx_outl(par, PLLCTRL2, reg->gfxpll);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3758af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, PLLCTRL0, reg->vidpll);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vga_outb(par, MISC_W, reg->misc[0x00] | 0x01);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 5; i++)
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_outb(par, i, reg->seq[i]);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 25; i++)
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		crt_outb(par, i, reg->crt[i]);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 9; i++)
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gra_outb(par, i, reg->gra[i]);
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 21; i++)
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		att_outb(par, i, reg->att[i]);
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	crt_outb(par, 0x1a, reg->ext[0]);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	crt_outb(par, 0x1b, reg->ext[1]);
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vga_enable_palette(par);
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vga_enable_video(par);
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3974f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	banshee_make_room(par, 9);
3988af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, VGAINIT0, reg->vgainit0);
3998af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, DACMODE, reg->dacmode);
4008af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, VIDDESKSTRIDE, reg->stride);
40190b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	tdfx_outl(par, HWCURPATADDR, reg->curspataddr);
4028af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
4038af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, VIDSCREENSIZE, reg->screensize);
4048af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, VIDDESKSTART, reg->startaddr);
4058af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, VIDPROCCFG, reg->vidcfg);
4068af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, VGAINIT1, reg->vgainit1);
4078af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, MISCINIT0, reg->miscinit0);
4088af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
4098af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	banshee_make_room(par, 8);
4104f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	tdfx_outl(par, SRCBASE, reg->startaddr);
4114f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	tdfx_outl(par, DSTBASE, reg->startaddr);
4128af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, COMMANDEXTRA_2D, 0);
4138af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, CLIP0MIN, 0);
4148af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, CLIP0MAX, 0x0fff0fff);
4158af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, CLIP1MIN, 0);
4168af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, CLIP1MAX, 0x0fff0fff);
4178af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, SRCXY, 0);
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	banshee_wait_idle(info);
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4228af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id)
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4244f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	u32 draminit0 = tdfx_inl(par, DRAMINIT0);
4254f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	u32 draminit1 = tdfx_inl(par, DRAMINIT1);
426333f981720d619e2038b980a55ad01b10580eb9fRichard Drummond	u32 miscinit1;
4274f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	int num_chips = (draminit0 & DRAMINIT0_SGRAM_NUM) ? 8 : 4;
428333f981720d619e2038b980a55ad01b10580eb9fRichard Drummond	int chip_size; /* in MB */
4294f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	int has_sgram = draminit1 & DRAMINIT1_MEM_SDRAM;
4308af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
431333f981720d619e2038b980a55ad01b10580eb9fRichard Drummond	if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) {
432333f981720d619e2038b980a55ad01b10580eb9fRichard Drummond		/* Banshee/Voodoo3 */
4338af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		chip_size = 2;
434bf6910c0afb1e416a99ad5b2296e088449fbe481Krzysztof Helt		if (has_sgram && !(draminit0 & DRAMINIT0_SGRAM_TYPE))
4354f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt			chip_size = 1;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Voodoo4/5 */
438333f981720d619e2038b980a55ad01b10580eb9fRichard Drummond		has_sgram = 0;
4394f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt		chip_size = draminit0 & DRAMINIT0_SGRAM_TYPE_MASK;
4404f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt		chip_size = 1 << (chip_size >> DRAMINIT0_SGRAM_TYPE_SHIFT);
441333f981720d619e2038b980a55ad01b10580eb9fRichard Drummond	}
442333f981720d619e2038b980a55ad01b10580eb9fRichard Drummond
443333f981720d619e2038b980a55ad01b10580eb9fRichard Drummond	/* disable block writes for SDRAM */
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	miscinit1 = tdfx_inl(par, MISCINIT1);
445333f981720d619e2038b980a55ad01b10580eb9fRichard Drummond	miscinit1 |= has_sgram ? 0 : MISCINIT1_2DBLOCK_DIS;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	miscinit1 |= MISCINIT1_CLUT_INV;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4488af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	banshee_make_room(par, 1);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tdfx_outl(par, MISCINIT1, miscinit1);
4504f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	return num_chips * chip_size * 1024l * 1024;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ------------------------------------------------------------------------- */
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4558af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
457a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	struct tdfx_par *par = info->par;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 lpitch;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->bits_per_pixel != 8  && var->bits_per_pixel != 16 &&
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->xres != var->xres_virtual)
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->xres_virtual = var->xres;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->yres > var->yres_virtual)
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->yres_virtual = var->yres;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->xoffset) {
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK("xoffset not supported\n");
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
47690b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	var->yoffset = 0;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4783cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	/*
4793cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	 * Banshee doesn't support interlace, but Voodoo4/5 and probably
4803cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	 * Voodoo3 do.
4813cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	 * no direct information about device id now?
4823cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	 *  use max_pixclock for this...
4833cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	 */
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) &&
4858af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	    (par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) {
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK("interlace not supported\n");
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
490215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	if (info->monspecs.hfmax && info->monspecs.vfmax &&
491215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	    info->monspecs.dclkmax && fb_validate_mode(var, info) < 0) {
492215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		DPRINTK("mode outside monitor's specs\n");
493215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		return -EINVAL;
494215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	}
495215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
4978af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
4988af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->xres < 320 || var->xres > 2048) {
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK("width not supported: %u\n", var->xres);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5038af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->yres < 200 || var->yres > 2048) {
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK("height not supported: %u\n", var->yres);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5088af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lpitch * var->yres_virtual > info->fix.smem_len) {
5108af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		var->yres_virtual = info->fix.smem_len / lpitch;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (var->yres_virtual < var->yres) {
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DPRINTK("no memory for screen (%ux%ux%u)\n",
5138af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt				var->xres, var->yres_virtual,
5148af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt				var->bits_per_pixel);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5188af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (PICOS2KHZ(var->pixclock) > par->max_pixclock) {
5208af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		DPRINTK("pixclock too high (%ldKHz)\n",
5218af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			PICOS2KHZ(var->pixclock));
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52592744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	var->transp.offset = 0;
52692744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	var->transp.length = 0;
5278af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	switch (var->bits_per_pixel) {
5288af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case 8:
5293cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		var->red.length = 8;
5303cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		var->red.offset = 0;
5313cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		var->green = var->red;
5323cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		var->blue = var->red;
5338af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
5348af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case 16:
5358af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		var->red.offset   = 11;
5368af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		var->red.length   = 5;
5378af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		var->green.offset = 5;
5388af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		var->green.length = 6;
5398af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		var->blue.offset  = 0;
5408af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		var->blue.length  = 5;
5418af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
5428af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case 32:
54392744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		var->transp.offset = 24;
54492744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		var->transp.length = 8;
5458af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case 24:
54692744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		var->red.offset = 16;
54792744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		var->green.offset = 8;
54892744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		var->blue.offset = 0;
5498af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		var->red.length = var->green.length = var->blue.length = 8;
5508af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5523cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	var->width = -1;
5533cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	var->height = -1;
5548af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->accel_flags = FB_ACCELF_TEXT;
5568af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
5578af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	DPRINTK("Checking graphics mode at %dx%d depth %d\n",
5588af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		var->xres, var->yres, var->bits_per_pixel);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tdfxfb_set_par(struct fb_info *info)
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
564a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	struct tdfx_par *par = info->par;
5654f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	u32 hdispend = info->var.xres;
5664f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	u32 hsyncsta = hdispend + info->var.right_margin;
5674f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	u32 hsyncend = hsyncsta + info->var.hsync_len;
5684f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	u32 htotal   = hsyncend + info->var.left_margin;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 hd, hs, he, ht, hbs, hbe;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 vd, vs, ve, vt, vbs, vbe;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct banshee_reg reg;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int fout, freq;
5734f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	u32 wd;
5744f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	u32 cpp = (info->var.bits_per_pixel + 7) >> 3;
5758af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&reg, 0, sizeof(reg));
5778af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
5788af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE |
5798af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		     VIDCFG_CURS_X11 |
5808af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		     ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
5818af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		     (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* PLL settings */
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	freq = PICOS2KHZ(info->var.pixclock);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5868af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	reg.vidcfg &= ~VIDCFG_2X;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5888af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	if (freq > par->max_pixclock / 2) {
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		freq = freq > par->max_pixclock ? par->max_pixclock : freq;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg.dacmode |= DACMODE_2X;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg.vidcfg  |= VIDCFG_2X;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hdispend >>= 1;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hsyncsta >>= 1;
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hsyncend >>= 1;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		htotal   >>= 1;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5978af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
5983cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	wd = (hdispend >> 3) - 1;
5993cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	hd  = wd;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hs  = (hsyncsta >> 3) - 1;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	he  = (hsyncend >> 3) - 1;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ht  = (htotal >> 3) - 1;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hbs = hd;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hbe = ht;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6073cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		vd = (info->var.yres << 1) - 1;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vs  = vd + (info->var.lower_margin << 1);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ve  = vs + (info->var.vsync_len << 1);
6103cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		vt = ve + (info->var.upper_margin << 1) - 1;
6114f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt		reg.screensize = info->var.xres | (info->var.yres << 13);
6124f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt		reg.vidcfg |= VIDCFG_HALF_MODE;
6134f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt		reg.crt[0x09] = 0x80;
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6153cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		vd = info->var.yres - 1;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vs  = vd + info->var.lower_margin;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ve  = vs + info->var.vsync_len;
6183cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		vt = ve + info->var.upper_margin - 1;
6194f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt		reg.screensize = info->var.xres | (info->var.yres << 12);
6204f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt		reg.vidcfg &= ~VIDCFG_HALF_MODE;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6223cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	vbs = vd;
6233cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	vbe = vt;
6248af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* this is all pretty standard VGA register stuffing */
6268af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	reg.misc[0x00] = 0x0f |
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(info->var.xres < 400 ? 0xa0 :
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 info->var.xres < 480 ? 0x60 :
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 info->var.xres < 768 ? 0xe0 : 0x20);
6308af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.gra[0x05] = 0x40;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.gra[0x06] = 0x05;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.gra[0x07] = 0x0f;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.gra[0x08] = 0xff;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x00] = 0x00;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x01] = 0x01;
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x02] = 0x02;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x03] = 0x03;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x04] = 0x04;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x05] = 0x05;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x06] = 0x06;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x07] = 0x07;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x08] = 0x08;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x09] = 0x09;
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x0a] = 0x0a;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x0b] = 0x0b;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x0c] = 0x0c;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x0d] = 0x0d;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x0e] = 0x0e;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x0f] = 0x0f;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x10] = 0x41;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.att[0x12] = 0x0f;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.seq[0x00] = 0x03;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.seq[0x02] = 0x0f;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.seq[0x03] = 0x00;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.seq[0x04] = 0x0e;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x00] = ht - 4;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x01] = hd;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x02] = hbs;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x03] = 0x80 | (hbe & 0x1f);
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x04] = hs;
6668af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x06] = vt;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x07] = ((vs & 0x200) >> 2) |
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			((vd & 0x200) >> 3) |
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			((vt & 0x200) >> 4) | 0x10 |
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			((vbs & 0x100) >> 5) |
6728af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			((vs & 0x100) >> 6) |
6738af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			((vd & 0x100) >> 7) |
6748af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			((vt & 0x100) >> 8);
6754f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	reg.crt[0x09] |= 0x40 | ((vbs & 0x200) >> 4);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x10] = vs;
6778af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	reg.crt[0x11] = (ve & 0x0f) | 0x20;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x12] = vd;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x13] = wd;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x15] = vbs;
6818af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	reg.crt[0x16] = vbe + 1;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x17] = 0xc3;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.crt[0x18] = 0xff;
6848af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Banshee's nonvga stuff */
6868af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	reg.ext[0x00] = (((ht & 0x100) >> 8) |
6878af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			((hd & 0x100) >> 6) |
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			((hbs & 0x100) >> 4) |
6898af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			((hbe & 0x40) >> 1) |
6908af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			((hs & 0x100) >> 2) |
6918af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			((he & 0x20) << 2));
6928af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	reg.ext[0x01] = (((vt & 0x400) >> 10) |
6938af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			((vd & 0x400) >> 8) |
6948af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			((vbs & 0x400) >> 6) |
6958af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			((vbe & 0x400) >> 4));
6968af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
6978af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	reg.vgainit0 =	VGAINIT0_8BIT_DAC     |
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			VGAINIT0_EXT_ENABLE   |
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			VGAINIT0_WAKEUP_3C3   |
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			VGAINIT0_ALT_READBACK |
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			VGAINIT0_EXTSHIFTOUT;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.vgainit1 = tdfx_inl(par, VGAINIT1) & 0x1fffff;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
70490b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	if (hwcursor)
70590b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		reg.curspataddr = info->fix.smem_len;
70690b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.cursloc   = 0;
7088af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
7098af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	reg.cursc0    = 0;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.cursc1    = 0xffffff;
7118af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.stride    = info->var.xres * cpp;
7134f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	reg.startaddr = info->var.yoffset * reg.stride
7144f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt			+ info->var.xoffset * cpp;
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.vidpll = do_calc_pll(freq, &fout);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.mempll = do_calc_pll(..., &fout);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.gfxpll = do_calc_pll(..., &fout);
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg.vidcfg |= VIDCFG_INTERLACE;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reg.miscinit0 = tdfx_inl(par, MISCINIT0);
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(__BIG_ENDIAN)
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (info->var.bits_per_pixel) {
7288af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case 8:
7298af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case 24:
7308af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		reg.miscinit0 &= ~(1 << 30);
7318af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		reg.miscinit0 &= ~(1 << 31);
7328af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
7338af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case 16:
7348af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		reg.miscinit0 |= (1 << 30);
7358af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		reg.miscinit0 |= (1 << 31);
7368af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
7378af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case 32:
7388af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		reg.miscinit0 |= (1 << 30);
7398af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		reg.miscinit0 &= ~(1 << 31);
7408af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7428af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt#endif
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_write_regs(info, &reg);
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now change fb_fix_screeninfo according to changes in par */
7464f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	info->fix.line_length = reg.stride;
7478af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	info->fix.visual = (info->var.bits_per_pixel == 8)
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				? FB_VISUAL_PSEUDOCOLOR
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				: FB_VISUAL_TRUECOLOR;
7508af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	DPRINTK("Graphics mode is now set at %dx%d depth %d\n",
7518af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		info->var.xres, info->var.yres, info->var.bits_per_pixel);
7528af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	return 0;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A handy macro shamelessly pinched from matroxfb */
7563cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7588af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
7598af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			    unsigned blue, unsigned transp,
7608af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			    struct fb_info *info)
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
762a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	struct tdfx_par *par = info->par;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 rgbcol;
7648af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
7658af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	if (regno >= info->cmap.len || regno > 255)
7668af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		return 1;
7678af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
768254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	/* grayscale works only partially under directcolor */
769254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	if (info->var.grayscale) {
770254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
7713cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		blue = (red * 77 + green * 151 + blue * 28) >> 8;
7723cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		green = blue;
7733cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		red = blue;
774254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt	}
775254c94710754127631a4e05d3131cef38c9996c7Krzysztof Helt
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (info->fix.visual) {
77754243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas	case FB_VISUAL_PSEUDOCOLOR:
7783cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		rgbcol = (((u32)red   & 0xff00) << 8) |
7793cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt			 (((u32)green & 0xff00) << 0) |
7803cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt			 (((u32)blue  & 0xff00) >> 8);
78154243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas		do_setpalentry(par, regno, rgbcol);
78254243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas		break;
78354243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas	/* Truecolor has no hardware color palettes. */
78454243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas	case FB_VISUAL_TRUECOLOR:
78554243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas		if (regno < 16) {
7868af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			rgbcol = (CNVT_TOHW(red, info->var.red.length) <<
787a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas				  info->var.red.offset) |
7888af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt				(CNVT_TOHW(green, info->var.green.length) <<
78954243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas				 info->var.green.offset) |
7908af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt				(CNVT_TOHW(blue, info->var.blue.length) <<
79154243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas				 info->var.blue.offset) |
7928af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt				(CNVT_TOHW(transp, info->var.transp.length) <<
79354243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas				 info->var.transp.offset);
79454243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas			par->palette[regno] = rgbcol;
79554243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas		}
79654243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas
79754243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas		break;
79854243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas	default:
79954243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas		DPRINTK("bad depth %u\n", info->var.bits_per_pixel);
80054243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas		break;
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
80254243cefdd3ab8133ebe7d3d705f35ca1d0b59ebAntonino A. Daplas
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tdfxfb_blank(int blank, struct fb_info *info)
8088af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt{
809a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	struct tdfx_par *par = info->par;
8104f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	int vgablank = 1;
8114f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	u32 dacmode = tdfx_inl(par, DACMODE);
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8134f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	dacmode &= ~(BIT(1) | BIT(3));
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (blank) {
8168af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */
8178af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		vgablank = 0;
8188af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
8198af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */
8208af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
8218af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */
8224f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt		dacmode |= BIT(3);
8238af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
8248af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */
8254f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt		dacmode |= BIT(1);
8268af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
8278af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */
8284f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt		dacmode |= BIT(1) | BIT(3);
8298af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8328af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	banshee_make_room(par, 1);
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tdfx_outl(par, DACMODE, dacmode);
8348af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	if (vgablank)
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vga_disable_video(par);
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vga_enable_video(par);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8418af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt/*
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the starting position of the visible screen to var->yoffset
8438af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt */
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tdfxfb_pan_display(struct fb_var_screeninfo *var,
8458af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			      struct fb_info *info)
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
847a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	struct tdfx_par *par = info->par;
8484f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	u32 addr = var->yoffset * info->fix.line_length;
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
850c2c12155cf05bf3e25eeae5711beffc634505400Krzysztof Helt	if (nopan || var->xoffset)
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	banshee_make_room(par, 1);
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tdfx_outl(par, VIDDESKSTART, addr);
8558af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_FB_3DFX_ACCEL
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8618af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt * FillRect 2D command (solidfill or invert (via ROP_XOR))
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8638af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic void tdfxfb_fillrect(struct fb_info *info,
8648af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			    const struct fb_fillrect *rect)
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
866a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	struct tdfx_par *par = info->par;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 bpp = info->var.bits_per_pixel;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 stride = info->fix.line_length;
8693cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tdfx_rop;
87192744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	u32 dx = rect->dx;
87292744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	u32 dy = rect->dy;
87392744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	u32 dstbase = 0;
8748af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
8758af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	if (rect->rop == ROP_COPY)
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tdfx_rop = TDFX_ROP_COPY;
8778af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	else
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tdfx_rop = TDFX_ROP_XOR;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
88025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* assume always rect->height < 4096 */
88192744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	if (dy + rect->height > 4095) {
88292744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		dstbase = stride * dy;
88392744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		dy = 0;
88492744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	}
88525985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* assume always rect->width < 4096 */
88692744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	if (dx + rect->width > 4095) {
88792744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		dstbase += dx * bpp >> 3;
88892744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		dx = 0;
88992744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	}
89092744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	banshee_make_room(par, 6);
8918af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, DSTFORMAT, fmt);
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
8938af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		tdfx_outl(par, COLORFORE, rect->color);
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else { /* FB_VISUAL_TRUECOLOR */
895a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas		tdfx_outl(par, COLORFORE, par->palette[rect->color]);
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8978af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24));
89892744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	tdfx_outl(par, DSTBASE, dstbase);
8998af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16));
90092744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	tdfx_outl(par, LAUNCH_2D, dx | (dy << 16));
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9048af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt * Screen-to-Screen BitBlt 2D command (for the bmove fb op.)
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9068af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic void tdfxfb_copyarea(struct fb_info *info,
9078af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			    const struct fb_copyarea *area)
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
909a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	struct tdfx_par *par = info->par;
9108af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy;
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 bpp = info->var.bits_per_pixel;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 stride = info->fix.line_length;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);
9148af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
91592744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	u32 dstbase = 0;
91692744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	u32 srcbase = 0;
91792744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt
91825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* assume always area->height < 4096 */
91992744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	if (sy + area->height > 4095) {
92092744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		srcbase = stride * sy;
92192744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		sy = 0;
92292744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	}
92325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* assume always area->width < 4096 */
92492744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	if (sx + area->width > 4095) {
92592744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		srcbase += sx * bpp >> 3;
92692744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		sx = 0;
92792744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	}
92825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* assume always area->height < 4096 */
92992744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	if (dy + area->height > 4095) {
93092744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		dstbase = stride * dy;
93192744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		dy = 0;
93292744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	}
93325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* assume always area->width < 4096 */
93492744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	if (dx + area->width > 4095) {
93592744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		dstbase += dx * bpp >> 3;
93692744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		dx = 0;
93792744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	}
93892744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (area->sx <= area->dx) {
9403cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		/* -X */
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		blitcmd |= BIT(14);
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sx += area->width - 1;
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dx += area->width - 1;
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (area->sy <= area->dy) {
9463cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		/* -Y */
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		blitcmd |= BIT(15);
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sy += area->height - 1;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dy += area->height - 1;
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9518af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
95292744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	banshee_make_room(par, 8);
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9548af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, SRCFORMAT, fmt);
9558af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, DSTFORMAT, fmt);
9568af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, COMMAND_2D, blitcmd);
9578af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, DSTSIZE, area->width | (area->height << 16));
9588af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, DSTXY, dx | (dy << 16));
95992744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	tdfx_outl(par, SRCBASE, srcbase);
96092744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	tdfx_outl(par, DSTBASE, dstbase);
9618af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, LAUNCH_2D, sx | (sy << 16));
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9648af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image)
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
966a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	struct tdfx_par *par = info->par;
9678af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	int size = image->height * ((image->width * image->depth + 7) >> 3);
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int fifo_free;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, stride = info->fix.line_length;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 bpp = info->var.bits_per_pixel;
9718af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	u32 dstfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 *chardata = (u8 *) image->data;
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 srcfmt;
97492744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	u32 dx = image->dx;
97592744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	u32 dy = image->dy;
97692744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	u32 dstbase = 0;
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (image->depth != 1) {
9793cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt#ifdef BROKEN_CODE
9803cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		banshee_make_room(par, 6 + ((size + 3) >> 2));
9813cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		srcfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13) |
9823cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt			0x400000;
9833cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt#else
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfb_imageblit(info, image);
9853cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt#endif
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
98792744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	}
98892744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	banshee_make_room(par, 9);
98992744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	switch (info->fix.visual) {
99092744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	case FB_VISUAL_PSEUDOCOLOR:
99192744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		tdfx_outl(par, COLORFORE, image->fg_color);
99292744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		tdfx_outl(par, COLORBACK, image->bg_color);
99392744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		break;
99492744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	case FB_VISUAL_TRUECOLOR:
99592744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	default:
99692744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		tdfx_outl(par, COLORFORE,
99792744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt			  par->palette[image->fg_color]);
99892744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		tdfx_outl(par, COLORBACK,
99992744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt			  par->palette[image->bg_color]);
100092744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	}
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __BIG_ENDIAN
100292744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	srcfmt = 0x400000 | BIT(20);
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
100492744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	srcfmt = 0x400000;
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
100625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* assume always image->height < 4096 */
100792744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	if (dy + image->height > 4095) {
100892744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		dstbase = stride * dy;
100992744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		dy = 0;
101092744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	}
101125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* assume always image->width < 4096 */
101292744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	if (dx + image->width > 4095) {
101392744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		dstbase += dx * bpp >> 3;
101492744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		dx = 0;
10158af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	}
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
101792744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	tdfx_outl(par, DSTBASE, dstbase);
10188af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, SRCXY, 0);
101992744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	tdfx_outl(par, DSTXY, dx | (dy << 16));
10203cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	tdfx_outl(par, COMMAND_2D,
10213cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		  COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
10228af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, SRCFORMAT, srcfmt);
10238af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, DSTFORMAT, dstfmt);
10248af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	tdfx_outl(par, DSTSIZE, image->width | (image->height << 16));
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* A count of how many free FIFO entries we've requested.
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * When this goes negative, we need to request more. */
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fifo_free = 0;
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10308af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	/* Send four bytes at a time of data */
10318af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	for (i = (size >> 2); i > 0; i--) {
10328af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		if (--fifo_free < 0) {
10338af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			fifo_free = 31;
10348af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			banshee_make_room(par, fifo_free);
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10363cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		tdfx_outl(par, LAUNCH_2D, *(u32 *)chardata);
10378af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		chardata += 4;
10388af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	}
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10408af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	/* Send the leftovers now */
10418af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	banshee_make_room(par, 3);
10424f05b53b28cc7a2b868bc13d19d88cd858e759b6Krzysztof Helt	switch (size % 4) {
10438af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case 0:
10448af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
10458af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case 1:
10468af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		tdfx_outl(par, LAUNCH_2D, *chardata);
10478af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
10488af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case 2:
10493cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		tdfx_outl(par, LAUNCH_2D, *(u16 *)chardata);
10508af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
10518af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case 3:
10528af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		tdfx_outl(par, LAUNCH_2D,
10533cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt			*(u16 *)chardata | (chardata[3] << 24));
10548af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_FB_3DFX_ACCEL */
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1061a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	struct tdfx_par *par = info->par;
106290b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	u32 vidcfg;
106390b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt
106490b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	if (!hwcursor)
106590b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		return -EINVAL;	/* just to force soft_cursor() call */
106690b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt
106790b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	/* Too large of a cursor or wrong bpp :-( */
106890b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	if (cursor->image.width > 64 ||
106990b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	    cursor->image.height > 64 ||
107090b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	    cursor->image.depth > 1)
107190b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		return -EINVAL;
107290b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt
107390b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	vidcfg = tdfx_inl(par, VIDPROCCFG);
107490b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	if (cursor->enable)
107590b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		tdfx_outl(par, VIDPROCCFG, vidcfg | VIDCFG_HWCURSOR_ENABLE);
107690b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	else
107790b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		tdfx_outl(par, VIDPROCCFG, vidcfg & ~VIDCFG_HWCURSOR_ENABLE);
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
10808af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	 * If the cursor is not be changed this means either we want the
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * current cursor state (if enable is set) or we want to query what
10828af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	 * we can do with the cursor (if enable is not set)
10838af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	 */
10848af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	if (!cursor->set)
10858af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		return 0;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* fix cursor color - XFree86 forgets to restore it properly */
108890b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	if (cursor->set & FB_CUR_SETCMAP) {
108990b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		struct fb_cmap cmap = info->cmap;
109090b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		u32 bg_idx = cursor->image.bg_color;
109190b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		u32 fg_idx = cursor->image.fg_color;
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long bg_color, fg_color;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
109490b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		fg_color = (((u32)cmap.red[fg_idx]   & 0xff00) << 8) |
109590b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt			   (((u32)cmap.green[fg_idx] & 0xff00) << 0) |
109690b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt			   (((u32)cmap.blue[fg_idx]  & 0xff00) >> 8);
109790b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		bg_color = (((u32)cmap.red[bg_idx]   & 0xff00) << 8) |
109890b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt			   (((u32)cmap.green[bg_idx] & 0xff00) << 0) |
109990b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt			   (((u32)cmap.blue[bg_idx]  & 0xff00) >> 8);
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		banshee_make_room(par, 2);
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tdfx_outl(par, HWCURC0, bg_color);
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tdfx_outl(par, HWCURC1, fg_color);
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
110590b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	if (cursor->set & FB_CUR_SETPOS) {
110690b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		int x = cursor->image.dx;
110790b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		int y = cursor->image.dy - info->var.yoffset;
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x += 63;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		y += 63;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		banshee_make_room(par, 1);
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tdfx_outl(par, HWCURLOC, (y << 16) + x);
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
111490b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	if (cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
11168af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		 * Voodoo 3 and above cards use 2 monochrome cursor patterns.
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *    The reason is so the card can fetch 8 words at a time
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * and are stored on chip for use for the next 8 scanlines.
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * This reduces the number of times for access to draw the
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * cursor for each screen refresh.
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *    Each pattern is a bitmap of 64 bit wide and 64 bit high
112290b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		 * (total of 8192 bits or 1024 bytes). The two patterns are
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * stored in such a way that pattern 0 always resides in the
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * lower half (least significant 64 bits) of a 128 bit word
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * and pattern 1 the upper half. If you examine the data of
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the cursor image the graphics card uses then from the
112725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		 * beginning you see line one of pattern 0, line one of
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * pattern 1, line two of pattern 0, line two of pattern 1,
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * etc etc. The linear stride for the cursor is always 16 bytes
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (128 bits) which is the maximum cursor width times two for
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the two monochrome patterns.
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
113390b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		u8 __iomem *cursorbase = info->screen_base + info->fix.smem_len;
113490b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		u8 *bitmap = (u8 *)cursor->image.data;
113590b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		u8 *mask = (u8 *)cursor->mask;
113690b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		int i;
113790b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt
113890b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		fb_memset(cursorbase, 0, 1024);
113990b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt
114090b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		for (i = 0; i < cursor->image.height; i++) {
114190b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt			int h = 0;
114290b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt			int j = (cursor->image.width + 7) >> 3;
114390b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt
114490b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt			for (; j > 0; j--) {
114590b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt				u8 data = *mask ^ *bitmap;
114690b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt				if (cursor->rop == ROP_COPY)
114790b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt					data = *mask & *bitmap;
114890b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt				/* Pattern 0. Copy the cursor mask to it */
114990b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt				fb_writeb(*mask, cursorbase + h);
115090b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt				mask++;
115190b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt				/* Pattern 1. Copy the cursor bitmap to it */
115290b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt				fb_writeb(data, cursorbase + h + 8);
115390b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt				bitmap++;
115490b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt				h++;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
115690b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt			cursorbase += 16;
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11628af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Heltstatic struct fb_ops tdfxfb_ops = {
11638af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.owner		= THIS_MODULE,
11648af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.fb_check_var	= tdfxfb_check_var,
11658af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.fb_set_par	= tdfxfb_set_par,
11668af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.fb_setcolreg	= tdfxfb_setcolreg,
11678af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.fb_blank	= tdfxfb_blank,
11688af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.fb_pan_display	= tdfxfb_pan_display,
11698af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.fb_sync	= banshee_wait_idle,
117090b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	.fb_cursor	= tdfxfb_cursor,
11718af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt#ifdef CONFIG_FB_3DFX_ACCEL
11728af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.fb_fillrect	= tdfxfb_fillrect,
11738af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.fb_copyarea	= tdfxfb_copyarea,
11748af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.fb_imageblit	= tdfxfb_imageblit,
11758af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt#else
11768af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.fb_fillrect	= cfb_fillrect,
11778af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.fb_copyarea	= cfb_copyarea,
11788af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	.fb_imageblit	= cfb_imageblit,
11798af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt#endif
11808af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt};
11818af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
1182feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt#ifdef CONFIG_FB_3DFX_I2C
1183feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt/* The voo GPIO registers don't have individual masks for each bit
1184feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt   so we always have to read before writing. */
1185feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1186feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Heltstatic void tdfxfb_i2c_setscl(void *data, int val)
1187feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt{
1188feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfxfb_i2c_chan 	*chan = data;
1189feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfx_par 	*par = chan->par;
1190feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	unsigned int r;
1191feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1192feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	r = tdfx_inl(par, VIDSERPARPORT);
1193feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	if (val)
1194feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		r |= I2C_SCL_OUT;
1195feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	else
1196feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		r &= ~I2C_SCL_OUT;
1197feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfx_outl(par, VIDSERPARPORT, r);
1198feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfx_inl(par, VIDSERPARPORT);	/* flush posted write */
1199feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt}
1200feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1201feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Heltstatic void tdfxfb_i2c_setsda(void *data, int val)
1202feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt{
1203feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfxfb_i2c_chan 	*chan = data;
1204feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfx_par 	*par = chan->par;
1205feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	unsigned int r;
1206feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1207feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	r = tdfx_inl(par, VIDSERPARPORT);
1208feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	if (val)
1209feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		r |= I2C_SDA_OUT;
1210feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	else
1211feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		r &= ~I2C_SDA_OUT;
1212feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfx_outl(par, VIDSERPARPORT, r);
1213feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfx_inl(par, VIDSERPARPORT);	/* flush posted write */
1214feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt}
1215feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1216feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt/* The GPIO pins are open drain, so the pins always remain outputs.
1217feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt   We rely on the i2c-algo-bit routines to set the pins high before
1218feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt   reading the input from other chips. */
1219feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1220feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Heltstatic int tdfxfb_i2c_getscl(void *data)
1221feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt{
1222feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfxfb_i2c_chan 	*chan = data;
1223feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfx_par 	*par = chan->par;
1224feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1225feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	return (0 != (tdfx_inl(par, VIDSERPARPORT) & I2C_SCL_IN));
1226feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt}
1227feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1228feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Heltstatic int tdfxfb_i2c_getsda(void *data)
1229feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt{
1230feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfxfb_i2c_chan 	*chan = data;
1231feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfx_par 	*par = chan->par;
1232feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1233feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	return (0 != (tdfx_inl(par, VIDSERPARPORT) & I2C_SDA_IN));
1234feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt}
1235feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1236feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Heltstatic void tdfxfb_ddc_setscl(void *data, int val)
1237feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt{
1238feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfxfb_i2c_chan 	*chan = data;
1239feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfx_par 	*par = chan->par;
1240feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	unsigned int r;
1241feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1242feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	r = tdfx_inl(par, VIDSERPARPORT);
1243feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	if (val)
1244feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		r |= DDC_SCL_OUT;
1245feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	else
1246feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		r &= ~DDC_SCL_OUT;
1247feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfx_outl(par, VIDSERPARPORT, r);
1248feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfx_inl(par, VIDSERPARPORT);	/* flush posted write */
1249feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt}
1250feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1251feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Heltstatic void tdfxfb_ddc_setsda(void *data, int val)
1252feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt{
1253feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfxfb_i2c_chan 	*chan = data;
1254feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfx_par 	*par = chan->par;
1255feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	unsigned int r;
1256feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1257feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	r = tdfx_inl(par, VIDSERPARPORT);
1258feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	if (val)
1259feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		r |= DDC_SDA_OUT;
1260feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	else
1261feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		r &= ~DDC_SDA_OUT;
1262feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfx_outl(par, VIDSERPARPORT, r);
1263feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfx_inl(par, VIDSERPARPORT);	/* flush posted write */
1264feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt}
1265feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1266feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Heltstatic int tdfxfb_ddc_getscl(void *data)
1267feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt{
1268feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfxfb_i2c_chan 	*chan = data;
1269feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfx_par 	*par = chan->par;
1270feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1271feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	return (0 != (tdfx_inl(par, VIDSERPARPORT) & DDC_SCL_IN));
1272feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt}
1273feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1274feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Heltstatic int tdfxfb_ddc_getsda(void *data)
1275feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt{
1276feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfxfb_i2c_chan 	*chan = data;
1277feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfx_par 	*par = chan->par;
1278feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1279feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	return (0 != (tdfx_inl(par, VIDSERPARPORT) & DDC_SDA_IN));
1280feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt}
1281feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1282feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Heltstatic int __devinit tdfxfb_setup_ddc_bus(struct tdfxfb_i2c_chan *chan,
1283feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt					  const char *name, struct device *dev)
1284feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt{
1285feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	int rc;
1286feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1287feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name));
1288feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->adapter.owner		= THIS_MODULE;
1289feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->adapter.class		= I2C_CLASS_DDC;
1290feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->adapter.algo_data		= &chan->algo;
1291feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->adapter.dev.parent	= dev;
1292feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.setsda		= tdfxfb_ddc_setsda;
1293feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.setscl		= tdfxfb_ddc_setscl;
1294feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.getsda		= tdfxfb_ddc_getsda;
1295feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.getscl		= tdfxfb_ddc_getscl;
1296feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.udelay		= 10;
1297feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.timeout		= msecs_to_jiffies(500);
1298feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.data 		= chan;
1299feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1300feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	i2c_set_adapdata(&chan->adapter, chan);
1301feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1302feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	rc = i2c_bit_add_bus(&chan->adapter);
1303feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	if (rc == 0)
1304feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		DPRINTK("I2C bus %s registered.\n", name);
1305feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	else
1306feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		chan->par = NULL;
1307feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1308feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	return rc;
1309feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt}
1310feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1311feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Heltstatic int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan,
1312feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt					  const char *name, struct device *dev)
1313feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt{
1314feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	int rc;
1315feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1316feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name));
1317feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->adapter.owner		= THIS_MODULE;
1318feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->adapter.algo_data		= &chan->algo;
1319feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->adapter.dev.parent	= dev;
1320feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.setsda		= tdfxfb_i2c_setsda;
1321feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.setscl		= tdfxfb_i2c_setscl;
1322feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.getsda		= tdfxfb_i2c_getsda;
1323feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.getscl		= tdfxfb_i2c_getscl;
1324feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.udelay		= 10;
1325feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.timeout		= msecs_to_jiffies(500);
1326feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	chan->algo.data 		= chan;
1327feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1328feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	i2c_set_adapdata(&chan->adapter, chan);
1329feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1330feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	rc = i2c_bit_add_bus(&chan->adapter);
1331feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	if (rc == 0)
1332feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		DPRINTK("I2C bus %s registered.\n", name);
1333feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	else
1334feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		chan->par = NULL;
1335feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1336feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	return rc;
1337feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt}
1338feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1339feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Heltstatic void __devinit tdfxfb_create_i2c_busses(struct fb_info *info)
1340feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt{
1341feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	struct tdfx_par *par = info->par;
1342feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1343feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfx_outl(par, VIDINFORMAT, 0x8160);
1344feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfx_outl(par, VIDSERPARPORT, 0xcffc0020);
1345feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1346feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	par->chan[0].par = par;
1347feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	par->chan[1].par = par;
1348feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1349feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfxfb_setup_ddc_bus(&par->chan[0], "Voodoo3-DDC", info->dev);
1350feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfxfb_setup_i2c_bus(&par->chan[1], "Voodoo3-I2C", info->dev);
1351feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt}
1352feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1353feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Heltstatic void tdfxfb_delete_i2c_busses(struct tdfx_par *par)
1354feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt{
1355feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	if (par->chan[0].par)
1356feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		i2c_del_adapter(&par->chan[0].adapter);
1357feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	par->chan[0].par = NULL;
1358feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
1359feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	if (par->chan[1].par)
1360feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt		i2c_del_adapter(&par->chan[1].adapter);
1361feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	par->chan[1].par = NULL;
1362feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt}
1363215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt
1364215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Heltstatic int tdfxfb_probe_i2c_connector(struct tdfx_par *par,
1365215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt				      struct fb_monspecs *specs)
1366215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt{
1367215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	u8 *edid = NULL;
1368215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt
1369215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	DPRINTK("Probe DDC Bus\n");
1370215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	if (par->chan[0].par)
1371215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		edid = fb_ddc_read(&par->chan[0].adapter);
1372215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt
1373215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	if (edid) {
1374215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		fb_edid_to_monspecs(edid, specs);
1375215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		kfree(edid);
1376215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		return 0;
1377215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	}
1378215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	return 1;
1379215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt}
1380feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt#endif /* CONFIG_FB_3DFX_I2C */
1381feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      tdfxfb_probe - Device Initializiation
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      @pdev:  PCI Device to initialize
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      @id:    PCI Device ID
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Initializes and allocates resources for PCI device @pdev.
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit tdfxfb_probe(struct pci_dev *pdev,
13928af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt				  const struct pci_device_id *id)
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tdfx_par *default_par;
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fb_info *info;
1396a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	int err, lpitch;
1397215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	struct fb_monspecs *specs;
1398215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	bool found;
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14003cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	err = pci_enable_device(pdev);
14013cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	if (err) {
14023cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		printk(KERN_ERR "tdfxfb: Can't enable pdev: %d\n", err);
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1406a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	info = framebuffer_alloc(sizeof(struct tdfx_par), &pdev->dev);
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1408a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	if (!info)
1409a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas		return -ENOMEM;
14108af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default_par = info->par;
14123b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	info->fix = tdfx_fix;
14138af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Configure the default fb_fix_screeninfo first */
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (pdev->device) {
14168af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case PCI_DEVICE_ID_3DFX_BANSHEE:
14173b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt		strcpy(info->fix.id, "3Dfx Banshee");
14188af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK;
14198af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
14208af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case PCI_DEVICE_ID_3DFX_VOODOO3:
14213b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt		strcpy(info->fix.id, "3Dfx Voodoo3");
14228af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK;
14238af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
14248af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	case PCI_DEVICE_ID_3DFX_VOODOO5:
14253b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt		strcpy(info->fix.id, "3Dfx Voodoo5");
14268af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK;
14278af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		break;
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14303b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	info->fix.mmio_start = pci_resource_start(pdev, 0);
14313b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	info->fix.mmio_len = pci_resource_len(pdev, 0);
14323b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	if (!request_mem_region(info->fix.mmio_start, info->fix.mmio_len,
143392744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt				"tdfx regbase")) {
14343cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		printk(KERN_ERR "tdfxfb: Can't reserve regbase\n");
143592744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		goto out_err;
143692744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	}
143792744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt
14388af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	default_par->regbase_virt =
14393b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt		ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!default_par->regbase_virt) {
14413cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		printk(KERN_ERR "fb: Can't remap %s register area.\n",
14423b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt				info->fix.id);
144392744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		goto out_err_regbase;
14448af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	}
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14463b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	info->fix.smem_start = pci_resource_start(pdev, 1);
14473b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	info->fix.smem_len = do_lfb_size(default_par, pdev->device);
14483b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	if (!info->fix.smem_len) {
14493b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt		printk(KERN_ERR "fb: Can't count %s memory.\n", info->fix.id);
145092744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		goto out_err_regbase;
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14533b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	if (!request_mem_region(info->fix.smem_start,
14548af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt				pci_resource_len(pdev, 1), "tdfx smem")) {
14553cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		printk(KERN_ERR "tdfxfb: Can't reserve smem\n");
145692744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		goto out_err_regbase;
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14593b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	info->screen_base = ioremap_nocache(info->fix.smem_start,
14603b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt					    info->fix.smem_len);
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info->screen_base) {
14623cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		printk(KERN_ERR "fb: Can't remap %s framebuffer.\n",
14633b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt				info->fix.id);
146492744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		goto out_err_screenbase;
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default_par->iobase = pci_resource_start(pdev, 2);
14688af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!request_region(pci_resource_start(pdev, 2),
14708af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt			    pci_resource_len(pdev, 2), "tdfx iobase")) {
14713cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		printk(KERN_ERR "tdfxfb: Can't reserve iobase\n");
147292744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		goto out_err_screenbase;
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14753b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	printk(KERN_INFO "fb: %s memory = %dK\n", info->fix.id,
14763b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt			info->fix.smem_len >> 10);
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14780960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt	default_par->mtrr_handle = -1;
14790960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt	if (!nomtrr)
14800960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt		default_par->mtrr_handle =
14813b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt			mtrr_add(info->fix.smem_start, info->fix.smem_len,
14820960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt				 MTRR_TYPE_WRCOMB, 1);
14830960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt
14843b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	info->fix.ypanstep	= nopan ? 0 : 1;
14853b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	info->fix.ywrapstep	= nowrap ? 0 : 1;
14868af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->fbops		= &tdfxfb_ops;
1488a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	info->pseudo_palette	= default_par->palette;
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->flags		= FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_FB_3DFX_ACCEL
14913cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt	info->flags		|= FBINFO_HWACCEL_FILLRECT |
149292744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt				   FBINFO_HWACCEL_COPYAREA |
149392744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt				   FBINFO_HWACCEL_IMAGEBLIT |
149492744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt				   FBINFO_READS_FAST;
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
149690b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	/* reserve 8192 bits for cursor */
149790b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	/* the 2.4 driver says PAGE_MASK boundary is not enough for Voodoo4 */
149890b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt	if (hwcursor)
149990b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt		info->fix.smem_len = (info->fix.smem_len - 1024) &
150090b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt					(PAGE_MASK << 1);
1501215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	specs = &info->monspecs;
1502215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	found = false;
1503215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	info->var.bits_per_pixel = 8;
1504feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt#ifdef CONFIG_FB_3DFX_I2C
1505feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfxfb_create_i2c_busses(info);
1506215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	err = tdfxfb_probe_i2c_connector(default_par, specs);
1507215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt
1508215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	if (!err) {
1509215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		if (specs->modedb == NULL)
1510215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt			DPRINTK("Unable to get Mode Database\n");
1511215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		else {
1512215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt			const struct fb_videomode *m;
1513215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt
1514215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt			fb_videomode_to_modelist(specs->modedb,
1515215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt						 specs->modedb_len,
1516215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt						 &info->modelist);
1517215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt			m = fb_find_best_display(specs, &info->modelist);
1518215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt			if (m) {
1519215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt				fb_videomode_to_var(&info->var, m);
1520215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt				/* fill all other info->var's fields */
1521215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt				if (tdfxfb_check_var(&info->var, info) < 0)
1522215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt					info->var = tdfx_var;
1523215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt				else
1524215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt					found = true;
1525215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt			}
1526215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		}
1527215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	}
1528feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt#endif
1529215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	if (!mode_option && !found)
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mode_option = "640x480@60";
15318af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
1532215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	if (mode_option) {
1533215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		err = fb_find_mode(&info->var, info, mode_option,
1534215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt				   specs->modedb, specs->modedb_len,
1535215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt				   NULL, info->var.bits_per_pixel);
1536215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		if (!err || err == 4)
1537215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt			info->var = tdfx_var;
1538215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	}
1539215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt
1540215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	if (found) {
1541215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		fb_destroy_modedb(specs->modedb);
1542215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt		specs->modedb = NULL;
1543215059d2421f95c30d1fca6ff31357fcae9f67dcKrzysztof Helt	}
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* maximize virtual vertical length */
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3);
15478af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	info->var.yres_virtual = info->fix.smem_len / lpitch;
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (info->var.yres_virtual < info->var.yres)
154992744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		goto out_err_iobase;
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
15523cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		printk(KERN_ERR "tdfxfb: Can't allocate color map\n");
155392744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		goto out_err_iobase;
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (register_framebuffer(info) < 0) {
15573cbe9cff92a52a2c2dd4767292b97884b67afe36Krzysztof Helt		printk(KERN_ERR "tdfxfb: can't register framebuffer\n");
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fb_dealloc_cmap(&info->cmap);
155992744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		goto out_err_iobase;
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Our driver data
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_set_drvdata(pdev, info);
15658af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	return 0;
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
156792744dd517258181af0637105eed5f72d95e05e7Krzysztof Heltout_err_iobase:
1568feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt#ifdef CONFIG_FB_3DFX_I2C
1569feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfxfb_delete_i2c_busses(default_par);
1570feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt#endif
15710960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt	if (default_par->mtrr_handle >= 0)
15720960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt		mtrr_del(default_par->mtrr_handle, info->fix.smem_start,
15730960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt			 info->fix.smem_len);
157426692f53ef550f7b8dc43fc5171c6187094632a8Julia Lawall	release_region(pci_resource_start(pdev, 2),
157526692f53ef550f7b8dc43fc5171c6187094632a8Julia Lawall		       pci_resource_len(pdev, 2));
157692744dd517258181af0637105eed5f72d95e05e7Krzysztof Heltout_err_screenbase:
157792744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt	if (info->screen_base)
157892744dd517258181af0637105eed5f72d95e05e7Krzysztof Helt		iounmap(info->screen_base);
15793b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	release_mem_region(info->fix.smem_start, pci_resource_len(pdev, 1));
158092744dd517258181af0637105eed5f72d95e05e7Krzysztof Heltout_err_regbase:
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Cleanup after anything that was remapped/allocated.
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (default_par->regbase_virt)
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iounmap(default_par->regbase_virt);
15863b25613c276d390d1dd1d69f238ee779611ccc6cKrzysztof Helt	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
158792744dd517258181af0637105eed5f72d95e05e7Krzysztof Heltout_err:
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	framebuffer_release(info);
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENXIO;
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE
15930ce85eb8824679cd9e7b3b12202e2bf54f1f3e2cRandy Dunlapstatic void __init tdfxfb_setup(char *options)
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15958af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	char *this_opt;
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!options || !*options)
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((this_opt = strsep(&options, ",")) != NULL) {
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!*this_opt)
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
16038af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		if (!strcmp(this_opt, "nopan")) {
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nopan = 1;
16058af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt		} else if (!strcmp(this_opt, "nowrap")) {
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nowrap = 1;
16070960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt		} else if (!strncmp(this_opt, "hwcursor=", 9)) {
16080960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt			hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
16090960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt#ifdef CONFIG_MTRR
16100960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt		} else if (!strncmp(this_opt, "nomtrr", 6)) {
16110960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt			nomtrr = 1;
16120960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt#endif
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode_option = this_opt;
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      tdfxfb_remove - Device removal
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      @pdev:  PCI Device to cleanup
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Releases all resources allocated during the course of the driver's
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      lifetime for the PCI device @pdev.
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devexit tdfxfb_remove(struct pci_dev *pdev)
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fb_info *info = pci_get_drvdata(pdev);
1632a807f618b62594467a52b488912bd77606af0572Antonino A. Daplas	struct tdfx_par *par = info->par;
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_framebuffer(info);
1635feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt#ifdef CONFIG_FB_3DFX_I2C
1636feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt	tdfxfb_delete_i2c_busses(par);
1637feff3880d06da0cc8fc65b9e40f518fea7594674Krzysztof Helt#endif
16380960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt	if (par->mtrr_handle >= 0)
16390960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt		mtrr_del(par->mtrr_handle, info->fix.smem_start,
16400960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt			 info->fix.smem_len);
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(par->regbase_virt);
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(info->screen_base);
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Clean up after reserved regions */
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(pci_resource_start(pdev, 2),
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       pci_resource_len(pdev, 2));
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_mem_region(pci_resource_start(pdev, 1),
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   pci_resource_len(pdev, 1));
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_mem_region(pci_resource_start(pdev, 0),
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   pci_resource_len(pdev, 0));
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_set_drvdata(pdev, NULL);
1652895d72279da7f24f266f9583c239e7b22230127cAndres Salomon	fb_dealloc_cmap(&info->cmap);
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	framebuffer_release(info);
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init tdfxfb_init(void)
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *option = NULL;
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fb_get_options("tdfxfb", &option))
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tdfxfb_setup(option);
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
16668af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	return pci_register_driver(&tdfxfb_driver);
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit tdfxfb_exit(void)
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16718af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt	pci_unregister_driver(&tdfxfb_driver);
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>");
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("3Dfx framebuffer device driver");
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
16778af1d50f7f679375f579782f2d5eb5e2a1508df8Krzysztof Helt
167890b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Heltmodule_param(hwcursor, int, 0644);
167990b0f08536531abbbe7b5d4944792da08cadde01Krzysztof HeltMODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
168090b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt			"(1=enable, 0=disable, default=1)");
1681ea9014bcacf236124d5e0ff971838049a98456cbKrzysztof Heltmodule_param(mode_option, charp, 0);
1682ea9014bcacf236124d5e0ff971838049a98456cbKrzysztof HeltMODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
16830960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt#ifdef CONFIG_MTRR
16840960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Heltmodule_param(nomtrr, bool, 0);
16850960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof HeltMODULE_PARM_DESC(nomtrr, "Disable MTRR support (default: enabled)");
16860960bd3db199d73b07e4d266949dcdd6dda10d54Krzysztof Helt#endif
168790b0f08536531abbbe7b5d4944792da08cadde01Krzysztof Helt
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(tdfxfb_init);
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(tdfxfb_exit);
1690