pm3fb.c revision d5383fcc4c221227b954e028821a697ca7859e0e
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#ifdef CONFIG_MTRR 36#include <asm/mtrr.h> 37#endif 38 39#include <video/pm3fb.h> 40 41#if !defined(CONFIG_PCI) 42#error "Only generic PCI cards supported." 43#endif 44 45#undef PM3FB_MASTER_DEBUG 46#ifdef PM3FB_MASTER_DEBUG 47#define DPRINTK(a,b...) printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b) 48#else 49#define DPRINTK(a,b...) 50#endif 51 52#define PM3_PIXMAP_SIZE (2048 * 4) 53 54/* 55 * Driver data 56 */ 57static char *mode_option __devinitdata; 58static int noaccel __devinitdata = 0; 59 60/* mtrr option */ 61#ifdef CONFIG_MTRR 62static int nomtrr __devinitdata = 0; 63#endif 64 65/* 66 * This structure defines the hardware state of the graphics card. Normally 67 * you place this in a header file in linux/include/video. This file usually 68 * also includes register information. That allows other driver subsystems 69 * and userland applications the ability to use the same header file to 70 * avoid duplicate work and easy porting of software. 71 */ 72struct pm3_par { 73 unsigned char __iomem *v_regs;/* virtual address of p_regs */ 74 u32 video; /* video flags before blanking */ 75 u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */ 76 u32 palette[16]; 77 int mtrr_handle; 78}; 79 80/* 81 * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo 82 * if we don't use modedb. If we do use modedb see pm3fb_init how to use it 83 * to get a fb_var_screeninfo. Otherwise define a default var as well. 84 */ 85static struct fb_fix_screeninfo pm3fb_fix __devinitdata = { 86 .id = "Permedia3", 87 .type = FB_TYPE_PACKED_PIXELS, 88 .visual = FB_VISUAL_PSEUDOCOLOR, 89 .xpanstep = 1, 90 .ypanstep = 1, 91 .ywrapstep = 0, 92 .accel = FB_ACCEL_3DLABS_PERMEDIA3, 93}; 94 95/* 96 * Utility functions 97 */ 98 99static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off) 100{ 101 return fb_readl(par->v_regs + off); 102} 103 104static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v) 105{ 106 fb_writel(v, par->v_regs + off); 107} 108 109static inline void PM3_WAIT(struct pm3_par *par, u32 n) 110{ 111 while (PM3_READ_REG(par, PM3InFIFOSpace) < n); 112} 113 114static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v) 115{ 116 PM3_WAIT(par, 3); 117 PM3_WRITE_REG(par, PM3RD_IndexHigh, (r >> 8) & 0xff); 118 PM3_WRITE_REG(par, PM3RD_IndexLow, r & 0xff); 119 wmb(); 120 PM3_WRITE_REG(par, PM3RD_IndexedData, v); 121 wmb(); 122} 123 124static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno, 125 unsigned char r, unsigned char g, unsigned char b) 126{ 127 PM3_WAIT(par, 4); 128 PM3_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno); 129 wmb(); 130 PM3_WRITE_REG(par, PM3RD_PaletteData, r); 131 wmb(); 132 PM3_WRITE_REG(par, PM3RD_PaletteData, g); 133 wmb(); 134 PM3_WRITE_REG(par, PM3RD_PaletteData, b); 135 wmb(); 136} 137 138static void pm3fb_clear_colormap(struct pm3_par *par, 139 unsigned char r, unsigned char g, unsigned char b) 140{ 141 int i; 142 143 for (i = 0; i < 256 ; i++) 144 pm3fb_set_color(par, i, r, g, b); 145 146} 147 148/* Calculating various clock parameters */ 149static void pm3fb_calculate_clock(unsigned long reqclock, 150 unsigned char *prescale, 151 unsigned char *feedback, 152 unsigned char *postscale) 153{ 154 int f, pre, post; 155 unsigned long freq; 156 long freqerr = 1000; 157 long currerr; 158 159 for (f = 1; f < 256; f++) { 160 for (pre = 1; pre < 256; pre++) { 161 for (post = 0; post < 5; post++) { 162 freq = ((2*PM3_REF_CLOCK * f) >> post) / pre; 163 currerr = (reqclock > freq) 164 ? reqclock - freq 165 : freq - reqclock; 166 if (currerr < freqerr) { 167 freqerr = currerr; 168 *feedback = f; 169 *prescale = pre; 170 *postscale = post; 171 } 172 } 173 } 174 } 175} 176 177static inline int pm3fb_depth(const struct fb_var_screeninfo *var) 178{ 179 if (var->bits_per_pixel == 16) 180 return var->red.length + var->green.length 181 + var->blue.length; 182 183 return var->bits_per_pixel; 184} 185 186static inline int pm3fb_shift_bpp(unsigned bpp, int v) 187{ 188 switch (bpp) { 189 case 8: 190 return (v >> 4); 191 case 16: 192 return (v >> 3); 193 case 32: 194 return (v >> 2); 195 } 196 DPRINTK("Unsupported depth %u\n", bpp); 197 return 0; 198} 199 200/* acceleration */ 201static int pm3fb_sync(struct fb_info *info) 202{ 203 struct pm3_par *par = info->par; 204 205 PM3_WAIT(par, 2); 206 PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync); 207 PM3_WRITE_REG(par, PM3Sync, 0); 208 mb(); 209 do { 210 while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0); 211 rmb(); 212 } while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag); 213 214 return 0; 215} 216 217static void pm3fb_init_engine(struct fb_info *info) 218{ 219 struct pm3_par *par = info->par; 220 const u32 width = (info->var.xres_virtual + 7) & ~7; 221 222 PM3_WAIT(par, 50); 223 PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync); 224 PM3_WRITE_REG(par, PM3StatisticMode, 0x0); 225 PM3_WRITE_REG(par, PM3DeltaMode, 0x0); 226 PM3_WRITE_REG(par, PM3RasterizerMode, 0x0); 227 PM3_WRITE_REG(par, PM3ScissorMode, 0x0); 228 PM3_WRITE_REG(par, PM3LineStippleMode, 0x0); 229 PM3_WRITE_REG(par, PM3AreaStippleMode, 0x0); 230 PM3_WRITE_REG(par, PM3GIDMode, 0x0); 231 PM3_WRITE_REG(par, PM3DepthMode, 0x0); 232 PM3_WRITE_REG(par, PM3StencilMode, 0x0); 233 PM3_WRITE_REG(par, PM3StencilData, 0x0); 234 PM3_WRITE_REG(par, PM3ColorDDAMode, 0x0); 235 PM3_WRITE_REG(par, PM3TextureCoordMode, 0x0); 236 PM3_WRITE_REG(par, PM3TextureIndexMode0, 0x0); 237 PM3_WRITE_REG(par, PM3TextureIndexMode1, 0x0); 238 PM3_WRITE_REG(par, PM3TextureReadMode, 0x0); 239 PM3_WRITE_REG(par, PM3LUTMode, 0x0); 240 PM3_WRITE_REG(par, PM3TextureFilterMode, 0x0); 241 PM3_WRITE_REG(par, PM3TextureCompositeMode, 0x0); 242 PM3_WRITE_REG(par, PM3TextureApplicationMode, 0x0); 243 PM3_WRITE_REG(par, PM3TextureCompositeColorMode1, 0x0); 244 PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode1, 0x0); 245 PM3_WRITE_REG(par, PM3TextureCompositeColorMode0, 0x0); 246 PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode0, 0x0); 247 PM3_WRITE_REG(par, PM3FogMode, 0x0); 248 PM3_WRITE_REG(par, PM3ChromaTestMode, 0x0); 249 PM3_WRITE_REG(par, PM3AlphaTestMode, 0x0); 250 PM3_WRITE_REG(par, PM3AntialiasMode, 0x0); 251 PM3_WRITE_REG(par, PM3YUVMode, 0x0); 252 PM3_WRITE_REG(par, PM3AlphaBlendColorMode, 0x0); 253 PM3_WRITE_REG(par, PM3AlphaBlendAlphaMode, 0x0); 254 PM3_WRITE_REG(par, PM3DitherMode, 0x0); 255 PM3_WRITE_REG(par, PM3LogicalOpMode, 0x0); 256 PM3_WRITE_REG(par, PM3RouterMode, 0x0); 257 PM3_WRITE_REG(par, PM3Window, 0x0); 258 259 PM3_WRITE_REG(par, PM3Config2D, 0x0); 260 261 PM3_WRITE_REG(par, PM3SpanColorMask, 0xffffffff); 262 263 PM3_WRITE_REG(par, PM3XBias, 0x0); 264 PM3_WRITE_REG(par, PM3YBias, 0x0); 265 PM3_WRITE_REG(par, PM3DeltaControl, 0x0); 266 267 PM3_WRITE_REG(par, PM3BitMaskPattern, 0xffffffff); 268 269 PM3_WRITE_REG(par, PM3FBDestReadEnables, 270 PM3FBDestReadEnables_E(0xff) | 271 PM3FBDestReadEnables_R(0xff) | 272 PM3FBDestReadEnables_ReferenceAlpha(0xff)); 273 PM3_WRITE_REG(par, PM3FBDestReadBufferAddr0, 0x0); 274 PM3_WRITE_REG(par, PM3FBDestReadBufferOffset0, 0x0); 275 PM3_WRITE_REG(par, PM3FBDestReadBufferWidth0, 276 PM3FBDestReadBufferWidth_Width(width)); 277 278 PM3_WRITE_REG(par, PM3FBDestReadMode, 279 PM3FBDestReadMode_ReadEnable | 280 PM3FBDestReadMode_Enable0); 281 PM3_WRITE_REG(par, PM3FBSourceReadBufferAddr, 0x0); 282 PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 0x0); 283 PM3_WRITE_REG(par, PM3FBSourceReadBufferWidth, 284 PM3FBSourceReadBufferWidth_Width(width)); 285 PM3_WRITE_REG(par, PM3FBSourceReadMode, 286 PM3FBSourceReadMode_Blocking | 287 PM3FBSourceReadMode_ReadEnable); 288 289 PM3_WAIT(par, 2); 290 { 291 /* invert bits in bitmask */ 292 unsigned long rm = 1 | (3 << 7); 293 switch (info->var.bits_per_pixel) { 294 case 8: 295 PM3_WRITE_REG(par, PM3PixelSize, 296 PM3PixelSize_GLOBAL_8BIT); 297#ifdef __BIG_ENDIAN 298 rm |= 3 << 15; 299#endif 300 break; 301 case 16: 302 PM3_WRITE_REG(par, PM3PixelSize, 303 PM3PixelSize_GLOBAL_16BIT); 304#ifdef __BIG_ENDIAN 305 rm |= 2 << 15; 306#endif 307 break; 308 case 32: 309 PM3_WRITE_REG(par, PM3PixelSize, 310 PM3PixelSize_GLOBAL_32BIT); 311 break; 312 default: 313 DPRINTK(1, "Unsupported depth %d\n", 314 info->var.bits_per_pixel); 315 break; 316 } 317 PM3_WRITE_REG(par, PM3RasterizerMode, rm); 318 } 319 320 PM3_WAIT(par, 20); 321 PM3_WRITE_REG(par, PM3FBSoftwareWriteMask, 0xffffffff); 322 PM3_WRITE_REG(par, PM3FBHardwareWriteMask, 0xffffffff); 323 PM3_WRITE_REG(par, PM3FBWriteMode, 324 PM3FBWriteMode_WriteEnable | 325 PM3FBWriteMode_OpaqueSpan | 326 PM3FBWriteMode_Enable0); 327 PM3_WRITE_REG(par, PM3FBWriteBufferAddr0, 0x0); 328 PM3_WRITE_REG(par, PM3FBWriteBufferOffset0, 0x0); 329 PM3_WRITE_REG(par, PM3FBWriteBufferWidth0, 330 PM3FBWriteBufferWidth_Width(width)); 331 332 PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 0x0); 333 { 334 /* size in lines of FB */ 335 unsigned long sofb = info->screen_size / 336 info->fix.line_length; 337 if (sofb > 4095) 338 PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 4095); 339 else 340 PM3_WRITE_REG(par, PM3SizeOfFramebuffer, sofb); 341 342 switch (info->var.bits_per_pixel) { 343 case 8: 344 PM3_WRITE_REG(par, PM3DitherMode, 345 (1 << 10) | (2 << 3)); 346 break; 347 case 16: 348 PM3_WRITE_REG(par, PM3DitherMode, 349 (1 << 10) | (1 << 3)); 350 break; 351 case 32: 352 PM3_WRITE_REG(par, PM3DitherMode, 353 (1 << 10) | (0 << 3)); 354 break; 355 default: 356 DPRINTK(1, "Unsupported depth %d\n", 357 info->current_par->depth); 358 break; 359 } 360 } 361 362 PM3_WRITE_REG(par, PM3dXDom, 0x0); 363 PM3_WRITE_REG(par, PM3dXSub, 0x0); 364 PM3_WRITE_REG(par, PM3dY, 1 << 16); 365 PM3_WRITE_REG(par, PM3StartXDom, 0x0); 366 PM3_WRITE_REG(par, PM3StartXSub, 0x0); 367 PM3_WRITE_REG(par, PM3StartY, 0x0); 368 PM3_WRITE_REG(par, PM3Count, 0x0); 369 370/* Disable LocalBuffer. better safe than sorry */ 371 PM3_WRITE_REG(par, PM3LBDestReadMode, 0x0); 372 PM3_WRITE_REG(par, PM3LBDestReadEnables, 0x0); 373 PM3_WRITE_REG(par, PM3LBSourceReadMode, 0x0); 374 PM3_WRITE_REG(par, PM3LBWriteMode, 0x0); 375 376 pm3fb_sync(info); 377} 378 379static void pm3fb_fillrect (struct fb_info *info, 380 const struct fb_fillrect *region) 381{ 382 struct pm3_par *par = info->par; 383 struct fb_fillrect modded; 384 int vxres, vyres; 385 int rop; 386 u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? 387 ((u32*)info->pseudo_palette)[region->color] : region->color; 388 389 if (info->state != FBINFO_STATE_RUNNING) 390 return; 391 if (info->flags & FBINFO_HWACCEL_DISABLED) { 392 cfb_fillrect(info, region); 393 return; 394 } 395 if (region->rop == ROP_COPY ) 396 rop = PM3Config2D_ForegroundROP(0x3); /* GXcopy */ 397 else 398 rop = PM3Config2D_ForegroundROP(0x6) | /* GXxor */ 399 PM3Config2D_FBDestReadEnable; 400 401 vxres = info->var.xres_virtual; 402 vyres = info->var.yres_virtual; 403 404 memcpy(&modded, region, sizeof(struct fb_fillrect)); 405 406 if(!modded.width || !modded.height || 407 modded.dx >= vxres || modded.dy >= vyres) 408 return; 409 410 if(modded.dx + modded.width > vxres) 411 modded.width = vxres - modded.dx; 412 if(modded.dy + modded.height > vyres) 413 modded.height = vyres - modded.dy; 414 415 if(info->var.bits_per_pixel == 8) 416 color |= color << 8; 417 if(info->var.bits_per_pixel <= 16) 418 color |= color << 16; 419 420 PM3_WAIT(par, 4); 421 /* ROP Ox3 is GXcopy */ 422 PM3_WRITE_REG(par, PM3Config2D, 423 PM3Config2D_UseConstantSource | 424 PM3Config2D_ForegroundROPEnable | 425 rop | 426 PM3Config2D_FBWriteEnable); 427 428 PM3_WRITE_REG(par, PM3ForegroundColor, color); 429 430 PM3_WRITE_REG(par, PM3RectanglePosition, 431 PM3RectanglePosition_XOffset(modded.dx) | 432 PM3RectanglePosition_YOffset(modded.dy)); 433 434 PM3_WRITE_REG(par, PM3Render2D, 435 PM3Render2D_XPositive | 436 PM3Render2D_YPositive | 437 PM3Render2D_Operation_Normal | 438 PM3Render2D_SpanOperation | 439 PM3Render2D_Width(modded.width) | 440 PM3Render2D_Height(modded.height)); 441} 442 443static void pm3fb_copyarea(struct fb_info *info, 444 const struct fb_copyarea *area) 445{ 446 struct pm3_par *par = info->par; 447 struct fb_copyarea modded; 448 u32 vxres, vyres; 449 int x_align, o_x, o_y; 450 451 if (info->state != FBINFO_STATE_RUNNING) 452 return; 453 if (info->flags & FBINFO_HWACCEL_DISABLED) { 454 cfb_copyarea(info, area); 455 return; 456 } 457 458 memcpy(&modded, area, sizeof(struct fb_copyarea)); 459 460 vxres = info->var.xres_virtual; 461 vyres = info->var.yres_virtual; 462 463 if(!modded.width || !modded.height || 464 modded.sx >= vxres || modded.sy >= vyres || 465 modded.dx >= vxres || modded.dy >= vyres) 466 return; 467 468 if(modded.sx + modded.width > vxres) 469 modded.width = vxres - modded.sx; 470 if(modded.dx + modded.width > vxres) 471 modded.width = vxres - modded.dx; 472 if(modded.sy + modded.height > vyres) 473 modded.height = vyres - modded.sy; 474 if(modded.dy + modded.height > vyres) 475 modded.height = vyres - modded.dy; 476 477 o_x = modded.sx - modded.dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */ 478 o_y = modded.sy - modded.dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */ 479 480 x_align = (modded.sx & 0x1f); 481 482 PM3_WAIT(par, 6); 483 484 PM3_WRITE_REG(par, PM3Config2D, 485 PM3Config2D_UserScissorEnable | 486 PM3Config2D_ForegroundROPEnable | 487 PM3Config2D_Blocking | 488 PM3Config2D_ForegroundROP(0x3) | /* Ox3 is GXcopy */ 489 PM3Config2D_FBWriteEnable); 490 491 PM3_WRITE_REG(par, PM3ScissorMinXY, 492 ((modded.dy & 0x0fff) << 16) | (modded.dx & 0x0fff)); 493 PM3_WRITE_REG(par, PM3ScissorMaxXY, 494 (((modded.dy + modded.height) & 0x0fff) << 16) | 495 ((modded.dx + modded.width) & 0x0fff)); 496 497 PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 498 PM3FBSourceReadBufferOffset_XOffset(o_x) | 499 PM3FBSourceReadBufferOffset_YOffset(o_y)); 500 501 PM3_WRITE_REG(par, PM3RectanglePosition, 502 PM3RectanglePosition_XOffset(modded.dx - x_align) | 503 PM3RectanglePosition_YOffset(modded.dy)); 504 505 PM3_WRITE_REG(par, PM3Render2D, 506 ((modded.sx > modded.dx) ? PM3Render2D_XPositive : 0) | 507 ((modded.sy > modded.dy) ? PM3Render2D_YPositive : 0) | 508 PM3Render2D_Operation_Normal | 509 PM3Render2D_SpanOperation | 510 PM3Render2D_FBSourceReadEnable | 511 PM3Render2D_Width(modded.width + x_align) | 512 PM3Render2D_Height(modded.height)); 513} 514 515static void pm3fb_imageblit(struct fb_info *info, const struct fb_image *image) 516{ 517 struct pm3_par *par = info->par; 518 u32 height = image->height; 519 u32 fgx, bgx; 520 const u32 *src = (const u32*)image->data; 521 522 if (info->state != FBINFO_STATE_RUNNING) 523 return; 524 if (info->flags & FBINFO_HWACCEL_DISABLED) { 525 cfb_imageblit(info, image); 526 return; 527 } 528 switch (info->fix.visual) { 529 case FB_VISUAL_PSEUDOCOLOR: 530 fgx = image->fg_color; 531 bgx = image->bg_color; 532 break; 533 case FB_VISUAL_TRUECOLOR: 534 default: 535 fgx = par->palette[image->fg_color]; 536 bgx = par->palette[image->bg_color]; 537 break; 538 } 539 if (image->depth != 1) { 540 return cfb_imageblit(info, image); 541 } 542 if (info->var.bits_per_pixel == 8) { 543 fgx |= fgx << 8; 544 bgx |= bgx << 8; 545 } 546 if (info->var.bits_per_pixel <= 16) { 547 fgx |= fgx << 16; 548 bgx |= bgx << 16; 549 } 550 551 PM3_WAIT(par, 7); 552 553 PM3_WRITE_REG(par, PM3ForegroundColor, fgx); 554 PM3_WRITE_REG(par, PM3BackgroundColor, bgx); 555 556 /* ROP Ox3 is GXcopy */ 557 PM3_WRITE_REG(par, PM3Config2D, 558 PM3Config2D_UserScissorEnable | 559 PM3Config2D_UseConstantSource | 560 PM3Config2D_ForegroundROPEnable | 561 PM3Config2D_ForegroundROP(0x3) | 562 PM3Config2D_OpaqueSpan | 563 PM3Config2D_FBWriteEnable); 564 PM3_WRITE_REG(par, PM3ScissorMinXY, 565 ((image->dy & 0x0fff) << 16) | (image->dx & 0x0fff)); 566 PM3_WRITE_REG(par, PM3ScissorMaxXY, 567 (((image->dy + image->height) & 0x0fff) << 16) | 568 ((image->dx + image->width) & 0x0fff)); 569 PM3_WRITE_REG(par, PM3RectanglePosition, 570 PM3RectanglePosition_XOffset(image->dx) | 571 PM3RectanglePosition_YOffset(image->dy)); 572 PM3_WRITE_REG(par, PM3Render2D, 573 PM3Render2D_XPositive | 574 PM3Render2D_YPositive | 575 PM3Render2D_Operation_SyncOnBitMask | 576 PM3Render2D_SpanOperation | 577 PM3Render2D_Width(image->width) | 578 PM3Render2D_Height(image->height)); 579 580 581 while (height--) { 582 int width = ((image->width + 7) >> 3) 583 + info->pixmap.scan_align - 1; 584 width >>= 2; 585 586 while (width >= PM3_FIFO_SIZE) { 587 int i = PM3_FIFO_SIZE - 1; 588 589 PM3_WAIT(par, PM3_FIFO_SIZE); 590 while (i--) { 591 PM3_WRITE_REG(par, PM3BitMaskPattern, *src); 592 src++; 593 } 594 width -= PM3_FIFO_SIZE - 1; 595 } 596 597 PM3_WAIT(par, width + 1); 598 while (width--) { 599 PM3_WRITE_REG(par, PM3BitMaskPattern, *src); 600 src++; 601 } 602 } 603} 604/* end of acceleration functions */ 605 606/* write the mode to registers */ 607static void pm3fb_write_mode(struct fb_info *info) 608{ 609 struct pm3_par *par = info->par; 610 char tempsync = 0x00, tempmisc = 0x00; 611 const u32 hsstart = info->var.right_margin; 612 const u32 hsend = hsstart + info->var.hsync_len; 613 const u32 hbend = hsend + info->var.left_margin; 614 const u32 xres = (info->var.xres + 31) & ~31; 615 const u32 htotal = xres + hbend; 616 const u32 vsstart = info->var.lower_margin; 617 const u32 vsend = vsstart + info->var.vsync_len; 618 const u32 vbend = vsend + info->var.upper_margin; 619 const u32 vtotal = info->var.yres + vbend; 620 const u32 width = (info->var.xres_virtual + 7) & ~7; 621 const unsigned bpp = info->var.bits_per_pixel; 622 623 PM3_WAIT(par, 20); 624 PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff); 625 PM3_WRITE_REG(par, PM3Aperture0, 0x00000000); 626 PM3_WRITE_REG(par, PM3Aperture1, 0x00000000); 627 PM3_WRITE_REG(par, PM3FIFODis, 0x00000007); 628 629 PM3_WRITE_REG(par, PM3HTotal, 630 pm3fb_shift_bpp(bpp, htotal - 1)); 631 PM3_WRITE_REG(par, PM3HsEnd, 632 pm3fb_shift_bpp(bpp, hsend)); 633 PM3_WRITE_REG(par, PM3HsStart, 634 pm3fb_shift_bpp(bpp, hsstart)); 635 PM3_WRITE_REG(par, PM3HbEnd, 636 pm3fb_shift_bpp(bpp, hbend)); 637 PM3_WRITE_REG(par, PM3HgEnd, 638 pm3fb_shift_bpp(bpp, hbend)); 639 PM3_WRITE_REG(par, PM3ScreenStride, 640 pm3fb_shift_bpp(bpp, width)); 641 PM3_WRITE_REG(par, PM3VTotal, vtotal - 1); 642 PM3_WRITE_REG(par, PM3VsEnd, vsend - 1); 643 PM3_WRITE_REG(par, PM3VsStart, vsstart - 1); 644 PM3_WRITE_REG(par, PM3VbEnd, vbend); 645 646 switch (bpp) { 647 case 8: 648 PM3_WRITE_REG(par, PM3ByAperture1Mode, 649 PM3ByApertureMode_PIXELSIZE_8BIT); 650 PM3_WRITE_REG(par, PM3ByAperture2Mode, 651 PM3ByApertureMode_PIXELSIZE_8BIT); 652 break; 653 654 case 16: 655#ifndef __BIG_ENDIAN 656 PM3_WRITE_REG(par, PM3ByAperture1Mode, 657 PM3ByApertureMode_PIXELSIZE_16BIT); 658 PM3_WRITE_REG(par, PM3ByAperture2Mode, 659 PM3ByApertureMode_PIXELSIZE_16BIT); 660#else 661 PM3_WRITE_REG(par, PM3ByAperture1Mode, 662 PM3ByApertureMode_PIXELSIZE_16BIT | 663 PM3ByApertureMode_BYTESWAP_BADC); 664 PM3_WRITE_REG(par, PM3ByAperture2Mode, 665 PM3ByApertureMode_PIXELSIZE_16BIT | 666 PM3ByApertureMode_BYTESWAP_BADC); 667#endif /* ! __BIG_ENDIAN */ 668 break; 669 670 case 32: 671#ifndef __BIG_ENDIAN 672 PM3_WRITE_REG(par, PM3ByAperture1Mode, 673 PM3ByApertureMode_PIXELSIZE_32BIT); 674 PM3_WRITE_REG(par, PM3ByAperture2Mode, 675 PM3ByApertureMode_PIXELSIZE_32BIT); 676#else 677 PM3_WRITE_REG(par, PM3ByAperture1Mode, 678 PM3ByApertureMode_PIXELSIZE_32BIT | 679 PM3ByApertureMode_BYTESWAP_DCBA); 680 PM3_WRITE_REG(par, PM3ByAperture2Mode, 681 PM3ByApertureMode_PIXELSIZE_32BIT | 682 PM3ByApertureMode_BYTESWAP_DCBA); 683#endif /* ! __BIG_ENDIAN */ 684 break; 685 686 default: 687 DPRINTK("Unsupported depth %d\n", bpp); 688 break; 689 } 690 691 /* 692 * Oxygen VX1 - it appears that setting PM3VideoControl and 693 * then PM3RD_SyncControl to the same SYNC settings undoes 694 * any net change - they seem to xor together. Only set the 695 * sync options in PM3RD_SyncControl. --rmk 696 */ 697 { 698 unsigned int video = par->video; 699 700 video &= ~(PM3VideoControl_HSYNC_MASK | 701 PM3VideoControl_VSYNC_MASK); 702 video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | 703 PM3VideoControl_VSYNC_ACTIVE_HIGH; 704 PM3_WRITE_REG(par, PM3VideoControl, video); 705 } 706 PM3_WRITE_REG(par, PM3VClkCtl, 707 (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC)); 708 PM3_WRITE_REG(par, PM3ScreenBase, par->base); 709 PM3_WRITE_REG(par, PM3ChipConfig, 710 (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD)); 711 712 wmb(); 713 { 714 unsigned char uninitialized_var(m); /* ClkPreScale */ 715 unsigned char uninitialized_var(n); /* ClkFeedBackScale */ 716 unsigned char uninitialized_var(p); /* ClkPostScale */ 717 unsigned long pixclock = PICOS2KHZ(info->var.pixclock); 718 719 (void)pm3fb_calculate_clock(pixclock, &m, &n, &p); 720 721 DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n", 722 pixclock, (int) m, (int) n, (int) p); 723 724 PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m); 725 PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n); 726 PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p); 727 } 728 /* 729 PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00); 730 */ 731 /* 732 PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00); 733 */ 734 if ((par->video & PM3VideoControl_HSYNC_MASK) == 735 PM3VideoControl_HSYNC_ACTIVE_HIGH) 736 tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; 737 if ((par->video & PM3VideoControl_VSYNC_MASK) == 738 PM3VideoControl_VSYNC_ACTIVE_HIGH) 739 tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; 740 741 PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync); 742 DPRINTK("PM3RD_SyncControl: %d\n", tempsync); 743 744 PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00); 745 746 switch (pm3fb_depth(&info->var)) { 747 case 8: 748 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 749 PM3RD_PixelSize_8_BIT_PIXELS); 750 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 751 PM3RD_ColorFormat_CI8_COLOR | 752 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); 753 tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 754 break; 755 case 12: 756 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 757 PM3RD_PixelSize_16_BIT_PIXELS); 758 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 759 PM3RD_ColorFormat_4444_COLOR | 760 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 761 PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 762 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 763 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 764 break; 765 case 15: 766 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 767 PM3RD_PixelSize_16_BIT_PIXELS); 768 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 769 PM3RD_ColorFormat_5551_FRONT_COLOR | 770 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 771 PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 772 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 773 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 774 break; 775 case 16: 776 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 777 PM3RD_PixelSize_16_BIT_PIXELS); 778 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 779 PM3RD_ColorFormat_565_FRONT_COLOR | 780 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 781 PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 782 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 783 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 784 break; 785 case 32: 786 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 787 PM3RD_PixelSize_32_BIT_PIXELS); 788 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 789 PM3RD_ColorFormat_8888_COLOR | 790 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); 791 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 792 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 793 break; 794 } 795 PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc); 796} 797 798/* 799 * hardware independent functions 800 */ 801static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 802{ 803 u32 lpitch; 804 unsigned bpp = var->red.length + var->green.length 805 + var->blue.length + var->transp.length; 806 807 if (bpp != var->bits_per_pixel) { 808 /* set predefined mode for bits_per_pixel settings */ 809 810 switch(var->bits_per_pixel) { 811 case 8: 812 var->red.length = var->green.length = var->blue.length = 8; 813 var->red.offset = var->green.offset = var->blue.offset = 0; 814 var->transp.offset = 0; 815 var->transp.length = 0; 816 break; 817 case 16: 818 var->red.length = var->blue.length = 5; 819 var->green.length = 6; 820 var->transp.length = 0; 821 break; 822 case 32: 823 var->red.length = var->green.length = var->blue.length = 8; 824 var->transp.length = 8; 825 break; 826 default: 827 DPRINTK("depth not supported: %u\n", var->bits_per_pixel); 828 return -EINVAL; 829 } 830 } 831 /* it is assumed BGRA order */ 832 if (var->bits_per_pixel > 8 ) 833 { 834 var->blue.offset = 0; 835 var->green.offset = var->blue.length; 836 var->red.offset = var->green.offset + var->green.length; 837 var->transp.offset = var->red.offset + var->red.length; 838 } 839 var->height = var->width = -1; 840 841 if (var->xres != var->xres_virtual) { 842 DPRINTK("virtual x resolution != physical x resolution not supported\n"); 843 return -EINVAL; 844 } 845 846 if (var->yres > var->yres_virtual) { 847 DPRINTK("virtual y resolution < physical y resolution not possible\n"); 848 return -EINVAL; 849 } 850 851 if (var->xoffset) { 852 DPRINTK("xoffset not supported\n"); 853 return -EINVAL; 854 } 855 856 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { 857 DPRINTK("interlace not supported\n"); 858 return -EINVAL; 859 } 860 861 var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */ 862 lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); 863 864 if (var->xres < 200 || var->xres > 2048) { 865 DPRINTK("width not supported: %u\n", var->xres); 866 return -EINVAL; 867 } 868 869 if (var->yres < 200 || var->yres > 4095) { 870 DPRINTK("height not supported: %u\n", var->yres); 871 return -EINVAL; 872 } 873 874 if (lpitch * var->yres_virtual > info->fix.smem_len) { 875 DPRINTK("no memory for screen (%ux%ux%u)\n", 876 var->xres, var->yres_virtual, var->bits_per_pixel); 877 return -EINVAL; 878 } 879 880 if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) { 881 DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); 882 return -EINVAL; 883 } 884 885 var->accel_flags = 0; /* Can't mmap if this is on */ 886 887 DPRINTK("Checking graphics mode at %dx%d depth %d\n", 888 var->xres, var->yres, var->bits_per_pixel); 889 return 0; 890} 891 892static int pm3fb_set_par(struct fb_info *info) 893{ 894 struct pm3_par *par = info->par; 895 const u32 xres = (info->var.xres + 31) & ~31; 896 const unsigned bpp = info->var.bits_per_pixel; 897 898 par->base = pm3fb_shift_bpp(bpp,(info->var.yoffset * xres) 899 + info->var.xoffset); 900 par->video = 0; 901 902 if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) 903 par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH; 904 else 905 par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW; 906 907 if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) 908 par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH; 909 else 910 par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW; 911 912 if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) 913 par->video |= PM3VideoControl_LINE_DOUBLE_ON; 914 915 if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) 916 par->video |= PM3VideoControl_ENABLE; 917 else 918 DPRINTK("PM3Video disabled\n"); 919 920 switch (bpp) { 921 case 8: 922 par->video |= PM3VideoControl_PIXELSIZE_8BIT; 923 break; 924 case 16: 925 par->video |= PM3VideoControl_PIXELSIZE_16BIT; 926 break; 927 case 32: 928 par->video |= PM3VideoControl_PIXELSIZE_32BIT; 929 break; 930 default: 931 DPRINTK("Unsupported depth\n"); 932 break; 933 } 934 935 info->fix.visual = 936 (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 937 info->fix.line_length = ((info->var.xres_virtual + 7) >> 3) * bpp; 938 939/* pm3fb_clear_memory(info, 0);*/ 940 pm3fb_clear_colormap(par, 0, 0, 0); 941 PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 0); 942 pm3fb_init_engine(info); 943 pm3fb_write_mode(info); 944 return 0; 945} 946 947static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, 948 unsigned blue, unsigned transp, 949 struct fb_info *info) 950{ 951 struct pm3_par *par = info->par; 952 953 if (regno >= 256) /* no. of hw registers */ 954 return -EINVAL; 955 956 /* grayscale works only partially under directcolor */ 957 if (info->var.grayscale) { 958 /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 959 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; 960 } 961 962 /* Directcolor: 963 * var->{color}.offset contains start of bitfield 964 * var->{color}.length contains length of bitfield 965 * {hardwarespecific} contains width of DAC 966 * pseudo_palette[X] is programmed to (X << red.offset) | 967 * (X << green.offset) | 968 * (X << blue.offset) 969 * RAMDAC[X] is programmed to (red, green, blue) 970 * color depth = SUM(var->{color}.length) 971 * 972 * Pseudocolor: 973 * var->{color}.offset is 0 974 * var->{color}.length contains width of DAC or the number of unique 975 * colors available (color depth) 976 * pseudo_palette is not used 977 * RAMDAC[X] is programmed to (red, green, blue) 978 * color depth = var->{color}.length 979 */ 980 981 /* 982 * This is the point where the color is converted to something that 983 * is acceptable by the hardware. 984 */ 985#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) 986 red = CNVT_TOHW(red, info->var.red.length); 987 green = CNVT_TOHW(green, info->var.green.length); 988 blue = CNVT_TOHW(blue, info->var.blue.length); 989 transp = CNVT_TOHW(transp, info->var.transp.length); 990#undef CNVT_TOHW 991 992 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 993 info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 994 u32 v; 995 996 if (regno >= 16) 997 return -EINVAL; 998 999 v = (red << info->var.red.offset) | 1000 (green << info->var.green.offset) | 1001 (blue << info->var.blue.offset) | 1002 (transp << info->var.transp.offset); 1003 1004 switch (info->var.bits_per_pixel) { 1005 case 8: 1006 break; 1007 case 16: 1008 case 32: 1009 ((u32*)(info->pseudo_palette))[regno] = v; 1010 break; 1011 } 1012 return 0; 1013 } 1014 else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) 1015 pm3fb_set_color(par, regno, red, green, blue); 1016 1017 return 0; 1018} 1019 1020static int pm3fb_pan_display(struct fb_var_screeninfo *var, 1021 struct fb_info *info) 1022{ 1023 struct pm3_par *par = info->par; 1024 const u32 xres = (var->xres + 31) & ~31; 1025 1026 par->base = pm3fb_shift_bpp(var->bits_per_pixel, 1027 (var->yoffset * xres) 1028 + var->xoffset); 1029 PM3_WAIT(par, 1); 1030 PM3_WRITE_REG(par, PM3ScreenBase, par->base); 1031 return 0; 1032} 1033 1034static int pm3fb_blank(int blank_mode, struct fb_info *info) 1035{ 1036 struct pm3_par *par = info->par; 1037 u32 video = par->video; 1038 1039 /* 1040 * Oxygen VX1 - it appears that setting PM3VideoControl and 1041 * then PM3RD_SyncControl to the same SYNC settings undoes 1042 * any net change - they seem to xor together. Only set the 1043 * sync options in PM3RD_SyncControl. --rmk 1044 */ 1045 video &= ~(PM3VideoControl_HSYNC_MASK | 1046 PM3VideoControl_VSYNC_MASK); 1047 video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | 1048 PM3VideoControl_VSYNC_ACTIVE_HIGH; 1049 1050 switch (blank_mode) { 1051 case FB_BLANK_UNBLANK: 1052 video |= PM3VideoControl_ENABLE; 1053 break; 1054 case FB_BLANK_NORMAL: 1055 video &= ~PM3VideoControl_ENABLE; 1056 break; 1057 case FB_BLANK_HSYNC_SUSPEND: 1058 video &= ~(PM3VideoControl_HSYNC_MASK | 1059 PM3VideoControl_BLANK_ACTIVE_LOW); 1060 break; 1061 case FB_BLANK_VSYNC_SUSPEND: 1062 video &= ~(PM3VideoControl_VSYNC_MASK | 1063 PM3VideoControl_BLANK_ACTIVE_LOW); 1064 break; 1065 case FB_BLANK_POWERDOWN: 1066 video &= ~(PM3VideoControl_HSYNC_MASK | 1067 PM3VideoControl_VSYNC_MASK | 1068 PM3VideoControl_BLANK_ACTIVE_LOW); 1069 break; 1070 default: 1071 DPRINTK("Unsupported blanking %d\n", blank_mode); 1072 return 1; 1073 } 1074 1075 PM3_WAIT(par, 1); 1076 PM3_WRITE_REG(par,PM3VideoControl, video); 1077 return 0; 1078} 1079 1080 /* 1081 * Frame buffer operations 1082 */ 1083 1084static struct fb_ops pm3fb_ops = { 1085 .owner = THIS_MODULE, 1086 .fb_check_var = pm3fb_check_var, 1087 .fb_set_par = pm3fb_set_par, 1088 .fb_setcolreg = pm3fb_setcolreg, 1089 .fb_pan_display = pm3fb_pan_display, 1090 .fb_fillrect = pm3fb_fillrect, 1091 .fb_copyarea = pm3fb_copyarea, 1092 .fb_imageblit = pm3fb_imageblit, 1093 .fb_blank = pm3fb_blank, 1094 .fb_sync = pm3fb_sync, 1095}; 1096 1097/* ------------------------------------------------------------------------- */ 1098 1099 /* 1100 * Initialization 1101 */ 1102 1103/* mmio register are already mapped when this function is called */ 1104/* the pm3fb_fix.smem_start is also set */ 1105static unsigned long pm3fb_size_memory(struct pm3_par *par) 1106{ 1107 unsigned long memsize = 0, tempBypass, i, temp1, temp2; 1108 unsigned char __iomem *screen_mem; 1109 1110 pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */ 1111 /* Linear frame buffer - request region and map it. */ 1112 if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, 1113 "pm3fb smem")) { 1114 printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); 1115 return 0; 1116 } 1117 screen_mem = 1118 ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 1119 if (!screen_mem) { 1120 printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); 1121 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 1122 return 0; 1123 } 1124 1125 /* TODO: card-specific stuff, *before* accessing *any* FB memory */ 1126 /* For Appian Jeronimo 2000 board second head */ 1127 1128 tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask); 1129 1130 DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass); 1131 1132 PM3_WAIT(par, 1); 1133 PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF); 1134 1135 /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */ 1136 for (i = 0; i < 32; i++) { 1137 fb_writel(i * 0x00345678, 1138 (screen_mem + (i * 1048576))); 1139 mb(); 1140 temp1 = fb_readl((screen_mem + (i * 1048576))); 1141 1142 /* Let's check for wrapover, write will fail at 16MB boundary */ 1143 if (temp1 == (i * 0x00345678)) 1144 memsize = i; 1145 else 1146 break; 1147 } 1148 1149 DPRINTK("First detect pass already got %ld MB\n", memsize + 1); 1150 1151 if (memsize + 1 == i) { 1152 for (i = 0; i < 32; i++) { 1153 /* Clear first 32MB ; 0 is 0, no need to byteswap */ 1154 writel(0x0000000, (screen_mem + (i * 1048576))); 1155 } 1156 wmb(); 1157 1158 for (i = 32; i < 64; i++) { 1159 fb_writel(i * 0x00345678, 1160 (screen_mem + (i * 1048576))); 1161 mb(); 1162 temp1 = 1163 fb_readl((screen_mem + (i * 1048576))); 1164 temp2 = 1165 fb_readl((screen_mem + ((i - 32) * 1048576))); 1166 /* different value, different RAM... */ 1167 if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) 1168 memsize = i; 1169 else 1170 break; 1171 } 1172 } 1173 DPRINTK("Second detect pass got %ld MB\n", memsize + 1); 1174 1175 PM3_WAIT(par, 1); 1176 PM3_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass); 1177 1178 iounmap(screen_mem); 1179 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 1180 memsize = 1048576 * (memsize + 1); 1181 1182 DPRINTK("Returning 0x%08lx bytes\n", memsize); 1183 1184 return memsize; 1185} 1186 1187static int __devinit pm3fb_probe(struct pci_dev *dev, 1188 const struct pci_device_id *ent) 1189{ 1190 struct fb_info *info; 1191 struct pm3_par *par; 1192 struct device* device = &dev->dev; /* for pci drivers */ 1193 int err, retval = -ENXIO; 1194 1195 err = pci_enable_device(dev); 1196 if (err) { 1197 printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err); 1198 return err; 1199 } 1200 /* 1201 * Dynamically allocate info and par 1202 */ 1203 info = framebuffer_alloc(sizeof(struct pm3_par), device); 1204 1205 if (!info) 1206 return -ENOMEM; 1207 par = info->par; 1208 1209 /* 1210 * Here we set the screen_base to the virtual memory address 1211 * for the framebuffer. 1212 */ 1213 pm3fb_fix.mmio_start = pci_resource_start(dev, 0); 1214 pm3fb_fix.mmio_len = PM3_REGS_SIZE; 1215#if defined(__BIG_ENDIAN) 1216 pm3fb_fix.mmio_start += PM3_REGS_SIZE; 1217 DPRINTK("Adjusting register base for big-endian.\n"); 1218#endif 1219 1220 /* Registers - request region and map it. */ 1221 if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len, 1222 "pm3fb regbase")) { 1223 printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n"); 1224 goto err_exit_neither; 1225 } 1226 par->v_regs = 1227 ioremap_nocache(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 1228 if (!par->v_regs) { 1229 printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n", 1230 pm3fb_fix.id); 1231 release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 1232 goto err_exit_neither; 1233 } 1234 1235 /* Linear frame buffer - request region and map it. */ 1236 pm3fb_fix.smem_start = pci_resource_start(dev, 1); 1237 pm3fb_fix.smem_len = pm3fb_size_memory(par); 1238 if (!pm3fb_fix.smem_len) 1239 { 1240 printk(KERN_WARNING "pm3fb: Can't find memory on board.\n"); 1241 goto err_exit_mmio; 1242 } 1243 if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, 1244 "pm3fb smem")) { 1245 printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); 1246 goto err_exit_mmio; 1247 } 1248 info->screen_base = 1249 ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 1250 if (!info->screen_base) { 1251 printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); 1252 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 1253 goto err_exit_mmio; 1254 } 1255 info->screen_size = pm3fb_fix.smem_len; 1256 1257#ifdef CONFIG_MTRR 1258 if (!nomtrr) { 1259 par->mtrr_handle = mtrr_add(pm3fb_fix.smem_start, 1260 pm3fb_fix.smem_len, 1261 MTRR_TYPE_WRCOMB, 1); 1262 } 1263#endif 1264 info->fbops = &pm3fb_ops; 1265 1266 par->video = PM3_READ_REG(par, PM3VideoControl); 1267 1268 info->fix = pm3fb_fix; 1269 info->pseudo_palette = par->palette; 1270 info->flags = FBINFO_DEFAULT | 1271 FBINFO_HWACCEL_XPAN | 1272 FBINFO_HWACCEL_YPAN | 1273 FBINFO_HWACCEL_COPYAREA | 1274 FBINFO_HWACCEL_IMAGEBLIT | 1275 FBINFO_HWACCEL_FILLRECT; 1276 1277 if (noaccel) { 1278 printk(KERN_DEBUG "disabling acceleration\n"); 1279 info->flags |= FBINFO_HWACCEL_DISABLED; 1280 } 1281 info->pixmap.addr = kmalloc(PM3_PIXMAP_SIZE, GFP_KERNEL); 1282 if (!info->pixmap.addr) { 1283 retval = -ENOMEM; 1284 goto err_exit_pixmap; 1285 } 1286 info->pixmap.size = PM3_PIXMAP_SIZE; 1287 info->pixmap.buf_align = 4; 1288 info->pixmap.scan_align = 4; 1289 info->pixmap.access_align = 32; 1290 info->pixmap.flags = FB_PIXMAP_SYSTEM; 1291 1292 /* 1293 * This should give a reasonable default video mode. The following is 1294 * done when we can set a video mode. 1295 */ 1296 if (!mode_option) 1297 mode_option = "640x480@60"; 1298 1299 retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); 1300 1301 if (!retval || retval == 4) { 1302 retval = -EINVAL; 1303 goto err_exit_both; 1304 } 1305 1306 if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { 1307 retval = -ENOMEM; 1308 goto err_exit_both; 1309 } 1310 1311 /* 1312 * For drivers that can... 1313 */ 1314 pm3fb_check_var(&info->var, info); 1315 1316 if (register_framebuffer(info) < 0) { 1317 retval = -EINVAL; 1318 goto err_exit_all; 1319 } 1320 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, 1321 info->fix.id); 1322 pci_set_drvdata(dev, info); 1323 return 0; 1324 1325 err_exit_all: 1326 fb_dealloc_cmap(&info->cmap); 1327 err_exit_both: 1328 kfree(info->pixmap.addr); 1329 err_exit_pixmap: 1330 iounmap(info->screen_base); 1331 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 1332 err_exit_mmio: 1333 iounmap(par->v_regs); 1334 release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 1335 err_exit_neither: 1336 framebuffer_release(info); 1337 return retval; 1338} 1339 1340 /* 1341 * Cleanup 1342 */ 1343static void __devexit pm3fb_remove(struct pci_dev *dev) 1344{ 1345 struct fb_info *info = pci_get_drvdata(dev); 1346 1347 if (info) { 1348 struct fb_fix_screeninfo *fix = &info->fix; 1349 struct pm3_par *par = info->par; 1350 1351 unregister_framebuffer(info); 1352 fb_dealloc_cmap(&info->cmap); 1353 1354#ifdef CONFIG_MTRR 1355 if (par->mtrr_handle >= 0) 1356 mtrr_del(par->mtrr_handle, info->fix.smem_start, 1357 info->fix.smem_len); 1358#endif /* CONFIG_MTRR */ 1359 iounmap(info->screen_base); 1360 release_mem_region(fix->smem_start, fix->smem_len); 1361 iounmap(par->v_regs); 1362 release_mem_region(fix->mmio_start, fix->mmio_len); 1363 1364 pci_set_drvdata(dev, NULL); 1365 kfree(info->pixmap.addr); 1366 framebuffer_release(info); 1367 } 1368} 1369 1370static struct pci_device_id pm3fb_id_table[] = { 1371 { PCI_VENDOR_ID_3DLABS, 0x0a, 1372 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 1373 { 0, } 1374}; 1375 1376/* For PCI drivers */ 1377static struct pci_driver pm3fb_driver = { 1378 .name = "pm3fb", 1379 .id_table = pm3fb_id_table, 1380 .probe = pm3fb_probe, 1381 .remove = __devexit_p(pm3fb_remove), 1382}; 1383 1384MODULE_DEVICE_TABLE(pci, pm3fb_id_table); 1385 1386#ifndef MODULE 1387 /* 1388 * Setup 1389 */ 1390 1391/* 1392 * Only necessary if your driver takes special options, 1393 * otherwise we fall back on the generic fb_setup(). 1394 */ 1395static int __init pm3fb_setup(char *options) 1396{ 1397 char *this_opt; 1398 1399 /* Parse user speficied options (`video=pm3fb:') */ 1400 if (!options || !*options) 1401 return 0; 1402 1403 while ((this_opt = strsep(&options, ",")) != NULL) { 1404 if (!*this_opt) 1405 continue; 1406 else if (!strncmp(this_opt, "noaccel", 7)) { 1407 noaccel = 1; 1408#ifdef CONFIG_MTRR 1409 } else if (!strncmp(this_opt, "nomtrr", 6)) { 1410 nomtrr = 1; 1411#endif 1412 } else { 1413 mode_option = this_opt; 1414 } 1415 } 1416 return 0; 1417} 1418#endif /* MODULE */ 1419 1420static int __init pm3fb_init(void) 1421{ 1422 /* 1423 * For kernel boot options (in 'video=pm3fb:<options>' format) 1424 */ 1425#ifndef MODULE 1426 char *option = NULL; 1427 1428 if (fb_get_options("pm3fb", &option)) 1429 return -ENODEV; 1430 pm3fb_setup(option); 1431#endif 1432 1433 return pci_register_driver(&pm3fb_driver); 1434} 1435 1436#ifdef MODULE 1437static void __exit pm3fb_exit(void) 1438{ 1439 pci_unregister_driver(&pm3fb_driver); 1440} 1441 1442module_exit(pm3fb_exit); 1443#endif 1444module_init(pm3fb_init); 1445 1446module_param(noaccel, bool, 0); 1447MODULE_PARM_DESC(noaccel, "Disable acceleration"); 1448#ifdef CONFIG_MTRR 1449module_param(nomtrr, bool, 0); 1450MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); 1451#endif 1452 1453MODULE_DESCRIPTION("Permedia3 framebuffer device driver"); 1454MODULE_LICENSE("GPL"); 1455