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