Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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