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(®, 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, ®); 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