1/* 2 * linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device 3 * 4 * Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>. 5 * 6 * Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl> 7 * based on pm2fb.c 8 * 9 * Based on code written by: 10 * Sven Luther, <luther@dpt-info.u-strasbg.fr> 11 * Alan Hourihane, <alanh@fairlite.demon.co.uk> 12 * Russell King, <rmk@arm.linux.org.uk> 13 * Based on linux/drivers/video/skeletonfb.c: 14 * Copyright (C) 1997 Geert Uytterhoeven 15 * Based on linux/driver/video/pm2fb.c: 16 * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) 17 * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) 18 * 19 * This file is subject to the terms and conditions of the GNU General Public 20 * License. See the file COPYING in the main directory of this archive for 21 * more details. 22 * 23 */ 24 25#include <linux/module.h> 26#include <linux/kernel.h> 27#include <linux/errno.h> 28#include <linux/string.h> 29#include <linux/mm.h> 30#include <linux/slab.h> 31#include <linux/delay.h> 32#include <linux/fb.h> 33#include <linux/init.h> 34#include <linux/pci.h> 35 36#include <video/pm3fb.h> 37 38#if !defined(CONFIG_PCI) 39#error "Only generic PCI cards supported." 40#endif 41 42#undef PM3FB_MASTER_DEBUG 43#ifdef PM3FB_MASTER_DEBUG 44#define DPRINTK(a,b...) printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b) 45#else 46#define DPRINTK(a,b...) 47#endif 48 49/* 50 * Driver data 51 */ 52static char *mode_option __devinitdata; 53 54/* 55 * This structure defines the hardware state of the graphics card. Normally 56 * you place this in a header file in linux/include/video. This file usually 57 * also includes register information. That allows other driver subsystems 58 * and userland applications the ability to use the same header file to 59 * avoid duplicate work and easy porting of software. 60 */ 61struct pm3_par { 62 unsigned char __iomem *v_regs;/* virtual address of p_regs */ 63 u32 video; /* video flags before blanking */ 64 u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */ 65 u32 palette[16]; 66}; 67 68/* 69 * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo 70 * if we don't use modedb. If we do use modedb see pm3fb_init how to use it 71 * to get a fb_var_screeninfo. Otherwise define a default var as well. 72 */ 73static struct fb_fix_screeninfo pm3fb_fix __devinitdata = { 74 .id = "Permedia3", 75 .type = FB_TYPE_PACKED_PIXELS, 76 .visual = FB_VISUAL_PSEUDOCOLOR, 77 .xpanstep = 1, 78 .ypanstep = 1, 79 .ywrapstep = 0, 80 .accel = FB_ACCEL_NONE, 81}; 82 83/* 84 * Utility functions 85 */ 86 87static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off) 88{ 89 return fb_readl(par->v_regs + off); 90} 91 92static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v) 93{ 94 fb_writel(v, par->v_regs + off); 95} 96 97static inline void PM3_WAIT(struct pm3_par *par, u32 n) 98{ 99 while (PM3_READ_REG(par, PM3InFIFOSpace) < n); 100} 101 102static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v) 103{ 104 PM3_WAIT(par, 3); 105 PM3_WRITE_REG(par, PM3RD_IndexHigh, (r >> 8) & 0xff); 106 PM3_WRITE_REG(par, PM3RD_IndexLow, r & 0xff); 107 wmb(); 108 PM3_WRITE_REG(par, PM3RD_IndexedData, v); 109 wmb(); 110} 111 112static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno, 113 unsigned char r, unsigned char g, unsigned char b) 114{ 115 PM3_WAIT(par, 4); 116 PM3_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno); 117 wmb(); 118 PM3_WRITE_REG(par, PM3RD_PaletteData, r); 119 wmb(); 120 PM3_WRITE_REG(par, PM3RD_PaletteData, g); 121 wmb(); 122 PM3_WRITE_REG(par, PM3RD_PaletteData, b); 123 wmb(); 124} 125 126static void pm3fb_clear_colormap(struct pm3_par *par, 127 unsigned char r, unsigned char g, unsigned char b) 128{ 129 int i; 130 131 for (i = 0; i < 256 ; i++) 132 pm3fb_set_color(par, i, r, g, b); 133 134} 135 136/* Calculating various clock parameter */ 137static void pm3fb_calculate_clock(unsigned long reqclock, 138 unsigned char *prescale, 139 unsigned char *feedback, 140 unsigned char *postscale) 141{ 142 int f, pre, post; 143 unsigned long freq; 144 long freqerr = 1000; 145 long currerr; 146 147 for (f = 1; f < 256; f++) { 148 for (pre = 1; pre < 256; pre++) { 149 for (post = 0; post < 5; post++) { 150 freq = ((2*PM3_REF_CLOCK * f) >> post) / pre; 151 currerr = (reqclock > freq) 152 ? reqclock - freq 153 : freq - reqclock; 154 if (currerr < freqerr) { 155 freqerr = currerr; 156 *feedback = f; 157 *prescale = pre; 158 *postscale = post; 159 } 160 } 161 } 162 } 163} 164 165static inline int pm3fb_depth(const struct fb_var_screeninfo *var) 166{ 167 if ( var->bits_per_pixel == 16 ) 168 return var->red.length + var->green.length 169 + var->blue.length; 170 171 return var->bits_per_pixel; 172} 173 174static inline int pm3fb_shift_bpp(unsigned bpp, int v) 175{ 176 switch (bpp) { 177 case 8: 178 return (v >> 4); 179 case 16: 180 return (v >> 3); 181 case 32: 182 return (v >> 2); 183 } 184 DPRINTK("Unsupported depth %u\n", bpp); 185 return 0; 186} 187 188/* write the mode to registers */ 189static void pm3fb_write_mode(struct fb_info *info) 190{ 191 struct pm3_par *par = info->par; 192 char tempsync = 0x00, tempmisc = 0x00; 193 const u32 hsstart = info->var.right_margin; 194 const u32 hsend = hsstart + info->var.hsync_len; 195 const u32 hbend = hsend + info->var.left_margin; 196 const u32 xres = (info->var.xres + 31) & ~31; 197 const u32 htotal = xres + hbend; 198 const u32 vsstart = info->var.lower_margin; 199 const u32 vsend = vsstart + info->var.vsync_len; 200 const u32 vbend = vsend + info->var.upper_margin; 201 const u32 vtotal = info->var.yres + vbend; 202 const u32 width = (info->var.xres_virtual + 7) & ~7; 203 const unsigned bpp = info->var.bits_per_pixel; 204 205 PM3_WAIT(par, 20); 206 PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff); 207 PM3_WRITE_REG(par, PM3Aperture0, 0x00000000); 208 PM3_WRITE_REG(par, PM3Aperture1, 0x00000000); 209 PM3_WRITE_REG(par, PM3FIFODis, 0x00000007); 210 211 PM3_WRITE_REG(par, PM3HTotal, 212 pm3fb_shift_bpp(bpp, htotal - 1)); 213 PM3_WRITE_REG(par, PM3HsEnd, 214 pm3fb_shift_bpp(bpp, hsend)); 215 PM3_WRITE_REG(par, PM3HsStart, 216 pm3fb_shift_bpp(bpp, hsstart)); 217 PM3_WRITE_REG(par, PM3HbEnd, 218 pm3fb_shift_bpp(bpp, hbend)); 219 PM3_WRITE_REG(par, PM3HgEnd, 220 pm3fb_shift_bpp(bpp, hbend)); 221 PM3_WRITE_REG(par, PM3ScreenStride, 222 pm3fb_shift_bpp(bpp, width)); 223 PM3_WRITE_REG(par, PM3VTotal, vtotal - 1); 224 PM3_WRITE_REG(par, PM3VsEnd, vsend - 1); 225 PM3_WRITE_REG(par, PM3VsStart, vsstart - 1); 226 PM3_WRITE_REG(par, PM3VbEnd, vbend); 227 228 switch (bpp) { 229 case 8: 230 PM3_WRITE_REG(par, PM3ByAperture1Mode, 231 PM3ByApertureMode_PIXELSIZE_8BIT); 232 PM3_WRITE_REG(par, PM3ByAperture2Mode, 233 PM3ByApertureMode_PIXELSIZE_8BIT); 234 break; 235 236 case 16: 237#ifndef __BIG_ENDIAN 238 PM3_WRITE_REG(par, PM3ByAperture1Mode, 239 PM3ByApertureMode_PIXELSIZE_16BIT); 240 PM3_WRITE_REG(par, PM3ByAperture2Mode, 241 PM3ByApertureMode_PIXELSIZE_16BIT); 242#else 243 PM3_WRITE_REG(par, PM3ByAperture1Mode, 244 PM3ByApertureMode_PIXELSIZE_16BIT | 245 PM3ByApertureMode_BYTESWAP_BADC); 246 PM3_WRITE_REG(par, PM3ByAperture2Mode, 247 PM3ByApertureMode_PIXELSIZE_16BIT | 248 PM3ByApertureMode_BYTESWAP_BADC); 249#endif /* ! __BIG_ENDIAN */ 250 break; 251 252 case 32: 253#ifndef __BIG_ENDIAN 254 PM3_WRITE_REG(par, PM3ByAperture1Mode, 255 PM3ByApertureMode_PIXELSIZE_32BIT); 256 PM3_WRITE_REG(par, PM3ByAperture2Mode, 257 PM3ByApertureMode_PIXELSIZE_32BIT); 258#else 259 PM3_WRITE_REG(par, PM3ByAperture1Mode, 260 PM3ByApertureMode_PIXELSIZE_32BIT | 261 PM3ByApertureMode_BYTESWAP_DCBA); 262 PM3_WRITE_REG(par, PM3ByAperture2Mode, 263 PM3ByApertureMode_PIXELSIZE_32BIT | 264 PM3ByApertureMode_BYTESWAP_DCBA); 265#endif /* ! __BIG_ENDIAN */ 266 break; 267 268 default: 269 DPRINTK("Unsupported depth %d\n", bpp); 270 break; 271 } 272 273 /* 274 * Oxygen VX1 - it appears that setting PM3VideoControl and 275 * then PM3RD_SyncControl to the same SYNC settings undoes 276 * any net change - they seem to xor together. Only set the 277 * sync options in PM3RD_SyncControl. --rmk 278 */ 279 { 280 unsigned int video = par->video; 281 282 video &= ~(PM3VideoControl_HSYNC_MASK | 283 PM3VideoControl_VSYNC_MASK); 284 video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | 285 PM3VideoControl_VSYNC_ACTIVE_HIGH; 286 PM3_WRITE_REG(par, PM3VideoControl, video); 287 } 288 PM3_WRITE_REG(par, PM3VClkCtl, 289 (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC)); 290 PM3_WRITE_REG(par, PM3ScreenBase, par->base); 291 PM3_WRITE_REG(par, PM3ChipConfig, 292 (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD)); 293 294 wmb(); 295 { 296 unsigned char uninitialized_var(m); /* ClkPreScale */ 297 unsigned char uninitialized_var(n); /* ClkFeedBackScale */ 298 unsigned char uninitialized_var(p); /* ClkPostScale */ 299 unsigned long pixclock = PICOS2KHZ(info->var.pixclock); 300 301 (void)pm3fb_calculate_clock(pixclock, &m, &n, &p); 302 303 DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n", 304 pixclock, (int) m, (int) n, (int) p); 305 306 PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m); 307 PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n); 308 PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p); 309 } 310 /* 311 PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00); 312 */ 313 /* 314 PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00); 315 */ 316 if ((par->video & PM3VideoControl_HSYNC_MASK) == 317 PM3VideoControl_HSYNC_ACTIVE_HIGH) 318 tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; 319 if ((par->video & PM3VideoControl_VSYNC_MASK) == 320 PM3VideoControl_VSYNC_ACTIVE_HIGH) 321 tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; 322 323 PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync); 324 DPRINTK("PM3RD_SyncControl: %d\n", tempsync); 325 326 PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00); 327 328 switch (pm3fb_depth(&info->var)) { 329 case 8: 330 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 331 PM3RD_PixelSize_8_BIT_PIXELS); 332 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 333 PM3RD_ColorFormat_CI8_COLOR | 334 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); 335 tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 336 break; 337 case 12: 338 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 339 PM3RD_PixelSize_16_BIT_PIXELS); 340 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 341 PM3RD_ColorFormat_4444_COLOR | 342 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 343 PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 344 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 345 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 346 break; 347 case 15: 348 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 349 PM3RD_PixelSize_16_BIT_PIXELS); 350 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 351 PM3RD_ColorFormat_5551_FRONT_COLOR | 352 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 353 PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 354 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 355 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 356 break; 357 case 16: 358 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 359 PM3RD_PixelSize_16_BIT_PIXELS); 360 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 361 PM3RD_ColorFormat_565_FRONT_COLOR | 362 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 363 PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 364 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 365 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 366 break; 367 case 32: 368 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 369 PM3RD_PixelSize_32_BIT_PIXELS); 370 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 371 PM3RD_ColorFormat_8888_COLOR | 372 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); 373 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 374 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 375 break; 376 } 377 PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc); 378} 379 380/* 381 * hardware independent functions 382 */ 383int pm3fb_init(void); 384 385static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 386{ 387 u32 lpitch; 388 unsigned bpp = var->red.length + var->green.length 389 + var->blue.length + var->transp.length; 390 391 if ( bpp != var->bits_per_pixel ) { 392 /* set predefined mode for bits_per_pixel settings */ 393 394 switch(var->bits_per_pixel) { 395 case 8: 396 var->red.length = var->green.length = var->blue.length = 8; 397 var->red.offset = var->green.offset = var->blue.offset = 0; 398 var->transp.offset = 0; 399 var->transp.length = 0; 400 break; 401 case 16: 402 var->red.length = var->blue.length = 5; 403 var->green.length = 6; 404 var->transp.length = 0; 405 break; 406 case 32: 407 var->red.length = var->green.length = var->blue.length = 8; 408 var->transp.length = 8; 409 break; 410 default: 411 DPRINTK("depth not supported: %u\n", var->bits_per_pixel); 412 return -EINVAL; 413 } 414 } 415 /* it is assumed BGRA order */ 416 if (var->bits_per_pixel > 8 ) 417 { 418 var->blue.offset = 0; 419 var->green.offset = var->blue.length; 420 var->red.offset = var->green.offset + var->green.length; 421 var->transp.offset = var->red.offset + var->red.length; 422 } 423 var->height = var->width = -1; 424 425 if (var->xres != var->xres_virtual) { 426 DPRINTK("virtual x resolution != physical x resolution not supported\n"); 427 return -EINVAL; 428 } 429 430 if (var->yres > var->yres_virtual) { 431 DPRINTK("virtual y resolution < physical y resolution not possible\n"); 432 return -EINVAL; 433 } 434 435 if (var->xoffset) { 436 DPRINTK("xoffset not supported\n"); 437 return -EINVAL; 438 } 439 440 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { 441 DPRINTK("interlace not supported\n"); 442 return -EINVAL; 443 } 444 445 var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */ 446 lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); 447 448 if (var->xres < 200 || var->xres > 2048) { 449 DPRINTK("width not supported: %u\n", var->xres); 450 return -EINVAL; 451 } 452 453 if (var->yres < 200 || var->yres > 4095) { 454 DPRINTK("height not supported: %u\n", var->yres); 455 return -EINVAL; 456 } 457 458 if (lpitch * var->yres_virtual > info->fix.smem_len) { 459 DPRINTK("no memory for screen (%ux%ux%u)\n", 460 var->xres, var->yres_virtual, var->bits_per_pixel); 461 return -EINVAL; 462 } 463 464 if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) { 465 DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); 466 return -EINVAL; 467 } 468 469 var->accel_flags = 0; /* Can't mmap if this is on */ 470 471 DPRINTK("Checking graphics mode at %dx%d depth %d\n", 472 var->xres, var->yres, var->bits_per_pixel); 473 return 0; 474} 475 476static int pm3fb_set_par(struct fb_info *info) 477{ 478 struct pm3_par *par = info->par; 479 const u32 xres = (info->var.xres + 31) & ~31; 480 const unsigned bpp = info->var.bits_per_pixel; 481 482 par->base = pm3fb_shift_bpp(bpp,(info->var.yoffset * xres) 483 + info->var.xoffset); 484 par->video = 0; 485 486 if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) 487 par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH; 488 else 489 par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW; 490 491 if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) 492 par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH; 493 else 494 par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW; 495 496 if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) 497 par->video |= PM3VideoControl_LINE_DOUBLE_ON; 498 else 499 par->video |= PM3VideoControl_LINE_DOUBLE_OFF; 500 501 if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) 502 par->video |= PM3VideoControl_ENABLE; 503 else { 504 par->video |= PM3VideoControl_DISABLE; 505 DPRINTK("PM3Video disabled\n"); 506 } 507 switch (bpp) { 508 case 8: 509 par->video |= PM3VideoControl_PIXELSIZE_8BIT; 510 break; 511 case 16: 512 par->video |= PM3VideoControl_PIXELSIZE_16BIT; 513 break; 514 case 32: 515 par->video |= PM3VideoControl_PIXELSIZE_32BIT; 516 break; 517 default: 518 DPRINTK("Unsupported depth\n"); 519 break; 520 } 521 522 info->fix.visual = 523 (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 524 info->fix.line_length = ((info->var.xres_virtual + 7) & ~7) 525 * bpp / 8; 526 527/* pm3fb_clear_memory(info, 0);*/ 528 pm3fb_clear_colormap(par, 0, 0, 0); 529 PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 530 PM3RD_CursorMode_CURSOR_DISABLE); 531 pm3fb_write_mode(info); 532 return 0; 533} 534 535static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, 536 unsigned blue, unsigned transp, 537 struct fb_info *info) 538{ 539 struct pm3_par *par = info->par; 540 541 if (regno >= 256) /* no. of hw registers */ 542 return -EINVAL; 543 544 /* grayscale works only partially under directcolor */ 545 if (info->var.grayscale) { 546 /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 547 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; 548 } 549 550 /* Directcolor: 551 * var->{color}.offset contains start of bitfield 552 * var->{color}.length contains length of bitfield 553 * {hardwarespecific} contains width of DAC 554 * pseudo_palette[X] is programmed to (X << red.offset) | 555 * (X << green.offset) | 556 * (X << blue.offset) 557 * RAMDAC[X] is programmed to (red, green, blue) 558 * color depth = SUM(var->{color}.length) 559 * 560 * Pseudocolor: 561 * var->{color}.offset is 0 562 * var->{color}.length contains width of DAC or the number of unique 563 * colors available (color depth) 564 * pseudo_palette is not used 565 * RAMDAC[X] is programmed to (red, green, blue) 566 * color depth = var->{color}.length 567 */ 568 569 /* 570 * This is the point where the color is converted to something that 571 * is acceptable by the hardware. 572 */ 573#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) 574 red = CNVT_TOHW(red, info->var.red.length); 575 green = CNVT_TOHW(green, info->var.green.length); 576 blue = CNVT_TOHW(blue, info->var.blue.length); 577 transp = CNVT_TOHW(transp, info->var.transp.length); 578#undef CNVT_TOHW 579 580 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 581 info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 582 u32 v; 583 584 if (regno >= 16) 585 return -EINVAL; 586 587 v = (red << info->var.red.offset) | 588 (green << info->var.green.offset) | 589 (blue << info->var.blue.offset) | 590 (transp << info->var.transp.offset); 591 592 switch (info->var.bits_per_pixel) { 593 case 8: 594 break; 595 case 16: 596 case 32: 597 ((u32*)(info->pseudo_palette))[regno] = v; 598 break; 599 } 600 return 0; 601 } 602 else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) 603 pm3fb_set_color(par, regno, red, green, blue); 604 605 return 0; 606} 607 608static int pm3fb_pan_display(struct fb_var_screeninfo *var, 609 struct fb_info *info) 610{ 611 struct pm3_par *par = info->par; 612 const u32 xres = (var->xres + 31) & ~31; 613 614 par->base = pm3fb_shift_bpp(var->bits_per_pixel, 615 (var->yoffset * xres) 616 + var->xoffset); 617 PM3_WAIT(par, 1); 618 PM3_WRITE_REG(par, PM3ScreenBase, par->base); 619 return 0; 620} 621 622static int pm3fb_blank(int blank_mode, struct fb_info *info) 623{ 624 struct pm3_par *par = info->par; 625 u32 video = par->video; 626 627 /* 628 * Oxygen VX1 - it appears that setting PM3VideoControl and 629 * then PM3RD_SyncControl to the same SYNC settings undoes 630 * any net change - they seem to xor together. Only set the 631 * sync options in PM3RD_SyncControl. --rmk 632 */ 633 video &= ~(PM3VideoControl_HSYNC_MASK | 634 PM3VideoControl_VSYNC_MASK); 635 video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | 636 PM3VideoControl_VSYNC_ACTIVE_HIGH; 637 638 switch (blank_mode) { 639 case FB_BLANK_UNBLANK: 640 video |= PM3VideoControl_ENABLE; 641 break; 642 case FB_BLANK_NORMAL: 643 video &= ~(PM3VideoControl_ENABLE); 644 break; 645 case FB_BLANK_HSYNC_SUSPEND: 646 video &= ~(PM3VideoControl_HSYNC_MASK | 647 PM3VideoControl_BLANK_ACTIVE_LOW); 648 break; 649 case FB_BLANK_VSYNC_SUSPEND: 650 video &= ~(PM3VideoControl_VSYNC_MASK | 651 PM3VideoControl_BLANK_ACTIVE_LOW); 652 break; 653 case FB_BLANK_POWERDOWN: 654 video &= ~(PM3VideoControl_HSYNC_MASK | 655 PM3VideoControl_VSYNC_MASK | 656 PM3VideoControl_BLANK_ACTIVE_LOW); 657 break; 658 default: 659 DPRINTK("Unsupported blanking %d\n", blank_mode); 660 return 1; 661 } 662 663 PM3_WAIT(par, 1); 664 PM3_WRITE_REG(par,PM3VideoControl, video); 665 return 0; 666} 667 668 /* 669 * Frame buffer operations 670 */ 671 672static struct fb_ops pm3fb_ops = { 673 .owner = THIS_MODULE, 674 .fb_check_var = pm3fb_check_var, 675 .fb_set_par = pm3fb_set_par, 676 .fb_setcolreg = pm3fb_setcolreg, 677 .fb_pan_display = pm3fb_pan_display, 678 .fb_fillrect = cfb_fillrect, 679 .fb_copyarea = cfb_copyarea, 680 .fb_imageblit = cfb_imageblit, 681 .fb_blank = pm3fb_blank, 682}; 683 684/* ------------------------------------------------------------------------- */ 685 686 /* 687 * Initialization 688 */ 689 690/* mmio register are already mapped when this function is called */ 691/* the pm3fb_fix.smem_start is also set */ 692static unsigned long pm3fb_size_memory(struct pm3_par *par) 693{ 694 unsigned long memsize = 0, tempBypass, i, temp1, temp2; 695 unsigned char __iomem *screen_mem; 696 697 pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */ 698 /* Linear frame buffer - request region and map it. */ 699 if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, 700 "pm3fb smem")) { 701 printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); 702 return 0; 703 } 704 screen_mem = 705 ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 706 if (!screen_mem) { 707 printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); 708 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 709 return 0; 710 } 711 712 /* TODO: card-specific stuff, *before* accessing *any* FB memory */ 713 /* For Appian Jeronimo 2000 board second head */ 714 715 tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask); 716 717 DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass); 718 719 PM3_WAIT(par, 1); 720 PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF); 721 722 /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */ 723 for (i = 0; i < 32; i++) { 724 fb_writel(i * 0x00345678, 725 (screen_mem + (i * 1048576))); 726 mb(); 727 temp1 = fb_readl((screen_mem + (i * 1048576))); 728 729 /* Let's check for wrapover, write will fail at 16MB boundary */ 730 if (temp1 == (i * 0x00345678)) 731 memsize = i; 732 else 733 break; 734 } 735 736 DPRINTK("First detect pass already got %ld MB\n", memsize + 1); 737 738 if (memsize + 1 == i) { 739 for (i = 0; i < 32; i++) { 740 /* Clear first 32MB ; 0 is 0, no need to byteswap */ 741 writel(0x0000000, (screen_mem + (i * 1048576))); 742 } 743 wmb(); 744 745 for (i = 32; i < 64; i++) { 746 fb_writel(i * 0x00345678, 747 (screen_mem + (i * 1048576))); 748 mb(); 749 temp1 = 750 fb_readl((screen_mem + (i * 1048576))); 751 temp2 = 752 fb_readl((screen_mem + ((i - 32) * 1048576))); 753 /* different value, different RAM... */ 754 if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) 755 memsize = i; 756 else 757 break; 758 } 759 } 760 DPRINTK("Second detect pass got %ld MB\n", memsize + 1); 761 762 PM3_WAIT(par, 1); 763 PM3_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass); 764 765 iounmap(screen_mem); 766 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 767 memsize = 1048576 * (memsize + 1); 768 769 DPRINTK("Returning 0x%08lx bytes\n", memsize); 770 771 return memsize; 772} 773 774static int __devinit pm3fb_probe(struct pci_dev *dev, 775 const struct pci_device_id *ent) 776{ 777 struct fb_info *info; 778 struct pm3_par *par; 779 struct device* device = &dev->dev; /* for pci drivers */ 780 int err, retval = -ENXIO; 781 782 err = pci_enable_device(dev); 783 if (err) { 784 printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err); 785 return err; 786 } 787 /* 788 * Dynamically allocate info and par 789 */ 790 info = framebuffer_alloc(sizeof(struct pm3_par), device); 791 792 if (!info) 793 return -ENOMEM; 794 par = info->par; 795 796 /* 797 * Here we set the screen_base to the virtual memory address 798 * for the framebuffer. 799 */ 800 pm3fb_fix.mmio_start = pci_resource_start(dev, 0); 801 pm3fb_fix.mmio_len = PM3_REGS_SIZE; 802 803 /* Registers - request region and map it. */ 804 if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len, 805 "pm3fb regbase")) { 806 printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n"); 807 goto err_exit_neither; 808 } 809 par->v_regs = 810 ioremap_nocache(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 811 if (!par->v_regs) { 812 printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n", 813 pm3fb_fix.id); 814 release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 815 goto err_exit_neither; 816 } 817 818#if defined(__BIG_ENDIAN) 819 pm3fb_fix.mmio_start += PM3_REGS_SIZE; 820 DPRINTK("Adjusting register base for big-endian.\n"); 821#endif 822 /* Linear frame buffer - request region and map it. */ 823 pm3fb_fix.smem_start = pci_resource_start(dev, 1); 824 pm3fb_fix.smem_len = pm3fb_size_memory(par); 825 if (!pm3fb_fix.smem_len) 826 { 827 printk(KERN_WARNING "pm3fb: Can't find memory on board.\n"); 828 goto err_exit_mmio; 829 } 830 if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, 831 "pm3fb smem")) { 832 printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); 833 goto err_exit_mmio; 834 } 835 info->screen_base = 836 ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 837 if (!info->screen_base) { 838 printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); 839 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 840 goto err_exit_mmio; 841 } 842 info->screen_size = pm3fb_fix.smem_len; 843 844 info->fbops = &pm3fb_ops; 845 846 par->video = PM3_READ_REG(par, PM3VideoControl); 847 848 info->fix = pm3fb_fix; 849 info->pseudo_palette = par->palette; 850 info->flags = FBINFO_DEFAULT;/* | FBINFO_HWACCEL_YPAN;*/ 851 852 /* 853 * This should give a reasonable default video mode. The following is 854 * done when we can set a video mode. 855 */ 856 if (!mode_option) 857 mode_option = "640x480@60"; 858 859 retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); 860 861 if (!retval || retval == 4) { 862 retval = -EINVAL; 863 goto err_exit_both; 864 } 865 866 if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { 867 retval = -ENOMEM; 868 goto err_exit_both; 869 } 870 871 /* 872 * For drivers that can... 873 */ 874 pm3fb_check_var(&info->var, info); 875 876 if (register_framebuffer(info) < 0) { 877 retval = -EINVAL; 878 goto err_exit_all; 879 } 880 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, 881 info->fix.id); 882 pci_set_drvdata(dev, info); 883 return 0; 884 885 err_exit_all: 886 fb_dealloc_cmap(&info->cmap); 887 err_exit_both: 888 iounmap(info->screen_base); 889 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 890 err_exit_mmio: 891 iounmap(par->v_regs); 892 release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 893 err_exit_neither: 894 framebuffer_release(info); 895 return retval; 896} 897 898 /* 899 * Cleanup 900 */ 901static void __devexit pm3fb_remove(struct pci_dev *dev) 902{ 903 struct fb_info *info = pci_get_drvdata(dev); 904 905 if (info) { 906 struct fb_fix_screeninfo *fix = &info->fix; 907 struct pm3_par *par = info->par; 908 909 unregister_framebuffer(info); 910 fb_dealloc_cmap(&info->cmap); 911 912 iounmap(info->screen_base); 913 release_mem_region(fix->smem_start, fix->smem_len); 914 iounmap(par->v_regs); 915 release_mem_region(fix->mmio_start, fix->mmio_len); 916 917 pci_set_drvdata(dev, NULL); 918 framebuffer_release(info); 919 } 920} 921 922static struct pci_device_id pm3fb_id_table[] = { 923 { PCI_VENDOR_ID_3DLABS, 0x0a, 924 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 925 { 0, } 926}; 927 928/* For PCI drivers */ 929static struct pci_driver pm3fb_driver = { 930 .name = "pm3fb", 931 .id_table = pm3fb_id_table, 932 .probe = pm3fb_probe, 933 .remove = __devexit_p(pm3fb_remove), 934}; 935 936MODULE_DEVICE_TABLE(pci, pm3fb_id_table); 937 938#ifndef MODULE 939 /* 940 * Setup 941 */ 942 943/* 944 * Only necessary if your driver takes special options, 945 * otherwise we fall back on the generic fb_setup(). 946 */ 947static int __init pm3fb_setup(char *options) 948{ 949 /* Parse user speficied options (`video=pm3fb:') */ 950 return 0; 951} 952#endif /* MODULE */ 953 954int __init pm3fb_init(void) 955{ 956 /* 957 * For kernel boot options (in 'video=pm3fb:<options>' format) 958 */ 959#ifndef MODULE 960 char *option = NULL; 961 962 if (fb_get_options("pm3fb", &option)) 963 return -ENODEV; 964 pm3fb_setup(option); 965#endif 966 967 return pci_register_driver(&pm3fb_driver); 968} 969 970static void __exit pm3fb_exit(void) 971{ 972 pci_unregister_driver(&pm3fb_driver); 973} 974 975module_init(pm3fb_init); 976module_exit(pm3fb_exit); 977 978MODULE_LICENSE("GPL"); 979