1/* 2 * linux/drivers/video/sti/stifb.c - 3 * Frame buffer driver for HP workstations with STI (standard text interface) 4 * video firmware. 5 * 6 * Copyright (C) 2001 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 * - Artist gfx is the only supported chip atm, 43 * - remove the static fb_info to support multiple cards 44 * - remove the completely untested 1bpp mode 45 * - add support for h/w acceleration 46 * - add hardware cursor 47 * - 48 */ 49 50 51/* on supported graphic devices you may: 52 * #define FALLBACK_TO_1BPP to fall back to 1 bpp, or 53 * #undef FALLBACK_TO_1BPP to reject support for unsupported cards */ 54#undef FALLBACK_TO_1BPP 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/tty.h> 64#include <linux/slab.h> 65#include <linux/delay.h> 66#include <linux/fb.h> 67#include <linux/init.h> 68#include <linux/selection.h> 69#include <linux/ioport.h> 70#include <linux/pci.h> 71 72#include <video/fbcon.h> 73#include <video/fbcon-cfb8.h> 74#include <video/fbcon-cfb32.h> 75 76#include <asm/grfioctl.h> /* for HP-UX compatibility */ 77 78#include "sticore.h" 79 80extern struct display_switch fbcon_sti; /* fbcon-sti.c */ 81 82#ifdef __LP64__ 83/* return virtual address */ 84#define REGION_BASE(fb_info, index) \ 85 (fb_info->sti->glob_cfg->region_ptrs[index] | 0xffffffff00000000) 86#else 87/* return virtual address */ 88#define REGION_BASE(fb_info, index) \ 89 fb_info->sti->glob_cfg->region_ptrs[index] 90#endif 91 92#define NGLEDEVDEPROM_CRT_REGION 1 93 94typedef struct { 95 __s32 video_config_reg; 96 __s32 misc_video_start; 97 __s32 horiz_timing_fmt; 98 __s32 serr_timing_fmt; 99 __s32 vert_timing_fmt; 100 __s32 horiz_state; 101 __s32 vert_state; 102 __s32 vtg_state_elements; 103 __s32 pipeline_delay; 104 __s32 misc_video_end; 105} video_setup_t; 106 107typedef struct { 108 __s16 sizeof_ngle_data; 109 __s16 x_size_visible; /* visible screen dim in pixels */ 110 __s16 y_size_visible; 111 __s16 pad2[15]; 112 __s16 cursor_pipeline_delay; 113 __s16 video_interleaves; 114 __s32 pad3[11]; 115} ngle_rom_t; 116 117struct stifb_info { 118 struct fb_info info; 119 struct fb_var_screeninfo var; 120 struct fb_fix_screeninfo fix; 121 struct display disp; 122 struct sti_struct *sti; 123 unsigned int id, real_id; 124 int currcon; 125 int cmap_reload:1; 126 int deviceSpecificConfig; 127 ngle_rom_t ngle_rom; 128 struct { u8 red, green, blue; } palette[256]; 129#ifdef FBCON_HAS_CFB32 130 union { 131 u32 cfb32[16]; 132 } fbcon_cmap; 133#endif 134}; 135 136static int stifb_force_bpp[MAX_STI_ROMS] = {0, }; 137 138/* ------------------- chipset specific functions -------------------------- */ 139 140/* offsets to graphic-chip internal registers */ 141 142#define REG_1 0x000118 143#define REG_2 0x000480 144#define REG_3 0x0004a0 145#define REG_4 0x000600 146#define REG_6 0x000800 147#define REG_8 0x000820 148#define REG_9 0x000a04 149#define REG_10 0x018000 150#define REG_11 0x018004 151#define REG_12 0x01800c 152#define REG_13 0x018018 153#define REG_14 0x01801c 154#define REG_15 0x200000 155#define REG_15b0 0x200000 156#define REG_16b1 0x200005 157#define REG_16b3 0x200007 158#define REG_21 0x200218 159#define REG_22 0x0005a0 160#define REG_23 0x0005c0 161#define REG_26 0x200118 162#define REG_27 0x200308 163#define REG_32 0x21003c 164#define REG_33 0x210040 165#define REG_34 0x200008 166#define REG_35 0x018010 167#define REG_38 0x210020 168#define REG_39 0x210120 169#define REG_40 0x210130 170#define REG_42 0x210028 171#define REG_43 0x21002c 172#define REG_44 0x210030 173#define REG_45 0x210034 174 175#define READ_BYTE(fb,reg) __raw_readb((fb)->fix.mmio_start + (reg)) 176#define READ_WORD(fb,reg) __raw_readl((fb)->fix.mmio_start + (reg)) 177#define WRITE_BYTE(value,fb,reg) __raw_writeb((value),(fb)->fix.mmio_start + (reg)) 178#define WRITE_WORD(value,fb,reg) __raw_writel((value),(fb)->fix.mmio_start + (reg)) 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 186static void 187SETUP_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 199static void 200SETUP_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->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->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 236static void 237START_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 245static void 246WRITE_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 253static void 254FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) 255{ 256 WRITE_WORD(0x400, fb, REG_2); 257 if (fb->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 268static void 269SETUP_RAMDAC(struct stifb_info *fb) 270{ 271 SETUP_HW(fb); 272 WRITE_WORD(0x04000000, fb, 0x1020); 273 WRITE_WORD(0xff000000, fb, 0x1028); 274} 275 276static void 277CRX24_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 289static void 290CRX24_SET_OVLY_MASK(struct stifb_info *fb) 291{ 292 SETUP_HW(fb); 293 WRITE_WORD(0x13a02000, fb, REG_11); 294 WRITE_WORD(0x03000300, fb, REG_14); 295 WRITE_WORD(0x000017f0, fb, REG_3); 296 WRITE_WORD(0xffffffff, fb, REG_13); 297 WRITE_WORD(0xffffffff, fb, REG_22); 298 WRITE_WORD(0x00000000, fb, REG_23); 299} 300 301static void 302ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) 303{ 304 unsigned int value = enable ? 0x43000000 : 0x03000000; 305 SETUP_HW(fb); 306 WRITE_WORD(0x06000000, fb, 0x1030); 307 WRITE_WORD(value, fb, 0x1038); 308} 309 310static void 311CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) 312{ 313 unsigned int value = enable ? 0x10000000 : 0x30000000; 314 SETUP_HW(fb); 315 WRITE_WORD(0x01000000, fb, 0x1000); 316 WRITE_WORD(0x02000000, fb, 0x1004); 317 WRITE_WORD(value, fb, 0x1008); 318} 319 320static void 321ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) 322{ 323 u32 DregsMiscVideo = REG_21; 324 u32 DregsMiscCtl = REG_27; 325 326 SETUP_HW(fb); 327 if (enable) { 328 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo); 329 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl); 330 } else { 331 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo); 332 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl); 333 } 334} 335 336#define GET_ROMTABLE_INDEX(fb) \ 337 (READ_BYTE(fb, REG_16b3) - 1) 338 339#define HYPER_CONFIG_PLANES_24 0x00000100 340 341#define IS_24_DEVICE(fb) \ 342 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24) 343 344#define IS_888_DEVICE(fb) \ 345 (!(IS_24_DEVICE(fb))) 346 347#define GET_FIFO_SLOTS(fb, cnt, numslots) \ 348{ while (cnt < numslots) \ 349 cnt = READ_WORD(fb, REG_34); \ 350 cnt -= numslots; \ 351} 352 353#define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */ 354#define Otc04 2 /* Pixels in each longword transfer (4) */ 355#define Otc32 5 /* Pixels in each longword transfer (32) */ 356#define Ots08 3 /* Each pixel is size (8)d transfer (1) */ 357#define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */ 358#define AddrLong 5 /* FB address is Long aligned (pixel) */ 359#define BINovly 0x2 /* 8 bit overlay */ 360#define BINapp0I 0x0 /* Application Buffer 0, Indexed */ 361#define BINapp1I 0x1 /* Application Buffer 1, Indexed */ 362#define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */ 363#define BINattr 0xd /* Attribute Bitmap */ 364#define RopSrc 0x3 365#define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */ 366#define BitmapExtent32 5 /* Each write hits (32) bits in depth */ 367#define DataDynamic 0 /* Data register reloaded by direct access */ 368#define MaskDynamic 1 /* Mask register reloaded by direct access */ 369#define MaskOtc 0 /* Mask contains Object Count valid bits */ 370 371#define MaskAddrOffset(offset) (offset) 372#define StaticReg(en) (en) 373#define BGx(en) (en) 374#define FGx(en) (en) 375 376#define BAJustPoint(offset) (offset) 377#define BAIndexBase(base) (base) 378#define BA(F,C,S,A,J,B,I) \ 379 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I)) 380 381#define IBOvals(R,M,X,S,D,L,B,F) \ 382 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F)) 383 384#define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \ 385 WRITE_WORD(val, fb, REG_14) 386 387#define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \ 388 WRITE_WORD(val, fb, REG_11) 389 390#define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \ 391 WRITE_WORD(val, fb, REG_12) 392 393#define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \ 394 WRITE_WORD(plnmsk32, fb, REG_13) 395 396#define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \ 397 WRITE_WORD(fg32, fb, REG_35) 398 399#define NGLE_SET_TRANSFERDATA(fb, val) \ 400 WRITE_WORD(val, fb, REG_8) 401 402#define NGLE_SET_DSTXY(fb, val) \ 403 WRITE_WORD(val, fb, REG_6) 404 405#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \ 406 (u32) (fbaddrbase) + \ 407 ( (unsigned int) ( (y) << 13 ) | \ 408 (unsigned int) ( (x) << 2 ) ) \ 409 ) 410 411#define NGLE_BINC_SET_DSTADDR(fb, addr) \ 412 WRITE_WORD(addr, fb, REG_3) 413 414#define NGLE_BINC_SET_SRCADDR(fb, addr) \ 415 WRITE_WORD(addr, fb, REG_2) 416 417#define NGLE_BINC_SET_DSTMASK(fb, mask) \ 418 WRITE_WORD(mask, fb, REG_22) 419 420#define NGLE_BINC_WRITE32(fb, data32) \ 421 WRITE_WORD(data32, fb, REG_23) 422 423#define START_COLORMAPLOAD(fb, cmapBltCtlData32) \ 424 WRITE_WORD((cmapBltCtlData32), fb, REG_38) 425 426#define SET_LENXY_START_RECFILL(fb, lenxy) \ 427 WRITE_WORD(lenxy, fb, REG_9) 428 429static void 430HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) 431{ 432 u32 DregsHypMiscVideo = REG_33; 433 unsigned int value; 434 SETUP_HW(fb); 435 value = READ_WORD(fb, DregsHypMiscVideo); 436 if (enable) 437 value |= 0x0A000000; 438 else 439 value &= ~0x0A000000; 440 WRITE_WORD(value, fb, DregsHypMiscVideo); 441} 442 443 444/* BufferNumbers used by SETUP_ATTR_ACCESS() */ 445#define BUFF0_CMAP0 0x00001e02 446#define BUFF1_CMAP0 0x02001e02 447#define BUFF1_CMAP3 0x0c001e02 448#define ARTIST_CMAP0 0x00000102 449#define HYPER_CMAP8 0x00000100 450#define HYPER_CMAP24 0x00000800 451 452static void 453SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber) 454{ 455 SETUP_HW(fb); 456 WRITE_WORD(0x2EA0D000, fb, REG_11); 457 WRITE_WORD(0x23000302, fb, REG_14); 458 WRITE_WORD(BufferNumber, fb, REG_12); 459 WRITE_WORD(0xffffffff, fb, REG_8); 460} 461 462static void 463SET_ATTR_SIZE(struct stifb_info *fb, int width, int height) 464{ 465 WRITE_WORD(0x00000000, fb, REG_6); 466 WRITE_WORD((width<<16) | height, fb, REG_9); 467 WRITE_WORD(0x05000000, fb, REG_6); 468 WRITE_WORD(0x00040001, fb, REG_9); 469} 470 471static void 472FINISH_ATTR_ACCESS(struct stifb_info *fb) 473{ 474 SETUP_HW(fb); 475 WRITE_WORD(0x00000000, fb, REG_12); 476} 477 478static void 479elkSetupPlanes(struct stifb_info *fb) 480{ 481 SETUP_RAMDAC(fb); 482 SETUP_FB(fb); 483} 484 485static void 486ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber) 487{ 488 SETUP_ATTR_ACCESS(fb, BufferNumber); 489 SET_ATTR_SIZE(fb, fb->var.xres, fb->var.yres); 490 FINISH_ATTR_ACCESS(fb); 491 SETUP_FB(fb); 492} 493 494 495static void 496rattlerSetupPlanes(struct stifb_info *fb) 497{ 498 CRX24_SETUP_RAMDAC(fb); 499 500 /* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */ 501 WRITE_WORD(0x83000300, fb, REG_14); 502 SETUP_HW(fb); 503 WRITE_BYTE(1, fb, REG_16b1); 504 505 memset_io(fb->fix.smem_start, 0xff, 506 fb->var.yres*fb->fix.line_length); 507 508 CRX24_SET_OVLY_MASK(fb); 509 SETUP_FB(fb); 510} 511 512 513#define HYPER_CMAP_TYPE 0 514#define NGLE_CMAP_INDEXED0_TYPE 0 515#define NGLE_CMAP_OVERLAY_TYPE 3 516 517/* typedef of LUT (Colormap) BLT Control Register */ 518typedef union /* Note assumption that fields are packed left-to-right */ 519{ u32 all; 520 struct 521 { 522 unsigned enable : 1; 523 unsigned waitBlank : 1; 524 unsigned reserved1 : 4; 525 unsigned lutOffset : 10; /* Within destination LUT */ 526 unsigned lutType : 2; /* Cursor, image, overlay */ 527 unsigned reserved2 : 4; 528 unsigned length : 10; 529 } fields; 530} NgleLutBltCtl; 531 532 533 534static NgleLutBltCtl 535setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) 536{ 537 NgleLutBltCtl lutBltCtl; 538 539 /* set enable, zero reserved fields */ 540 lutBltCtl.all = 0x80000000; 541 542 lutBltCtl.fields.length = length; 543 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE; 544 545 /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */ 546 if (fb->var.bits_per_pixel == 8) 547 lutBltCtl.fields.lutOffset = 2 * 256; 548 else 549 lutBltCtl.fields.lutOffset = 0 * 256; 550 551 /* Offset points to start of LUT. Adjust for within LUT */ 552 lutBltCtl.fields.lutOffset += offsetWithinLut; 553 554 return lutBltCtl; 555} 556 557 558static void hyperUndoITE(struct stifb_info *fb) 559{ 560 int nFreeFifoSlots = 0; 561 u32 fbAddr; 562 563 NGLE_LOCK(fb); 564 565 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1); 566 WRITE_WORD(0xffffffff, fb, REG_32); 567 568 /* Write overlay transparency mask so only entry 255 is transparent */ 569 570 /* Hardware setup for full-depth write to "magic" location */ 571 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7); 572 NGLE_QUICK_SET_DST_BM_ACCESS(fb, 573 BA(IndexedDcd, Otc04, Ots08, AddrLong, 574 BAJustPoint(0), BINovly, BAIndexBase(0))); 575 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, 576 IBOvals(RopSrc, MaskAddrOffset(0), 577 BitmapExtent08, StaticReg(0), 578 DataDynamic, MaskOtc, BGx(0), FGx(0))); 579 580 /* Now prepare to write to the "magic" location */ 581 fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0); 582 NGLE_BINC_SET_DSTADDR(fb, fbAddr); 583 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff); 584 NGLE_BINC_SET_DSTMASK(fb, 0xffffffff); 585 586 /* Finally, write a zero to clear the mask */ 587 NGLE_BINC_WRITE32(fb, 0); 588 589 NGLE_UNLOCK(fb); 590} 591 592static void 593ngleDepth8_ClearImagePlanes(struct stifb_info *fb) 594{ 595} 596 597static void 598ngleDepth24_ClearImagePlanes(struct stifb_info *fb) 599{ 600} 601 602static void 603ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg) 604{ 605 int nFreeFifoSlots = 0; 606 u32 packed_dst; 607 u32 packed_len; 608 609 NGLE_LOCK(fb); 610 611 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4); 612 NGLE_QUICK_SET_DST_BM_ACCESS(fb, 613 BA(IndexedDcd, Otc32, OtsIndirect, 614 AddrLong, BAJustPoint(0), 615 BINattr, BAIndexBase(0))); 616 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg); 617 NGLE_SET_TRANSFERDATA(fb, 0xffffffff); 618 619 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, 620 IBOvals(RopSrc, MaskAddrOffset(0), 621 BitmapExtent08, StaticReg(1), 622 DataDynamic, MaskOtc, 623 BGx(0), FGx(0))); 624 packed_dst = 0; 625 packed_len = (fb->var.xres << 16) | fb->var.yres; 626 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2); 627 NGLE_SET_DSTXY(fb, packed_dst); 628 SET_LENXY_START_RECFILL(fb, packed_len); 629 630 /* 631 * In order to work around an ELK hardware problem (Buffy doesn't 632 * always flush it's buffers when writing to the attribute 633 * planes), at least 4 pixels must be written to the attribute 634 * planes starting at (X == 1280) and (Y != to the last Y written 635 * by BIF): 636 */ 637 638 if (fb->id == S9000_ID_A1659A) { /* ELK_DEVICE_ID */ 639 /* It's safe to use scanline zero: */ 640 packed_dst = (1280 << 16); 641 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2); 642 NGLE_SET_DSTXY(fb, packed_dst); 643 packed_len = (4 << 16) | 1; 644 SET_LENXY_START_RECFILL(fb, packed_len); 645 } /* ELK Hardware Kludge */ 646 647 /**** Finally, set the Control Plane Register back to zero: ****/ 648 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1); 649 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0); 650 651 NGLE_UNLOCK(fb); 652} 653 654static void 655ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data) 656{ 657 int nFreeFifoSlots = 0; 658 u32 packed_dst; 659 u32 packed_len; 660 661 NGLE_LOCK(fb); 662 663 /* Hardware setup */ 664 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8); 665 NGLE_QUICK_SET_DST_BM_ACCESS(fb, 666 BA(IndexedDcd, Otc04, Ots08, AddrLong, 667 BAJustPoint(0), BINovly, BAIndexBase(0))); 668 669 NGLE_SET_TRANSFERDATA(fb, 0xffffffff); /* Write foreground color */ 670 671 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data); 672 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask); 673 674 packed_dst = 0; 675 packed_len = (fb->var.xres << 16) | fb->var.yres; 676 NGLE_SET_DSTXY(fb, packed_dst); 677 678 /* Write zeroes to overlay planes */ 679 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, 680 IBOvals(RopSrc, MaskAddrOffset(0), 681 BitmapExtent08, StaticReg(0), 682 DataDynamic, MaskOtc, BGx(0), FGx(0))); 683 684 SET_LENXY_START_RECFILL(fb, packed_len); 685 686 NGLE_UNLOCK(fb); 687} 688 689static void 690hyperResetPlanes(struct stifb_info *fb, int enable) 691{ 692 unsigned int controlPlaneReg; 693 694 NGLE_LOCK(fb); 695 696 if (IS_24_DEVICE(fb)) 697 if (fb->var.bits_per_pixel == 32) 698 controlPlaneReg = 0x04000F00; 699 else 700 controlPlaneReg = 0x00000F00; /* 0x00000800 should be enought, but lets clear all 4 bits */ 701 else 702 controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */ 703 704 switch (enable) { 705 case 1: /* ENABLE */ 706 /* clear screen */ 707 if (IS_24_DEVICE(fb)) 708 ngleDepth24_ClearImagePlanes(fb); 709 else 710 ngleDepth8_ClearImagePlanes(fb); 711 712 /* Paint attribute planes for default case. 713 * On Hyperdrive, this means all windows using overlay cmap 0. */ 714 ngleResetAttrPlanes(fb, controlPlaneReg); 715 716 /* clear overlay planes */ 717 ngleClearOverlayPlanes(fb, 0xff, 255); 718 719 /************************************************** 720 ** Also need to counteract ITE settings 721 **************************************************/ 722 hyperUndoITE(fb); 723 break; 724 725 case 0: /* DISABLE */ 726 /* clear screen */ 727 if (IS_24_DEVICE(fb)) 728 ngleDepth24_ClearImagePlanes(fb); 729 else 730 ngleDepth8_ClearImagePlanes(fb); 731 ngleResetAttrPlanes(fb, controlPlaneReg); 732 ngleClearOverlayPlanes(fb, 0xff, 0); 733 break; 734 735 case -1: /* RESET */ 736 hyperUndoITE(fb); 737 ngleResetAttrPlanes(fb, controlPlaneReg); 738 break; 739 } 740 741 NGLE_UNLOCK(fb); 742} 743 744/* Return pointer to in-memory structure holding ELK device-dependent ROM values. */ 745 746static void 747ngleGetDeviceRomData(struct stifb_info *fb) 748{ 749} 750 751 752#define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4 753#define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8 754#define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10 755#define HYPERBOWL_MODE2_8_24 15 756 757/* HCRX specific boot-time initialization */ 758static void __init 759SETUP_HCRX(struct stifb_info *fb) 760{ 761 int hyperbowl; 762 int nFreeFifoSlots = 0; 763 764 if (fb->id != S9000_ID_HCRX) 765 return; 766 767 /* Initialize Hyperbowl registers */ 768 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7); 769 770 if (IS_24_DEVICE(fb)) { 771 hyperbowl = (fb->var.bits_per_pixel == 32) ? 772 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE : 773 HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE; 774 775 /* First write to Hyperbowl must happen twice (bug) */ 776 WRITE_WORD(hyperbowl, fb, REG_40); 777 WRITE_WORD(hyperbowl, fb, REG_40); 778 779 WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39); 780 781 WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */ 782 WRITE_WORD(0x404c4048, fb, REG_43); 783 WRITE_WORD(0x034c0348, fb, REG_44); 784 WRITE_WORD(0x444c4448, fb, REG_45); 785 } else { 786 hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES; 787 788 /* First write to Hyperbowl must happen twice (bug) */ 789 WRITE_WORD(hyperbowl, fb, REG_40); 790 WRITE_WORD(hyperbowl, fb, REG_40); 791 792 WRITE_WORD(0x00000000, fb, REG_42); 793 WRITE_WORD(0x00000000, fb, REG_43); 794 WRITE_WORD(0x00000000, fb, REG_44); 795 WRITE_WORD(0x444c4048, fb, REG_45); 796 } 797} 798 799 800/* ------------------- driver specific functions --------------------------- */ 801 802static int 803stifb_getcolreg(u_int regno, u_int *red, u_int *green, 804 u_int *blue, u_int *transp, struct fb_info *info) 805{ 806 struct stifb_info *fb = (struct stifb_info *) info; 807 808 if (regno > 255) 809 return 1; 810 *red = (fb->palette[regno].red<<8) | fb->palette[regno].red; 811 *green = (fb->palette[regno].green<<8) | fb->palette[regno].green; 812 *blue = (fb->palette[regno].blue<<8) | fb->palette[regno].blue; 813 *transp = 0; 814 815 return 0; 816} 817 818static int 819stifb_setcolreg(u_int regno, u_int red, u_int green, 820 u_int blue, u_int transp, struct fb_info *info) 821{ 822 struct stifb_info *fb = (struct stifb_info *) info; 823 824 if (regno > 255) 825 return 1; 826 827 red >>= 8; 828 green >>= 8; 829 blue >>= 8; 830 831 if ((fb->palette[regno].red != red) || 832 (fb->palette[regno].green != green) || 833 (fb->palette[regno].blue != blue)) 834 fb->cmap_reload = 1; 835 836 fb->palette[regno].red = red; 837 fb->palette[regno].green = green; 838 fb->palette[regno].blue = blue; 839 840#ifdef FBCON_HAS_CFB32 841 if (regno < 16 && fb->var.bits_per_pixel == 32) { 842 fb->fbcon_cmap.cfb32[regno] = ((red << 16) | 843 (green << 8) | 844 (blue << 0) | 845 (transp << 24)); 846 } 847#endif 848 return 0; 849} 850 851static void 852stifb_loadcmap(struct stifb_info *fb) 853{ 854 u32 color; 855 int i; 856 857 if (!fb->cmap_reload) 858 return; 859 860 START_IMAGE_COLORMAP_ACCESS(fb); 861 for (i = 0; i < 256; i++) { 862 if (fb->var.bits_per_pixel > 8) { 863 color = (i << 16) | (i << 8) | i; 864 } else { 865 if (fb->var.grayscale) { 866 /* gray = 0.30*R + 0.59*G + 0.11*B */ 867 color = ((fb->palette[i].red * 77) + 868 (fb->palette[i].green * 151) + 869 (fb->palette[i].blue * 28)) >> 8; 870 } else { 871 color = ((fb->palette[i].red << 16) | 872 (fb->palette[i].green << 8) | 873 (fb->palette[i].blue)); 874 } 875 } 876 WRITE_IMAGE_COLOR(fb, i, color); 877 } 878 if (fb->id == S9000_ID_HCRX) { 879 NgleLutBltCtl lutBltCtl; 880 881 lutBltCtl = setHyperLutBltCtl(fb, 882 0, /* Offset w/i LUT */ 883 256); /* Load entire LUT */ 884 NGLE_BINC_SET_SRCADDR(fb, 885 NGLE_LONG_FB_ADDRESS(0, 0x100, 0)); 886 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */ 887 START_COLORMAPLOAD(fb, lutBltCtl.all); 888 SETUP_FB(fb); 889 } else { 890 /* cleanup colormap hardware */ 891 FINISH_IMAGE_COLORMAP_ACCESS(fb); 892 } 893 fb->cmap_reload = 0; 894} 895 896static int 897stifb_get_fix(struct fb_fix_screeninfo *fix, int con, 898 struct fb_info *info) 899{ 900 memcpy (fix, &((struct stifb_info *)info)->fix, sizeof (*fix)); 901 return 0; 902} 903 904static int 905stifb_get_var(struct fb_var_screeninfo *var, int con, 906 struct fb_info *info) 907{ 908 memcpy (var, &((struct stifb_info *)info)->var, sizeof (*var)); 909 return 0; 910} 911 912static int 913stifb_set_var(struct fb_var_screeninfo *var, int con, 914 struct fb_info *info) 915{ 916 struct display *disp; 917 918 if (con >= 0) 919 disp = &fb_display[con]; 920 else 921 disp = info->disp; 922 923 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { 924 if (disp->var.xres != var->xres || 925 disp->var.yres != var->yres || 926 disp->var.xres_virtual != var->xres_virtual || 927 disp->var.yres_virtual != var->yres_virtual || 928 disp->var.bits_per_pixel != var->bits_per_pixel || 929 disp->var.accel_flags != var->accel_flags) 930 return -EINVAL; 931 } 932 return 0; 933} 934 935static int 936stifb_get_cmap(struct fb_cmap *cmap, int kspc, int con, 937 struct fb_info *info) 938{ 939 struct stifb_info *fb = (struct stifb_info *)info; 940 941 if (con == fb->currcon) /* current console ? */ 942 return fb_get_cmap(cmap, kspc, stifb_getcolreg, info); 943 else if (fb_display[con].cmap.len) /* non default colormap ? */ 944 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); 945 else 946 fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel > 8 ? 16 : 256), cmap, kspc ? 0: 2); 947 return 0; 948} 949 950static int 951stifb_set_cmap(struct fb_cmap *cmap, int kspc, int con, 952 struct fb_info *info) 953{ 954 struct stifb_info *fb = (struct stifb_info *)info; 955 struct display *disp; 956 int err; 957 958 if (con >= 0) 959 disp = &fb_display[con]; 960 else 961 disp = info->disp; 962 963 if (!disp->cmap.len) { /* no colormap allocated ? */ 964 if ((err = fb_alloc_cmap(&disp->cmap, disp->var.bits_per_pixel > 8 ? 16 : 256, 0))) 965 return err; 966 } 967 if (con == fb->currcon || con == -1) { 968 err = fb_set_cmap(cmap, kspc, stifb_setcolreg, info); 969 if (!err) 970 stifb_loadcmap ((struct stifb_info *)info); 971 return err; 972 } else 973 fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); 974 return 0; 975} 976 977static void 978stifb_blank(int blank_mode, struct fb_info *info) 979{ 980 struct stifb_info *fb = (struct stifb_info *) info; 981 int enable = (blank_mode == 0) ? ENABLE : DISABLE; 982 983 switch (fb->id) { 984 case S9000_ID_A1439A: 985 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable); 986 break; 987 case CRT_ID_VISUALIZE_EG: 988 case S9000_ID_ARTIST: 989 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable); 990 break; 991 case S9000_ID_HCRX: 992 HYPER_ENABLE_DISABLE_DISPLAY(fb, enable); 993 break; 994 case S9000_ID_A1659A:; /* fall through */ 995 case S9000_ID_TIMBER:; 996 case CRX24_OVERLAY_PLANES:; 997 default: 998 ENABLE_DISABLE_DISPLAY(fb, enable); 999 break; 1000 } 1001 1002 SETUP_FB(fb); 1003} 1004 1005static void 1006stifb_set_disp(struct stifb_info *fb) 1007{ 1008 int id = fb->id; 1009 1010 SETUP_FB(fb); 1011 1012 /* HCRX specific initialization */ 1013 SETUP_HCRX(fb); 1014 1015 /* 1016 if (id == S9000_ID_HCRX) 1017 hyperInitSprite(fb); 1018 else 1019 ngleInitSprite(fb); 1020 */ 1021 1022 /* Initialize the image planes. */ 1023 switch (id) { 1024 case S9000_ID_HCRX: 1025 hyperResetPlanes(fb, ENABLE); 1026 break; 1027 case S9000_ID_A1439A: 1028 rattlerSetupPlanes(fb); 1029 break; 1030 case S9000_ID_A1659A: 1031 case S9000_ID_ARTIST: 1032 case CRT_ID_VISUALIZE_EG: 1033 elkSetupPlanes(fb); 1034 break; 1035 } 1036 1037 /* Clear attribute planes on non HCRX devices. */ 1038 switch (id) { 1039 case S9000_ID_A1659A: 1040 case S9000_ID_A1439A: 1041 if (fb->var.bits_per_pixel == 32) 1042 ngleSetupAttrPlanes(fb, BUFF1_CMAP3); 1043 else { 1044 ngleSetupAttrPlanes(fb, BUFF1_CMAP0); 1045 } 1046 if (id == S9000_ID_A1439A) 1047 ngleClearOverlayPlanes(fb, 0xff, 0); 1048 break; 1049 case S9000_ID_ARTIST: 1050 case CRT_ID_VISUALIZE_EG: 1051 if (fb->var.bits_per_pixel == 32) 1052 ngleSetupAttrPlanes(fb, BUFF1_CMAP3); 1053 else { 1054 ngleSetupAttrPlanes(fb, ARTIST_CMAP0); 1055 } 1056 break; 1057 } 1058 stifb_blank(0, (struct fb_info *)fb); /* 0=enable screen */ 1059 1060 SETUP_FB(fb); 1061} 1062 1063static int 1064stifb_switch(int con, struct fb_info *info) 1065{ 1066 struct stifb_info *fb = (struct stifb_info *)info; 1067 1068 /* Do we have to save the colormap ? */ 1069 if (fb->currcon != -1 && fb_display[fb->currcon].cmap.len) 1070 fb_get_cmap(&fb_display[fb->currcon].cmap, 1, stifb_getcolreg, info); 1071 1072 fb->currcon = con; 1073 /* Install new colormap */ 1074 if (fb_display[con].cmap.len) 1075 fb_set_cmap(&fb_display[con].cmap, 1, stifb_setcolreg, info); 1076 else 1077 fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel > 8 ? 16 : 256), 1078 1, stifb_setcolreg, info); 1079 stifb_loadcmap ((struct stifb_info *)info); 1080 return 0; 1081} 1082 1083static int 1084stifb_update_var(int con, struct fb_info *info) 1085{ 1086 return 0; 1087} 1088 1089/* ------------ Interfaces to hardware functions ------------ */ 1090 1091static struct fb_ops stifb_ops = { 1092 owner: THIS_MODULE, 1093 fb_get_fix: stifb_get_fix, 1094 fb_get_var: stifb_get_var, 1095 fb_set_var: stifb_set_var, 1096 fb_get_cmap: stifb_get_cmap, 1097 fb_set_cmap: stifb_set_cmap, 1098// fb_pan_display: fbgen_pan_display, 1099// fb_ioctl: xxxfb_ioctl, /* optional */ 1100}; 1101 1102 1103 /* 1104 * Initialization 1105 */ 1106 1107int __init 1108stifb_init_fb(struct sti_struct *sti, int force_bpp) 1109{ 1110 struct fb_fix_screeninfo *fix; 1111 struct fb_var_screeninfo *var; 1112 struct display *disp; 1113 struct stifb_info *fb; 1114 unsigned long sti_rom_address; 1115 char *dev_name; 1116 int bpp, xres, yres; 1117 1118 fb = kmalloc(sizeof(struct stifb_info), GFP_ATOMIC); 1119 if (!fb) { 1120 printk(KERN_ERR "stifb: Could not allocate stifb structure\n"); 1121 return -ENODEV; 1122 } 1123 1124 /* set struct to a known state */ 1125 memset(fb, 0, sizeof(struct stifb_info)); 1126 fix = &fb->fix; 1127 var = &fb->var; 1128 disp = &fb->disp; 1129 1130 fb->currcon = -1; 1131 fb->cmap_reload = 1; 1132 fb->sti = sti; 1133 /* store upper 32bits of the graphics id */ 1134 fb->id = fb->sti->graphics_id[0]; 1135 fb->real_id = fb->id; /* save the real id */ 1136 1137 /* only supported cards are allowed */ 1138 switch (fb->id) { 1139 case S9000_ID_ARTIST: 1140 case S9000_ID_HCRX: 1141 case S9000_ID_TIMBER: 1142 case S9000_ID_A1659A: 1143 case S9000_ID_A1439A: 1144 case CRT_ID_VISUALIZE_EG: 1145 break; 1146 default: 1147 printk(KERN_WARNING "stifb: Unsupported gfx card id 0x%08x\n", 1148 fb->id); 1149 goto out_err1; 1150 } 1151 1152 /* default to 8 bpp on most graphic chips */ 1153 bpp = 8; 1154 xres = sti_onscreen_x(fb->sti); 1155 yres = sti_onscreen_y(fb->sti); 1156 1157 ngleGetDeviceRomData(fb); 1158 1159 /* get (virtual) io region base addr */ 1160 fix->mmio_start = REGION_BASE(fb,2); 1161 fix->mmio_len = 0x400000; 1162 1163 /* Reject any device not in the NGLE family */ 1164 switch (fb->id) { 1165 case S9000_ID_A1659A: /* CRX/A1659A */ 1166 break; 1167 case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */ 1168 var->grayscale = 1; 1169 fb->id = S9000_ID_A1659A; 1170 break; 1171 case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */ 1172 dev_name = fb->sti->outptr.dev_name; 1173 if (strstr(dev_name, "GRAYSCALE") || 1174 strstr(dev_name, "Grayscale") || 1175 strstr(dev_name, "grayscale")) 1176 var->grayscale = 1; 1177 break; 1178 case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */ 1179 xres = fb->ngle_rom.x_size_visible; 1180 yres = fb->ngle_rom.y_size_visible; 1181 fb->id = S9000_ID_A1659A; 1182 break; 1183 case S9000_ID_A1439A: /* CRX24/A1439A */ 1184 bpp = 32; 1185 break; 1186 case S9000_ID_HCRX: /* Hyperdrive/HCRX */ 1187 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom)); 1188 if ((fb->sti->regions_phys[0] & 0xfc000000) == 1189 (fb->sti->regions_phys[2] & 0xfc000000)) 1190 sti_rom_address = fb->sti->regions_phys[0]; 1191 else 1192 sti_rom_address = fb->sti->regions_phys[1]; 1193#ifdef __LP64__ 1194 sti_rom_address |= 0xffffffff00000000; 1195#endif 1196 fb->deviceSpecificConfig = __raw_readl(sti_rom_address); 1197 if (IS_24_DEVICE(fb)) { 1198 if (force_bpp == 8 || force_bpp == 32) 1199 bpp = force_bpp; 1200 else 1201 bpp = 32; 1202 } else 1203 bpp = 8; 1204 READ_WORD(fb, REG_15); 1205 SETUP_HW(fb); 1206 break; 1207 case CRT_ID_VISUALIZE_EG: 1208 case S9000_ID_ARTIST: /* Artist */ 1209 break; 1210 default: 1211#ifdef FALLBACK_TO_1BPP 1212 printk(KERN_WARNING 1213 "stifb: Unsupported graphics card (id=0x%08x) " 1214 "- now trying 1bpp mode instead\n", 1215 fb->id); 1216 bpp = 1; /* default to 1 bpp */ 1217 break; 1218#else 1219 printk(KERN_WARNING 1220 "stifb: Unsupported graphics card (id=0x%08x) " 1221 "- skipping.\n", 1222 fb->id); 1223 goto out_err1; 1224#endif 1225 } 1226 1227 1228 /* get framebuffer pysical and virtual base addr & len (64bit ready) */ 1229 fix->smem_start = fb->sti->regions_phys[1] | 0xffffffff00000000; 1230 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096; 1231 1232 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8; 1233 if (!fix->line_length) 1234 fix->line_length = 2048; /* default */ 1235 fix->accel = FB_ACCEL_NONE; 1236 1237 switch (bpp) { 1238 case 1: 1239 fix->type = FB_TYPE_PLANES; /* well, sort of */ 1240 fix->visual = FB_VISUAL_MONO10; 1241 disp->dispsw = &fbcon_sti; 1242 break; 1243#ifdef FBCON_HAS_CFB8 1244 case 8: 1245 fix->type = FB_TYPE_PACKED_PIXELS; 1246 fix->visual = FB_VISUAL_PSEUDOCOLOR; 1247 disp->dispsw = &fbcon_cfb8; 1248 var->red.length = var->green.length = var->blue.length = 8; 1249 break; 1250#endif 1251#ifdef FBCON_HAS_CFB32 1252 case 32: 1253 fix->type = FB_TYPE_PACKED_PIXELS; 1254 fix->visual = FB_VISUAL_TRUECOLOR; 1255 disp->dispsw = &fbcon_cfb32; 1256 disp->dispsw_data = fb->fbcon_cmap.cfb32; 1257 var->red.length = var->green.length = var->blue.length = var->transp.length = 8; 1258 var->blue.offset = 0; 1259 var->green.offset = 8; 1260 var->red.offset = 16; 1261 var->transp.offset = 24; 1262 break; 1263#endif 1264 default: 1265 disp->dispsw = &fbcon_dummy; 1266 break; 1267 } 1268 1269 var->xres = var->xres_virtual = xres; 1270 var->yres = var->yres_virtual = yres; 1271 var->bits_per_pixel = bpp; 1272 1273 disp->var = *var; 1274 disp->visual = fix->visual; 1275 disp->type = fix->type; 1276 disp->type_aux = fix->type_aux; 1277 disp->line_length = fix->line_length; 1278 disp->var.activate = FB_ACTIVATE_NOW; 1279 disp->screen_base = (void*) REGION_BASE(fb,1); 1280 disp->can_soft_blank = 1; 1281 disp->scrollmode = SCROLL_YREDRAW; 1282 1283 strcpy(fb->info.modename, "stifb"); 1284 fb->info.node = -1; 1285 fb->info.flags = FBINFO_FLAG_DEFAULT; 1286 fb->info.fbops = &stifb_ops; 1287 fb->info.disp = disp; 1288 fb->info.changevar = NULL; 1289 fb->info.switch_con = &stifb_switch; 1290 fb->info.updatevar = &stifb_update_var; 1291 fb->info.blank = &stifb_blank; 1292 fb->info.flags = FBINFO_FLAG_DEFAULT; 1293 1294 stifb_set_var(&disp->var, 1, &fb->info); 1295 1296 stifb_set_disp(fb); 1297 1298 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb")) { 1299 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n", 1300 fix->smem_start, fix->smem_start+fix->smem_len); 1301 goto out_err1; 1302 } 1303 1304 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) { 1305 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n", 1306 fix->mmio_start, fix->mmio_start+fix->mmio_len); 1307 goto out_err2; 1308 } 1309 1310 if (register_framebuffer(&fb->info) < 0) 1311 goto out_err3; 1312 1313 printk(KERN_INFO 1314 "fb%d: %s %dx%d-%d frame buffer device, id: %04x, mmio: 0x%04lx\n", 1315 GET_FB_IDX(fb->info.node), 1316 fb->info.modename, 1317 disp->var.xres, 1318 disp->var.yres, 1319 disp->var.bits_per_pixel, 1320 fb->id, 1321 fix->mmio_start); 1322 1323 return 0; 1324 1325 1326out_err3: 1327 release_mem_region(fix->mmio_start, fix->mmio_len); 1328out_err2: 1329 release_mem_region(fix->smem_start, fix->smem_len); 1330out_err1: 1331 kfree(fb); 1332 return -ENXIO; 1333} 1334 1335int __init 1336stifb_init(void) 1337{ 1338 struct sti_struct *sti; 1339 int i; 1340 1341 1342 if (sti_init_roms() == NULL) 1343 return -ENXIO; /* no STI cards available */ 1344 1345 for (i = 0; i < MAX_STI_ROMS; i++) { 1346 sti = sti_get_rom(i); 1347 if (sti) 1348 stifb_init_fb (sti, stifb_force_bpp[i]); 1349 else 1350 break; 1351 } 1352 return 0; 1353} 1354 1355/* 1356 * Cleanup 1357 */ 1358 1359void __exit 1360stifb_cleanup(struct fb_info *info) 1361{ 1362 // unregister_framebuffer(info); 1363} 1364 1365int __init 1366stifb_setup(char *options) 1367{ 1368 int i; 1369 1370 if (!options || !*options) 1371 return 0; 1372 1373 if (strncmp(options, "bpp", 3) == 0) { 1374 options += 3; 1375 for (i = 0; i < MAX_STI_ROMS; i++) { 1376 if (*options++ == ':') 1377 stifb_force_bpp[i] = simple_strtoul(options, &options, 10); 1378 else 1379 break; 1380 } 1381 } 1382 return 0; 1383} 1384 1385__setup("stifb=", stifb_setup); 1386 1387#ifdef MODULE 1388module_init(stifb_init); 1389#endif 1390module_exit(stifb_cleanup); 1391 1392MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>"); 1393MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines"); 1394MODULE_LICENSE("GPL"); 1395 1396MODULE_PARM(bpp, "i"); 1397MODULE_PARM_DESC(mem, "Bits per pixel (default: 8)"); 1398 1399