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