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