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