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