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