1 /* 2 * linux/drivers/video/stifb.c - 3 * Low level Frame buffer driver for HP workstations with 4 * STI (standard text interface) video firmware. 5 * 6 * Copyright (C) 2001-2006 Helge Deller <deller@gmx.de> 7 * Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de> 8 * 9 * Based on: 10 * - linux/drivers/video/artistfb.c -- Artist frame buffer driver 11 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> 12 * - based on skeletonfb, which was 13 * Created 28 Dec 1997 by Geert Uytterhoeven 14 * - HP Xhp cfb-based X11 window driver for XFree86 15 * (c)Copyright 1992 Hewlett-Packard Co. 16 * 17 * 18 * The following graphics display devices (NGLE family) are supported by this driver: 19 * 20 * HPA4070A known as "HCRX", a 1280x1024 color device with 8 planes 21 * HPA4071A known as "HCRX24", a 1280x1024 color device with 24 planes, 22 * optionally available with a hardware accelerator as HPA4071A_Z 23 * HPA1659A known as "CRX", a 1280x1024 color device with 8 planes 24 * HPA1439A known as "CRX24", a 1280x1024 color device with 24 planes, 25 * optionally available with a hardware accelerator. 26 * HPA1924A known as "GRX", a 1280x1024 grayscale device with 8 planes 27 * HPA2269A known as "Dual CRX", a 1280x1024 color device with 8 planes, 28 * implements support for two displays on a single graphics card. 29 * HP710C internal graphics support optionally available on the HP9000s710 SPU, 30 * supports 1280x1024 color displays with 8 planes. 31 * HP710G same as HP710C, 1280x1024 grayscale only 32 * HP710L same as HP710C, 1024x768 color only 33 * HP712 internal graphics support on HP9000s712 SPU, supports 640x480, 34 * 1024x768 or 1280x1024 color displays on 8 planes (Artist) 35 * 36 * This file is subject to the terms and conditions of the GNU General Public 37 * License. See the file COPYING in the main directory of this archive 38 * for more details. 39 */ 40 41 /* TODO: 42 * - 1bpp mode is completely untested 43 * - add support for h/w acceleration 44 * - add hardware cursor 45 * - automatically disable double buffering (e.g. on RDI precisionbook laptop) 46 */ 47 48 49 /* on supported graphic devices you may: 50 * #define FALLBACK_TO_1BPP to fall back to 1 bpp, or 51 * #undef FALLBACK_TO_1BPP to reject support for unsupported cards */ 52 #undef FALLBACK_TO_1BPP 53 54 #undef DEBUG_STIFB_REGS /* debug sti register accesses */ 55 56 57 #include <linux/module.h> 58 #include <linux/kernel.h> 59 #include <linux/errno.h> 60 #include <linux/string.h> 61 #include <linux/mm.h> 62 #include <linux/slab.h> 63 #include <linux/delay.h> 64 #include <linux/fb.h> 65 #include <linux/init.h> 66 #include <linux/ioport.h> 67 68 #include <asm/grfioctl.h> /* for HP-UX compatibility */ 69 #include <asm/uaccess.h> 70 71 #include "sticore.h" 72 73 /* REGION_BASE(fb_info, index) returns the virtual address for region <index> */ 74 #define REGION_BASE(fb_info, index) \ 75 F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index]) 76 77 #define NGLEDEVDEPROM_CRT_REGION 1 78 79 #define NR_PALETTE 256 80 81 typedef struct { 82 __s32 video_config_reg; 83 __s32 misc_video_start; 84 __s32 horiz_timing_fmt; 85 __s32 serr_timing_fmt; 86 __s32 vert_timing_fmt; 87 __s32 horiz_state; 88 __s32 vert_state; 89 __s32 vtg_state_elements; 90 __s32 pipeline_delay; 91 __s32 misc_video_end; 92 } video_setup_t; 93 94 typedef struct { 95 __s16 sizeof_ngle_data; 96 __s16 x_size_visible; /* visible screen dim in pixels */ 97 __s16 y_size_visible; 98 __s16 pad2[15]; 99 __s16 cursor_pipeline_delay; 100 __s16 video_interleaves; 101 __s32 pad3[11]; 102 } ngle_rom_t; 103 104 struct stifb_info { 105 struct fb_info info; 106 unsigned int id; 107 ngle_rom_t ngle_rom; 108 struct sti_struct *sti; 109 int deviceSpecificConfig; 110 u32 pseudo_palette[16]; 111 }; 112 113 static int __initdata stifb_bpp_pref[MAX_STI_ROMS]; 114 115 /* ------------------- chipset specific functions -------------------------- */ 116 117 /* offsets to graphic-chip internal registers */ 118 119 #define REG_1 0x000118 120 #define REG_2 0x000480 121 #define REG_3 0x0004a0 122 #define REG_4 0x000600 123 #define REG_6 0x000800 124 #define REG_7 0x000804 125 #define REG_8 0x000820 126 #define REG_9 0x000a04 127 #define REG_10 0x018000 128 #define REG_11 0x018004 129 #define REG_12 0x01800c 130 #define REG_13 0x018018 131 #define REG_14 0x01801c 132 #define REG_15 0x200000 133 #define REG_15b0 0x200000 134 #define REG_16b1 0x200005 135 #define REG_16b3 0x200007 136 #define REG_21 0x200218 137 #define REG_22 0x0005a0 138 #define REG_23 0x0005c0 139 #define REG_24 0x000808 140 #define REG_25 0x000b00 141 #define REG_26 0x200118 142 #define REG_27 0x200308 143 #define REG_32 0x21003c 144 #define REG_33 0x210040 145 #define REG_34 0x200008 146 #define REG_35 0x018010 147 #define REG_38 0x210020 148 #define REG_39 0x210120 149 #define REG_40 0x210130 150 #define REG_42 0x210028 151 #define REG_43 0x21002c 152 #define REG_44 0x210030 153 #define REG_45 0x210034 154 155 #define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg)) 156 #define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg)) 157 158 159 #ifndef DEBUG_STIFB_REGS 160 # define DEBUG_OFF() 161 # define DEBUG_ON() 162 # define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)) 163 # define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg)) 164 #else 165 static int debug_on = 1; 166 # define DEBUG_OFF() debug_on=0 167 # define DEBUG_ON() debug_on=1 168 # define WRITE_BYTE(value,fb,reg) do { if (debug_on) \ 169 printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \ 170 __func__, reg, value, READ_BYTE(fb,reg)); \ 171 gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0) 172 # define WRITE_WORD(value,fb,reg) do { if (debug_on) \ 173 printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \ 174 __func__, reg, value, READ_WORD(fb,reg)); \ 175 gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0) 176 #endif /* DEBUG_STIFB_REGS */ 177 178 179 #define ENABLE 1 /* for enabling/disabling screen */ 180 #define DISABLE 0 181 182 #define NGLE_LOCK(fb_info) do { } while (0) 183 #define NGLE_UNLOCK(fb_info) do { } while (0) 184 185 static void 186 SETUP_HW(struct stifb_info *fb) 187 { 188 char stat; 189 190 do { 191 stat = READ_BYTE(fb, REG_15b0); 192 if (!stat) 193 stat = READ_BYTE(fb, REG_15b0); 194 } while (stat); 195 } 196 197 198 static void 199 SETUP_FB(struct stifb_info *fb) 200 { 201 unsigned int reg10_value = 0; 202 203 SETUP_HW(fb); 204 switch (fb->id) 205 { 206 case CRT_ID_VISUALIZE_EG: 207 case S9000_ID_ARTIST: 208 case S9000_ID_A1659A: 209 reg10_value = 0x13601000; 210 break; 211 case S9000_ID_A1439A: 212 if (fb->info.var.bits_per_pixel == 32) 213 reg10_value = 0xBBA0A000; 214 else 215 reg10_value = 0x13601000; 216 break; 217 case S9000_ID_HCRX: 218 if (fb->info.var.bits_per_pixel == 32) 219 reg10_value = 0xBBA0A000; 220 else 221 reg10_value = 0x13602000; 222 break; 223 case S9000_ID_TIMBER: 224 case CRX24_OVERLAY_PLANES: 225 reg10_value = 0x13602000; 226 break; 227 } 228 if (reg10_value) 229 WRITE_WORD(reg10_value, fb, REG_10); 230 WRITE_WORD(0x83000300, fb, REG_14); 231 SETUP_HW(fb); 232 WRITE_BYTE(1, fb, REG_16b1); 233 } 234 235 static void 236 START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) 237 { 238 SETUP_HW(fb); 239 WRITE_WORD(0xBBE0F000, fb, REG_10); 240 WRITE_WORD(0x03000300, fb, REG_14); 241 WRITE_WORD(~0, fb, REG_13); 242 } 243 244 static void 245 WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color) 246 { 247 SETUP_HW(fb); 248 WRITE_WORD(((0x100+index)<<2), fb, REG_3); 249 WRITE_WORD(color, fb, REG_4); 250 } 251 252 static void 253 FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) 254 { 255 WRITE_WORD(0x400, fb, REG_2); 256 if (fb->info.var.bits_per_pixel == 32) { 257 WRITE_WORD(0x83000100, fb, REG_1); 258 } else { 259 if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG) 260 WRITE_WORD(0x80000100, fb, REG_26); 261 else 262 WRITE_WORD(0x80000100, fb, REG_1); 263 } 264 SETUP_FB(fb); 265 } 266 267 static void 268 SETUP_RAMDAC(struct stifb_info *fb) 269 { 270 SETUP_HW(fb); 271 WRITE_WORD(0x04000000, fb, 0x1020); 272 WRITE_WORD(0xff000000, fb, 0x1028); 273 } 274 275 static void 276 CRX24_SETUP_RAMDAC(struct stifb_info *fb) 277 { 278 SETUP_HW(fb); 279 WRITE_WORD(0x04000000, fb, 0x1000); 280 WRITE_WORD(0x02000000, fb, 0x1004); 281 WRITE_WORD(0xff000000, fb, 0x1008); 282 WRITE_WORD(0x05000000, fb, 0x1000); 283 WRITE_WORD(0x02000000, fb, 0x1004); 284 WRITE_WORD(0x03000000, fb, 0x1008); 285 } 286 287 #if 0 288 static void 289 HCRX_SETUP_RAMDAC(struct stifb_info *fb) 290 { 291 WRITE_WORD(0xffffffff, fb, REG_32); 292 } 293 #endif 294 295 static void 296 CRX24_SET_OVLY_MASK(struct stifb_info *fb) 297 { 298 SETUP_HW(fb); 299 WRITE_WORD(0x13a02000, fb, REG_11); 300 WRITE_WORD(0x03000300, fb, REG_14); 301 WRITE_WORD(0x000017f0, fb, REG_3); 302 WRITE_WORD(0xffffffff, fb, REG_13); 303 WRITE_WORD(0xffffffff, fb, REG_22); 304 WRITE_WORD(0x00000000, fb, REG_23); 305 } 306 307 static void 308 ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) 309 { 310 unsigned int value = enable ? 0x43000000 : 0x03000000; 311 SETUP_HW(fb); 312 WRITE_WORD(0x06000000, fb, 0x1030); 313 WRITE_WORD(value, fb, 0x1038); 314 } 315 316 static void 317 CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) 318 { 319 unsigned int value = enable ? 0x10000000 : 0x30000000; 320 SETUP_HW(fb); 321 WRITE_WORD(0x01000000, fb, 0x1000); 322 WRITE_WORD(0x02000000, fb, 0x1004); 323 WRITE_WORD(value, fb, 0x1008); 324 } 325 326 static void 327 ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) 328 { 329 u32 DregsMiscVideo = REG_21; 330 u32 DregsMiscCtl = REG_27; 331 332 SETUP_HW(fb); 333 if (enable) { 334 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo); 335 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl); 336 } else { 337 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo); 338 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl); 339 } 340 } 341 342 #define GET_ROMTABLE_INDEX(fb) \ 343 (READ_BYTE(fb, REG_16b3) - 1) 344 345 #define HYPER_CONFIG_PLANES_24 0x00000100 346 347 #define IS_24_DEVICE(fb) \ 348 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24) 349 350 #define IS_888_DEVICE(fb) \ 351 (!(IS_24_DEVICE(fb))) 352 353 #define GET_FIFO_SLOTS(fb, cnt, numslots) \ 354 { while (cnt < numslots) \ 355 cnt = READ_WORD(fb, REG_34); \ 356 cnt -= numslots; \ 357 } 358 359 #define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */ 360 #define Otc04 2 /* Pixels in each longword transfer (4) */ 361 #define Otc32 5 /* Pixels in each longword transfer (32) */ 362 #define Ots08 3 /* Each pixel is size (8)d transfer (1) */ 363 #define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */ 364 #define AddrLong 5 /* FB address is Long aligned (pixel) */ 365 #define BINovly 0x2 /* 8 bit overlay */ 366 #define BINapp0I 0x0 /* Application Buffer 0, Indexed */ 367 #define BINapp1I 0x1 /* Application Buffer 1, Indexed */ 368 #define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */ 369 #define BINattr 0xd /* Attribute Bitmap */ 370 #define RopSrc 0x3 371 #define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */ 372 #define BitmapExtent32 5 /* Each write hits (32) bits in depth */ 373 #define DataDynamic 0 /* Data register reloaded by direct access */ 374 #define MaskDynamic 1 /* Mask register reloaded by direct access */ 375 #define MaskOtc 0 /* Mask contains Object Count valid bits */ 376 377 #define MaskAddrOffset(offset) (offset) 378 #define StaticReg(en) (en) 379 #define BGx(en) (en) 380 #define FGx(en) (en) 381 382 #define BAJustPoint(offset) (offset) 383 #define BAIndexBase(base) (base) 384 #define BA(F,C,S,A,J,B,I) \ 385 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I)) 386 387 #define IBOvals(R,M,X,S,D,L,B,F) \ 388 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F)) 389 390 #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \ 391 WRITE_WORD(val, fb, REG_14) 392 393 #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \ 394 WRITE_WORD(val, fb, REG_11) 395 396 #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \ 397 WRITE_WORD(val, fb, REG_12) 398 399 #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \ 400 WRITE_WORD(plnmsk32, fb, REG_13) 401 402 #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \ 403 WRITE_WORD(fg32, fb, REG_35) 404 405 #define NGLE_SET_TRANSFERDATA(fb, val) \ 406 WRITE_WORD(val, fb, REG_8) 407 408 #define NGLE_SET_DSTXY(fb, val) \ 409 WRITE_WORD(val, fb, REG_6) 410 411 #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \ 412 (u32) (fbaddrbase) + \ 413 ( (unsigned int) ( (y) << 13 ) | \ 414 (unsigned int) ( (x) << 2 ) ) \ 415 ) 416 417 #define NGLE_BINC_SET_DSTADDR(fb, addr) \ 418 WRITE_WORD(addr, fb, REG_3) 419 420 #define NGLE_BINC_SET_SRCADDR(fb, addr) \ 421 WRITE_WORD(addr, fb, REG_2) 422 423 #define NGLE_BINC_SET_DSTMASK(fb, mask) \ 424 WRITE_WORD(mask, fb, REG_22) 425 426 #define NGLE_BINC_WRITE32(fb, data32) \ 427 WRITE_WORD(data32, fb, REG_23) 428 429 #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \ 430 WRITE_WORD((cmapBltCtlData32), fb, REG_38) 431 432 #define SET_LENXY_START_RECFILL(fb, lenxy) \ 433 WRITE_WORD(lenxy, fb, REG_9) 434 435 #define SETUP_COPYAREA(fb) \ 436 WRITE_BYTE(0, fb, REG_16b1) 437 438 static void 439 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) 440 { 441 u32 DregsHypMiscVideo = REG_33; 442 unsigned int value; 443 SETUP_HW(fb); 444 value = READ_WORD(fb, DregsHypMiscVideo); 445 if (enable) 446 value |= 0x0A000000; 447 else 448 value &= ~0x0A000000; 449 WRITE_WORD(value, fb, DregsHypMiscVideo); 450 } 451 452 453 /* BufferNumbers used by SETUP_ATTR_ACCESS() */ 454 #define BUFF0_CMAP0 0x00001e02 455 #define BUFF1_CMAP0 0x02001e02 456 #define BUFF1_CMAP3 0x0c001e02 457 #define ARTIST_CMAP0 0x00000102 458 #define HYPER_CMAP8 0x00000100 459 #define HYPER_CMAP24 0x00000800 460 461 static void 462 SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber) 463 { 464 SETUP_HW(fb); 465 WRITE_WORD(0x2EA0D000, fb, REG_11); 466 WRITE_WORD(0x23000302, fb, REG_14); 467 WRITE_WORD(BufferNumber, fb, REG_12); 468 WRITE_WORD(0xffffffff, fb, REG_8); 469 } 470 471 static void 472 SET_ATTR_SIZE(struct stifb_info *fb, int width, int height) 473 { 474 /* REG_6 seems to have special values when run on a 475 RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or 476 INTERNAL_EG_X1024). The values are: 477 0x2f0: internal (LCD) & external display enabled 478 0x2a0: external display only 479 0x000: zero on standard artist graphic cards 480 */ 481 WRITE_WORD(0x00000000, fb, REG_6); 482 WRITE_WORD((width<<16) | height, fb, REG_9); 483 WRITE_WORD(0x05000000, fb, REG_6); 484 WRITE_WORD(0x00040001, fb, REG_9); 485 } 486 487 static void 488 FINISH_ATTR_ACCESS(struct stifb_info *fb) 489 { 490 SETUP_HW(fb); 491 WRITE_WORD(0x00000000, fb, REG_12); 492 } 493 494 static void 495 elkSetupPlanes(struct stifb_info *fb) 496 { 497 SETUP_RAMDAC(fb); 498 SETUP_FB(fb); 499 } 500 501 static void 502 ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber) 503 { 504 SETUP_ATTR_ACCESS(fb, BufferNumber); 505 SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres); 506 FINISH_ATTR_ACCESS(fb); 507 SETUP_FB(fb); 508 } 509 510 511 static void 512 rattlerSetupPlanes(struct stifb_info *fb) 513 { 514 int saved_id, y; 515 516 /* Write RAMDAC pixel read mask register so all overlay 517 * planes are display-enabled. (CRX24 uses Bt462 pixel 518 * read mask register for overlay planes, not image planes). 519 */ 520 CRX24_SETUP_RAMDAC(fb); 521 522 /* change fb->id temporarily to fool SETUP_FB() */ 523 saved_id = fb->id; 524 fb->id = CRX24_OVERLAY_PLANES; 525 SETUP_FB(fb); 526 fb->id = saved_id; 527 528 for (y = 0; y < fb->info.var.yres; ++y) 529 memset(fb->info.screen_base + y * fb->info.fix.line_length, 530 0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8); 531 532 CRX24_SET_OVLY_MASK(fb); 533 SETUP_FB(fb); 534 } 535 536 537 #define HYPER_CMAP_TYPE 0 538 #define NGLE_CMAP_INDEXED0_TYPE 0 539 #define NGLE_CMAP_OVERLAY_TYPE 3 540 541 /* typedef of LUT (Colormap) BLT Control Register */ 542 typedef union /* Note assumption that fields are packed left-to-right */ 543 { u32 all; 544 struct 545 { 546 unsigned enable : 1; 547 unsigned waitBlank : 1; 548 unsigned reserved1 : 4; 549 unsigned lutOffset : 10; /* Within destination LUT */ 550 unsigned lutType : 2; /* Cursor, image, overlay */ 551 unsigned reserved2 : 4; 552 unsigned length : 10; 553 } fields; 554 } NgleLutBltCtl; 555 556 557 #if 0 558 static NgleLutBltCtl 559 setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) 560 { 561 NgleLutBltCtl lutBltCtl; 562 563 /* set enable, zero reserved fields */ 564 lutBltCtl.all = 0x80000000; 565 lutBltCtl.fields.length = length; 566 567 switch (fb->id) 568 { 569 case S9000_ID_A1439A: /* CRX24 */ 570 if (fb->var.bits_per_pixel == 8) { 571 lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE; 572 lutBltCtl.fields.lutOffset = 0; 573 } else { 574 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE; 575 lutBltCtl.fields.lutOffset = 0 * 256; 576 } 577 break; 578 579 case S9000_ID_ARTIST: 580 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE; 581 lutBltCtl.fields.lutOffset = 0 * 256; 582 break; 583 584 default: 585 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE; 586 lutBltCtl.fields.lutOffset = 0; 587 break; 588 } 589 590 /* Offset points to start of LUT. Adjust for within LUT */ 591 lutBltCtl.fields.lutOffset += offsetWithinLut; 592 593 return lutBltCtl; 594 } 595 #endif 596 597 static NgleLutBltCtl 598 setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) 599 { 600 NgleLutBltCtl lutBltCtl; 601 602 /* set enable, zero reserved fields */ 603 lutBltCtl.all = 0x80000000; 604 605 lutBltCtl.fields.length = length; 606 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE; 607 608 /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */ 609 if (fb->info.var.bits_per_pixel == 8) 610 lutBltCtl.fields.lutOffset = 2 * 256; 611 else 612 lutBltCtl.fields.lutOffset = 0 * 256; 613 614 /* Offset points to start of LUT. Adjust for within LUT */ 615 lutBltCtl.fields.lutOffset += offsetWithinLut; 616 617 return lutBltCtl; 618 } 619 620 621 static void hyperUndoITE(struct stifb_info *fb) 622 { 623 int nFreeFifoSlots = 0; 624 u32 fbAddr; 625 626 NGLE_LOCK(fb); 627 628 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1); 629 WRITE_WORD(0xffffffff, fb, REG_32); 630 631 /* Write overlay transparency mask so only entry 255 is transparent */ 632 633 /* Hardware setup for full-depth write to "magic" location */ 634 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7); 635 NGLE_QUICK_SET_DST_BM_ACCESS(fb, 636 BA(IndexedDcd, Otc04, Ots08, AddrLong, 637 BAJustPoint(0), BINovly, BAIndexBase(0))); 638 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, 639 IBOvals(RopSrc, MaskAddrOffset(0), 640 BitmapExtent08, StaticReg(0), 641 DataDynamic, MaskOtc, BGx(0), FGx(0))); 642 643 /* Now prepare to write to the "magic" location */ 644 fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0); 645 NGLE_BINC_SET_DSTADDR(fb, fbAddr); 646 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff); 647 NGLE_BINC_SET_DSTMASK(fb, 0xffffffff); 648 649 /* Finally, write a zero to clear the mask */ 650 NGLE_BINC_WRITE32(fb, 0); 651 652 NGLE_UNLOCK(fb); 653 } 654 655 static void 656 ngleDepth8_ClearImagePlanes(struct stifb_info *fb) 657 { 658 /* FIXME! */ 659 } 660 661 static void 662 ngleDepth24_ClearImagePlanes(struct stifb_info *fb) 663 { 664 /* FIXME! */ 665 } 666 667 static void 668 ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg) 669 { 670 int nFreeFifoSlots = 0; 671 u32 packed_dst; 672 u32 packed_len; 673 674 NGLE_LOCK(fb); 675 676 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4); 677 NGLE_QUICK_SET_DST_BM_ACCESS(fb, 678 BA(IndexedDcd, Otc32, OtsIndirect, 679 AddrLong, BAJustPoint(0), 680 BINattr, BAIndexBase(0))); 681 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg); 682 NGLE_SET_TRANSFERDATA(fb, 0xffffffff); 683 684 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, 685 IBOvals(RopSrc, MaskAddrOffset(0), 686 BitmapExtent08, StaticReg(1), 687 DataDynamic, MaskOtc, 688 BGx(0), FGx(0))); 689 packed_dst = 0; 690 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres; 691 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2); 692 NGLE_SET_DSTXY(fb, packed_dst); 693 SET_LENXY_START_RECFILL(fb, packed_len); 694 695 /* 696 * In order to work around an ELK hardware problem (Buffy doesn't 697 * always flush it's buffers when writing to the attribute 698 * planes), at least 4 pixels must be written to the attribute 699 * planes starting at (X == 1280) and (Y != to the last Y written 700 * by BIF): 701 */ 702 703 if (fb->id == S9000_ID_A1659A) { /* ELK_DEVICE_ID */ 704 /* It's safe to use scanline zero: */ 705 packed_dst = (1280 << 16); 706 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2); 707 NGLE_SET_DSTXY(fb, packed_dst); 708 packed_len = (4 << 16) | 1; 709 SET_LENXY_START_RECFILL(fb, packed_len); 710 } /* ELK Hardware Kludge */ 711 712 /**** Finally, set the Control Plane Register back to zero: ****/ 713 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1); 714 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0); 715 716 NGLE_UNLOCK(fb); 717 } 718 719 static void 720 ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data) 721 { 722 int nFreeFifoSlots = 0; 723 u32 packed_dst; 724 u32 packed_len; 725 726 NGLE_LOCK(fb); 727 728 /* Hardware setup */ 729 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8); 730 NGLE_QUICK_SET_DST_BM_ACCESS(fb, 731 BA(IndexedDcd, Otc04, Ots08, AddrLong, 732 BAJustPoint(0), BINovly, BAIndexBase(0))); 733 734 NGLE_SET_TRANSFERDATA(fb, 0xffffffff); /* Write foreground color */ 735 736 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data); 737 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask); 738 739 packed_dst = 0; 740 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres; 741 NGLE_SET_DSTXY(fb, packed_dst); 742 743 /* Write zeroes to overlay planes */ 744 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, 745 IBOvals(RopSrc, MaskAddrOffset(0), 746 BitmapExtent08, StaticReg(0), 747 DataDynamic, MaskOtc, BGx(0), FGx(0))); 748 749 SET_LENXY_START_RECFILL(fb, packed_len); 750 751 NGLE_UNLOCK(fb); 752 } 753 754 static void 755 hyperResetPlanes(struct stifb_info *fb, int enable) 756 { 757 unsigned int controlPlaneReg; 758 759 NGLE_LOCK(fb); 760 761 if (IS_24_DEVICE(fb)) 762 if (fb->info.var.bits_per_pixel == 32) 763 controlPlaneReg = 0x04000F00; 764 else 765 controlPlaneReg = 0x00000F00; /* 0x00000800 should be enough, but lets clear all 4 bits */ 766 else 767 controlPlaneReg = 0x00000F00; /* 0x00000100 should be enough, but lets clear all 4 bits */ 768 769 switch (enable) { 770 case ENABLE: 771 /* clear screen */ 772 if (IS_24_DEVICE(fb)) 773 ngleDepth24_ClearImagePlanes(fb); 774 else 775 ngleDepth8_ClearImagePlanes(fb); 776 777 /* Paint attribute planes for default case. 778 * On Hyperdrive, this means all windows using overlay cmap 0. */ 779 ngleResetAttrPlanes(fb, controlPlaneReg); 780 781 /* clear overlay planes */ 782 ngleClearOverlayPlanes(fb, 0xff, 255); 783 784 /************************************************** 785 ** Also need to counteract ITE settings 786 **************************************************/ 787 hyperUndoITE(fb); 788 break; 789 790 case DISABLE: 791 /* clear screen */ 792 if (IS_24_DEVICE(fb)) 793 ngleDepth24_ClearImagePlanes(fb); 794 else 795 ngleDepth8_ClearImagePlanes(fb); 796 ngleResetAttrPlanes(fb, controlPlaneReg); 797 ngleClearOverlayPlanes(fb, 0xff, 0); 798 break; 799 800 case -1: /* RESET */ 801 hyperUndoITE(fb); 802 ngleResetAttrPlanes(fb, controlPlaneReg); 803 break; 804 } 805 806 NGLE_UNLOCK(fb); 807 } 808 809 /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */ 810 811 static void 812 ngleGetDeviceRomData(struct stifb_info *fb) 813 { 814 #if 0 815 XXX: FIXME: !!! 816 int *pBytePerLongDevDepData;/* data byte == LSB */ 817 int *pRomTable; 818 NgleDevRomData *pPackedDevRomData; 819 int sizePackedDevRomData = sizeof(*pPackedDevRomData); 820 char *pCard8; 821 int i; 822 char *mapOrigin = NULL; 823 824 int romTableIdx; 825 826 pPackedDevRomData = fb->ngle_rom; 827 828 SETUP_HW(fb); 829 if (fb->id == S9000_ID_ARTIST) { 830 pPackedDevRomData->cursor_pipeline_delay = 4; 831 pPackedDevRomData->video_interleaves = 4; 832 } else { 833 /* Get pointer to unpacked byte/long data in ROM */ 834 pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION]; 835 836 /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */ 837 if (fb->id == S9000_ID_TOMCAT) 838 { 839 /* jump to the correct ROM table */ 840 GET_ROMTABLE_INDEX(romTableIdx); 841 while (romTableIdx > 0) 842 { 843 pCard8 = (Card8 *) pPackedDevRomData; 844 pRomTable = pBytePerLongDevDepData; 845 /* Pack every fourth byte from ROM into structure */ 846 for (i = 0; i < sizePackedDevRomData; i++) 847 { 848 *pCard8++ = (Card8) (*pRomTable++); 849 } 850 851 pBytePerLongDevDepData = (Card32 *) 852 ((Card8 *) pBytePerLongDevDepData + 853 pPackedDevRomData->sizeof_ngle_data); 854 855 romTableIdx--; 856 } 857 } 858 859 pCard8 = (Card8 *) pPackedDevRomData; 860 861 /* Pack every fourth byte from ROM into structure */ 862 for (i = 0; i < sizePackedDevRomData; i++) 863 { 864 *pCard8++ = (Card8) (*pBytePerLongDevDepData++); 865 } 866 } 867 868 SETUP_FB(fb); 869 #endif 870 } 871 872 873 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4 874 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8 875 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10 876 #define HYPERBOWL_MODE2_8_24 15 877 878 /* HCRX specific boot-time initialization */ 879 static void __init 880 SETUP_HCRX(struct stifb_info *fb) 881 { 882 int hyperbowl; 883 int nFreeFifoSlots = 0; 884 885 if (fb->id != S9000_ID_HCRX) 886 return; 887 888 /* Initialize Hyperbowl registers */ 889 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7); 890 891 if (IS_24_DEVICE(fb)) { 892 hyperbowl = (fb->info.var.bits_per_pixel == 32) ? 893 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE : 894 HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE; 895 896 /* First write to Hyperbowl must happen twice (bug) */ 897 WRITE_WORD(hyperbowl, fb, REG_40); 898 WRITE_WORD(hyperbowl, fb, REG_40); 899 900 WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39); 901 902 WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */ 903 WRITE_WORD(0x404c4048, fb, REG_43); 904 WRITE_WORD(0x034c0348, fb, REG_44); 905 WRITE_WORD(0x444c4448, fb, REG_45); 906 } else { 907 hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES; 908 909 /* First write to Hyperbowl must happen twice (bug) */ 910 WRITE_WORD(hyperbowl, fb, REG_40); 911 WRITE_WORD(hyperbowl, fb, REG_40); 912 913 WRITE_WORD(0x00000000, fb, REG_42); 914 WRITE_WORD(0x00000000, fb, REG_43); 915 WRITE_WORD(0x00000000, fb, REG_44); 916 WRITE_WORD(0x444c4048, fb, REG_45); 917 } 918 } 919 920 921 /* ------------------- driver specific functions --------------------------- */ 922 923 static int 924 stifb_setcolreg(u_int regno, u_int red, u_int green, 925 u_int blue, u_int transp, struct fb_info *info) 926 { 927 struct stifb_info *fb = container_of(info, struct stifb_info, info); 928 u32 color; 929 930 if (regno >= NR_PALETTE) 931 return 1; 932 933 red >>= 8; 934 green >>= 8; 935 blue >>= 8; 936 937 DEBUG_OFF(); 938 939 START_IMAGE_COLORMAP_ACCESS(fb); 940 941 if (unlikely(fb->info.var.grayscale)) { 942 /* gray = 0.30*R + 0.59*G + 0.11*B */ 943 color = ((red * 77) + 944 (green * 151) + 945 (blue * 28)) >> 8; 946 } else { 947 color = ((red << 16) | 948 (green << 8) | 949 (blue)); 950 } 951 952 if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) { 953 struct fb_var_screeninfo *var = &fb->info.var; 954 if (regno < 16) 955 ((u32 *)fb->info.pseudo_palette)[regno] = 956 regno << var->red.offset | 957 regno << var->green.offset | 958 regno << var->blue.offset; 959 } 960 961 WRITE_IMAGE_COLOR(fb, regno, color); 962 963 if (fb->id == S9000_ID_HCRX) { 964 NgleLutBltCtl lutBltCtl; 965 966 lutBltCtl = setHyperLutBltCtl(fb, 967 0, /* Offset w/i LUT */ 968 256); /* Load entire LUT */ 969 NGLE_BINC_SET_SRCADDR(fb, 970 NGLE_LONG_FB_ADDRESS(0, 0x100, 0)); 971 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */ 972 START_COLORMAPLOAD(fb, lutBltCtl.all); 973 SETUP_FB(fb); 974 } else { 975 /* cleanup colormap hardware */ 976 FINISH_IMAGE_COLORMAP_ACCESS(fb); 977 } 978 979 DEBUG_ON(); 980 981 return 0; 982 } 983 984 static int 985 stifb_blank(int blank_mode, struct fb_info *info) 986 { 987 struct stifb_info *fb = container_of(info, struct stifb_info, info); 988 int enable = (blank_mode == 0) ? ENABLE : DISABLE; 989 990 switch (fb->id) { 991 case S9000_ID_A1439A: 992 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable); 993 break; 994 case CRT_ID_VISUALIZE_EG: 995 case S9000_ID_ARTIST: 996 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable); 997 break; 998 case S9000_ID_HCRX: 999 HYPER_ENABLE_DISABLE_DISPLAY(fb, enable); 1000 break; 1001 case S9000_ID_A1659A: /* fall through */ 1002 case S9000_ID_TIMBER: 1003 case CRX24_OVERLAY_PLANES: 1004 default: 1005 ENABLE_DISABLE_DISPLAY(fb, enable); 1006 break; 1007 } 1008 1009 SETUP_FB(fb); 1010 return 0; 1011 } 1012 1013 static void 1014 stifb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 1015 { 1016 struct stifb_info *fb = container_of(info, struct stifb_info, info); 1017 1018 SETUP_COPYAREA(fb); 1019 1020 SETUP_HW(fb); 1021 if (fb->info.var.bits_per_pixel == 32) { 1022 WRITE_WORD(0xBBA0A000, fb, REG_10); 1023 1024 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff); 1025 } else { 1026 WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10); 1027 1028 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff); 1029 } 1030 1031 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, 1032 IBOvals(RopSrc, MaskAddrOffset(0), 1033 BitmapExtent08, StaticReg(1), 1034 DataDynamic, MaskOtc, BGx(0), FGx(0))); 1035 1036 WRITE_WORD(((area->sx << 16) | area->sy), fb, REG_24); 1037 WRITE_WORD(((area->width << 16) | area->height), fb, REG_7); 1038 WRITE_WORD(((area->dx << 16) | area->dy), fb, REG_25); 1039 1040 SETUP_FB(fb); 1041 } 1042 1043 static void __init 1044 stifb_init_display(struct stifb_info *fb) 1045 { 1046 int id = fb->id; 1047 1048 SETUP_FB(fb); 1049 1050 /* HCRX specific initialization */ 1051 SETUP_HCRX(fb); 1052 1053 /* 1054 if (id == S9000_ID_HCRX) 1055 hyperInitSprite(fb); 1056 else 1057 ngleInitSprite(fb); 1058 */ 1059 1060 /* Initialize the image planes. */ 1061 switch (id) { 1062 case S9000_ID_HCRX: 1063 hyperResetPlanes(fb, ENABLE); 1064 break; 1065 case S9000_ID_A1439A: 1066 rattlerSetupPlanes(fb); 1067 break; 1068 case S9000_ID_A1659A: 1069 case S9000_ID_ARTIST: 1070 case CRT_ID_VISUALIZE_EG: 1071 elkSetupPlanes(fb); 1072 break; 1073 } 1074 1075 /* Clear attribute planes on non HCRX devices. */ 1076 switch (id) { 1077 case S9000_ID_A1659A: 1078 case S9000_ID_A1439A: 1079 if (fb->info.var.bits_per_pixel == 32) 1080 ngleSetupAttrPlanes(fb, BUFF1_CMAP3); 1081 else { 1082 ngleSetupAttrPlanes(fb, BUFF1_CMAP0); 1083 } 1084 if (id == S9000_ID_A1439A) 1085 ngleClearOverlayPlanes(fb, 0xff, 0); 1086 break; 1087 case S9000_ID_ARTIST: 1088 case CRT_ID_VISUALIZE_EG: 1089 if (fb->info.var.bits_per_pixel == 32) 1090 ngleSetupAttrPlanes(fb, BUFF1_CMAP3); 1091 else { 1092 ngleSetupAttrPlanes(fb, ARTIST_CMAP0); 1093 } 1094 break; 1095 } 1096 stifb_blank(0, (struct fb_info *)fb); /* 0=enable screen */ 1097 1098 SETUP_FB(fb); 1099 } 1100 1101 /* ------------ Interfaces to hardware functions ------------ */ 1102 1103 static struct fb_ops stifb_ops = { 1104 .owner = THIS_MODULE, 1105 .fb_setcolreg = stifb_setcolreg, 1106 .fb_blank = stifb_blank, 1107 .fb_fillrect = cfb_fillrect, 1108 .fb_copyarea = stifb_copyarea, 1109 .fb_imageblit = cfb_imageblit, 1110 }; 1111 1112 1113 /* 1114 * Initialization 1115 */ 1116 1117 static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) 1118 { 1119 struct fb_fix_screeninfo *fix; 1120 struct fb_var_screeninfo *var; 1121 struct stifb_info *fb; 1122 struct fb_info *info; 1123 unsigned long sti_rom_address; 1124 char *dev_name; 1125 int bpp, xres, yres; 1126 1127 fb = kzalloc(sizeof(*fb), GFP_ATOMIC); 1128 if (!fb) { 1129 printk(KERN_ERR "stifb: Could not allocate stifb structure\n"); 1130 return -ENODEV; 1131 } 1132 1133 info = &fb->info; 1134 1135 /* set struct to a known state */ 1136 fix = &info->fix; 1137 var = &info->var; 1138 1139 fb->sti = sti; 1140 dev_name = sti->sti_data->inq_outptr.dev_name; 1141 /* store upper 32bits of the graphics id */ 1142 fb->id = fb->sti->graphics_id[0]; 1143 1144 /* only supported cards are allowed */ 1145 switch (fb->id) { 1146 case CRT_ID_VISUALIZE_EG: 1147 /* Visualize cards can run either in "double buffer" or 1148 "standard" mode. Depending on the mode, the card reports 1149 a different device name, e.g. "INTERNAL_EG_DX1024" in double 1150 buffer mode and "INTERNAL_EG_X1024" in standard mode. 1151 Since this driver only supports standard mode, we check 1152 if the device name contains the string "DX" and tell the 1153 user how to reconfigure the card. */ 1154 if (strstr(dev_name, "DX")) { 1155 printk(KERN_WARNING 1156 "WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n" 1157 "WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n", 1158 dev_name); 1159 goto out_err0; 1160 } 1161 /* fall though */ 1162 case S9000_ID_ARTIST: 1163 case S9000_ID_HCRX: 1164 case S9000_ID_TIMBER: 1165 case S9000_ID_A1659A: 1166 case S9000_ID_A1439A: 1167 break; 1168 default: 1169 printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n", 1170 dev_name, fb->id); 1171 goto out_err0; 1172 } 1173 1174 /* default to 8 bpp on most graphic chips */ 1175 bpp = 8; 1176 xres = sti_onscreen_x(fb->sti); 1177 yres = sti_onscreen_y(fb->sti); 1178 1179 ngleGetDeviceRomData(fb); 1180 1181 /* get (virtual) io region base addr */ 1182 fix->mmio_start = REGION_BASE(fb,2); 1183 fix->mmio_len = 0x400000; 1184 1185 /* Reject any device not in the NGLE family */ 1186 switch (fb->id) { 1187 case S9000_ID_A1659A: /* CRX/A1659A */ 1188 break; 1189 case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */ 1190 var->grayscale = 1; 1191 fb->id = S9000_ID_A1659A; 1192 break; 1193 case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */ 1194 if (strstr(dev_name, "GRAYSCALE") || 1195 strstr(dev_name, "Grayscale") || 1196 strstr(dev_name, "grayscale")) 1197 var->grayscale = 1; 1198 break; 1199 case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */ 1200 /* FIXME: TomCat supports two heads: 1201 * fb.iobase = REGION_BASE(fb_info,3); 1202 * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx); 1203 * for now we only support the left one ! */ 1204 xres = fb->ngle_rom.x_size_visible; 1205 yres = fb->ngle_rom.y_size_visible; 1206 fb->id = S9000_ID_A1659A; 1207 break; 1208 case S9000_ID_A1439A: /* CRX24/A1439A */ 1209 bpp = 32; 1210 break; 1211 case S9000_ID_HCRX: /* Hyperdrive/HCRX */ 1212 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom)); 1213 if ((fb->sti->regions_phys[0] & 0xfc000000) == 1214 (fb->sti->regions_phys[2] & 0xfc000000)) 1215 sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]); 1216 else 1217 sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]); 1218 1219 fb->deviceSpecificConfig = gsc_readl(sti_rom_address); 1220 if (IS_24_DEVICE(fb)) { 1221 if (bpp_pref == 8 || bpp_pref == 32) 1222 bpp = bpp_pref; 1223 else 1224 bpp = 32; 1225 } else 1226 bpp = 8; 1227 READ_WORD(fb, REG_15); 1228 SETUP_HW(fb); 1229 break; 1230 case CRT_ID_VISUALIZE_EG: 1231 case S9000_ID_ARTIST: /* Artist */ 1232 break; 1233 default: 1234 #ifdef FALLBACK_TO_1BPP 1235 printk(KERN_WARNING 1236 "stifb: Unsupported graphics card (id=0x%08x) " 1237 "- now trying 1bpp mode instead\n", 1238 fb->id); 1239 bpp = 1; /* default to 1 bpp */ 1240 break; 1241 #else 1242 printk(KERN_WARNING 1243 "stifb: Unsupported graphics card (id=0x%08x) " 1244 "- skipping.\n", 1245 fb->id); 1246 goto out_err0; 1247 #endif 1248 } 1249 1250 1251 /* get framebuffer physical and virtual base addr & len (64bit ready) */ 1252 fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]); 1253 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096; 1254 1255 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8; 1256 if (!fix->line_length) 1257 fix->line_length = 2048; /* default */ 1258 1259 /* limit fbsize to max visible screen size */ 1260 if (fix->smem_len > yres*fix->line_length) 1261 fix->smem_len = yres*fix->line_length; 1262 1263 fix->accel = FB_ACCEL_NONE; 1264 1265 switch (bpp) { 1266 case 1: 1267 fix->type = FB_TYPE_PLANES; /* well, sort of */ 1268 fix->visual = FB_VISUAL_MONO10; 1269 var->red.length = var->green.length = var->blue.length = 1; 1270 break; 1271 case 8: 1272 fix->type = FB_TYPE_PACKED_PIXELS; 1273 fix->visual = FB_VISUAL_PSEUDOCOLOR; 1274 var->red.length = var->green.length = var->blue.length = 8; 1275 break; 1276 case 32: 1277 fix->type = FB_TYPE_PACKED_PIXELS; 1278 fix->visual = FB_VISUAL_DIRECTCOLOR; 1279 var->red.length = var->green.length = var->blue.length = var->transp.length = 8; 1280 var->blue.offset = 0; 1281 var->green.offset = 8; 1282 var->red.offset = 16; 1283 var->transp.offset = 24; 1284 break; 1285 default: 1286 break; 1287 } 1288 1289 var->xres = var->xres_virtual = xres; 1290 var->yres = var->yres_virtual = yres; 1291 var->bits_per_pixel = bpp; 1292 1293 strcpy(fix->id, "stifb"); 1294 info->fbops = &stifb_ops; 1295 info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len); 1296 info->screen_size = fix->smem_len; 1297 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA; 1298 info->pseudo_palette = &fb->pseudo_palette; 1299 1300 /* This has to be done !!! */ 1301 if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0)) 1302 goto out_err1; 1303 stifb_init_display(fb); 1304 1305 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) { 1306 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n", 1307 fix->smem_start, fix->smem_start+fix->smem_len); 1308 goto out_err2; 1309 } 1310 1311 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) { 1312 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n", 1313 fix->mmio_start, fix->mmio_start+fix->mmio_len); 1314 goto out_err3; 1315 } 1316 1317 if (register_framebuffer(&fb->info) < 0) 1318 goto out_err4; 1319 1320 sti->info = info; /* save for unregister_framebuffer() */ 1321 1322 fb_info(&fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n", 1323 fix->id, 1324 var->xres, 1325 var->yres, 1326 var->bits_per_pixel, 1327 dev_name, 1328 fb->id, 1329 fix->mmio_start); 1330 1331 return 0; 1332 1333 1334 out_err4: 1335 release_mem_region(fix->mmio_start, fix->mmio_len); 1336 out_err3: 1337 release_mem_region(fix->smem_start, fix->smem_len); 1338 out_err2: 1339 fb_dealloc_cmap(&info->cmap); 1340 out_err1: 1341 iounmap(info->screen_base); 1342 out_err0: 1343 kfree(fb); 1344 return -ENXIO; 1345 } 1346 1347 static int stifb_disabled __initdata; 1348 1349 int __init 1350 stifb_setup(char *options); 1351 1352 static int __init stifb_init(void) 1353 { 1354 struct sti_struct *sti; 1355 struct sti_struct *def_sti; 1356 int i; 1357 1358 #ifndef MODULE 1359 char *option = NULL; 1360 1361 if (fb_get_options("stifb", &option)) 1362 return -ENODEV; 1363 stifb_setup(option); 1364 #endif 1365 if (stifb_disabled) { 1366 printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n"); 1367 return -ENXIO; 1368 } 1369 1370 def_sti = sti_get_rom(0); 1371 if (def_sti) { 1372 for (i = 1; i <= MAX_STI_ROMS; i++) { 1373 sti = sti_get_rom(i); 1374 if (!sti) 1375 break; 1376 if (sti == def_sti) { 1377 stifb_init_fb(sti, stifb_bpp_pref[i - 1]); 1378 break; 1379 } 1380 } 1381 } 1382 1383 for (i = 1; i <= MAX_STI_ROMS; i++) { 1384 sti = sti_get_rom(i); 1385 if (!sti) 1386 break; 1387 if (sti == def_sti) 1388 continue; 1389 stifb_init_fb(sti, stifb_bpp_pref[i - 1]); 1390 } 1391 return 0; 1392 } 1393 1394 /* 1395 * Cleanup 1396 */ 1397 1398 static void __exit 1399 stifb_cleanup(void) 1400 { 1401 struct sti_struct *sti; 1402 int i; 1403 1404 for (i = 1; i <= MAX_STI_ROMS; i++) { 1405 sti = sti_get_rom(i); 1406 if (!sti) 1407 break; 1408 if (sti->info) { 1409 struct fb_info *info = sti->info; 1410 unregister_framebuffer(sti->info); 1411 release_mem_region(info->fix.mmio_start, info->fix.mmio_len); 1412 release_mem_region(info->fix.smem_start, info->fix.smem_len); 1413 if (info->screen_base) 1414 iounmap(info->screen_base); 1415 fb_dealloc_cmap(&info->cmap); 1416 framebuffer_release(info); 1417 } 1418 sti->info = NULL; 1419 } 1420 } 1421 1422 int __init 1423 stifb_setup(char *options) 1424 { 1425 int i; 1426 1427 if (!options || !*options) 1428 return 1; 1429 1430 if (strncmp(options, "off", 3) == 0) { 1431 stifb_disabled = 1; 1432 options += 3; 1433 } 1434 1435 if (strncmp(options, "bpp", 3) == 0) { 1436 options += 3; 1437 for (i = 0; i < MAX_STI_ROMS; i++) { 1438 if (*options++ != ':') 1439 break; 1440 stifb_bpp_pref[i] = simple_strtoul(options, &options, 10); 1441 } 1442 } 1443 return 1; 1444 } 1445 1446 __setup("stifb=", stifb_setup); 1447 1448 module_init(stifb_init); 1449 module_exit(stifb_cleanup); 1450 1451 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>"); 1452 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines"); 1453 MODULE_LICENSE("GPL v2"); 1454