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

Configure Feed

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

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