1532 lines · c
1/*2 * linux/drivers/video/stifb.c -3 * Low level Frame buffer driver for HP workstations with4 * 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 driver11 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>12 * - based on skeletonfb, which was13 * Created 28 Dec 1997 by Geert Uytterhoeven14 * - HP Xhp cfb-based X11 window driver for XFree8615 * (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 planes21 * HPA4071A known as "HCRX24", a 1280x1024 color device with 24 planes,22 * optionally available with a hardware accelerator as HPA4071A_Z23 * HPA1659A known as "CRX", a 1280x1024 color device with 8 planes24 * 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 planes27 * 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 only32 * HP710L same as HP710C, 1024x768 color only33 * 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 Public37 * License. See the file COPYING in the main directory of this archive38 * for more details.39 */40 41/* TODO:42 * - 1bpp mode is completely untested43 * - add support for h/w acceleration44 * - add hardware cursor45 * - 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, or51 * #undef FALLBACK_TO_1BPP to reject support for unsupported cards */52#undef FALLBACK_TO_1BPP53 54#undef DEBUG_STIFB_REGS /* debug sti register accesses */55 56 57#include <linux/module.h>58#include <linux/kernel.h>59#include <linux/errno.h>60#include <linux/string.h>61#include <linux/mm.h>62#include <linux/slab.h>63#include <linux/delay.h>64#include <linux/fb.h>65#include <linux/init.h>66#include <linux/ioport.h>67#include <linux/io.h>68 69#include <asm/grfioctl.h> /* for HP-UX compatibility */70#include <linux/uaccess.h>71 72#include <video/sticore.h>73 74/* REGION_BASE(fb_info, index) returns the physical address for region <index> */75#define REGION_BASE(fb_info, index) \76 F_EXTEND(fb_info->sti->regions_phys[index])77 78#define NGLEDEVDEPROM_CRT_REGION 179 80#define NR_PALETTE 25681 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 0x000118121#define REG_2 0x000480122#define REG_3 0x0004a0123#define REG_4 0x000600124#define REG_6 0x000800125#define REG_7 0x000804126#define REG_8 0x000820127#define REG_9 0x000a04128#define REG_10 0x018000129#define REG_11 0x018004130#define REG_12 0x01800c131#define REG_13 0x018018132#define REG_14 0x01801c133#define REG_15 0x200000134#define REG_15b0 0x200000135#define REG_16b1 0x200005136#define REG_16b3 0x200007137#define REG_21 0x200218138#define REG_22 0x0005a0139#define REG_23 0x0005c0140#define REG_24 0x000808141#define REG_25 0x000b00142#define REG_26 0x200118143#define REG_27 0x200308144#define REG_32 0x21003c145#define REG_33 0x210040146#define REG_34 0x200008147#define REG_35 0x018010148#define REG_38 0x210020149#define REG_39 0x210120150#define REG_40 0x210130151#define REG_42 0x210028152#define REG_43 0x21002c153#define REG_44 0x210030154#define REG_45 0x210034155 156#define READ_BYTE(fb, reg) gsc_readb((fb)->info->fix.mmio_start + (reg))157#define READ_WORD(fb, reg) gsc_readl((fb)->info->fix.mmio_start + (reg))158 159 160#ifndef DEBUG_STIFB_REGS161# define DEBUG_OFF()162# define DEBUG_ON()163# define WRITE_BYTE(value, fb, reg) gsc_writeb((value), (fb)->info->fix.mmio_start + (reg))164# define WRITE_WORD(value, fb, reg) gsc_writel((value), (fb)->info->fix.mmio_start + (reg))165#else166 static int debug_on = 1;167# define DEBUG_OFF() debug_on=0168# define DEBUG_ON() debug_on=1169# define WRITE_BYTE(value,fb,reg) do { if (debug_on) \170 printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \171 __func__, reg, value, READ_BYTE(fb,reg)); \172 gsc_writeb((value), (fb)->info->fix.mmio_start + (reg)); } while (0)173# define WRITE_WORD(value,fb,reg) do { if (debug_on) \174 printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \175 __func__, reg, value, READ_WORD(fb,reg)); \176 gsc_writel((value), (fb)->info->fix.mmio_start + (reg)); } while (0)177#endif /* DEBUG_STIFB_REGS */178 179 180#define ENABLE 1 /* for enabling/disabling screen */181#define DISABLE 0182 183#define NGLE_LOCK(fb_info) do { } while (0)184#define NGLE_UNLOCK(fb_info) do { } while (0)185 186static void187SETUP_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 void200SETUP_FB(struct stifb_info *fb)201{202 unsigned int reg10_value = 0;203 204 SETUP_HW(fb);205 switch (fb->id)206 {207 case CRT_ID_VISUALIZE_EG:208 case S9000_ID_ARTIST:209 case S9000_ID_A1659A:210 reg10_value = 0x13601000;211 break;212 case S9000_ID_A1439A:213 if (fb->info->var.bits_per_pixel == 32)214 reg10_value = 0xBBA0A000;215 else216 reg10_value = 0x13601000;217 break;218 case S9000_ID_HCRX:219 if (fb->info->var.bits_per_pixel == 32)220 reg10_value = 0xBBA0A000;221 else222 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 void237START_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 void246WRITE_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 void254FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)255{256 WRITE_WORD(0x400, fb, REG_2);257 if (fb->info->var.bits_per_pixel == 32) {258 WRITE_WORD(0x83000100, fb, REG_1);259 } else {260 if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)261 WRITE_WORD(0x80000100, fb, REG_26);262 else263 WRITE_WORD(0x80000100, fb, REG_1);264 }265 SETUP_FB(fb);266}267 268static void269SETUP_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 void277CRX24_SETUP_RAMDAC(struct stifb_info *fb)278{279 SETUP_HW(fb);280 WRITE_WORD(0x04000000, fb, 0x1000);281 WRITE_WORD(0x02000000, fb, 0x1004);282 WRITE_WORD(0xff000000, fb, 0x1008);283 WRITE_WORD(0x05000000, fb, 0x1000);284 WRITE_WORD(0x02000000, fb, 0x1004);285 WRITE_WORD(0x03000000, fb, 0x1008);286}287 288#if 0289static void290HCRX_SETUP_RAMDAC(struct stifb_info *fb)291{292 WRITE_WORD(0xffffffff, fb, REG_32);293}294#endif295 296static void297CRX24_SET_OVLY_MASK(struct stifb_info *fb)298{299 SETUP_HW(fb);300 WRITE_WORD(0x13a02000, fb, REG_11);301 WRITE_WORD(0x03000300, fb, REG_14);302 WRITE_WORD(0x000017f0, fb, REG_3);303 WRITE_WORD(0xffffffff, fb, REG_13);304 WRITE_WORD(0xffffffff, fb, REG_22);305 WRITE_WORD(0x00000000, fb, REG_23);306}307 308static void309ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)310{311 unsigned int value = enable ? 0x43000000 : 0x03000000;312 SETUP_HW(fb);313 WRITE_WORD(0x06000000, fb, 0x1030);314 WRITE_WORD(value, fb, 0x1038);315}316 317static void318CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)319{320 unsigned int value = enable ? 0x10000000 : 0x30000000;321 SETUP_HW(fb);322 WRITE_WORD(0x01000000, fb, 0x1000);323 WRITE_WORD(0x02000000, fb, 0x1004);324 WRITE_WORD(value, fb, 0x1008);325}326 327static void328ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)329{330 u32 DregsMiscVideo = REG_21;331 u32 DregsMiscCtl = REG_27;332 333 SETUP_HW(fb);334 if (enable) {335 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);336 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl);337 } else {338 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);339 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl);340 }341}342 343#define GET_ROMTABLE_INDEX(fb) \344 (READ_BYTE(fb, REG_16b3) - 1)345 346#define HYPER_CONFIG_PLANES_24 0x00000100347 348#define IS_24_DEVICE(fb) \349 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)350 351#define IS_888_DEVICE(fb) \352 (!(IS_24_DEVICE(fb)))353 354#define GET_FIFO_SLOTS(fb, cnt, numslots) \355{ while (cnt < numslots) \356 cnt = READ_WORD(fb, REG_34); \357 cnt -= numslots; \358}359 360#define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */361#define Otc04 2 /* Pixels in each longword transfer (4) */362#define Otc32 5 /* Pixels in each longword transfer (32) */363#define Ots08 3 /* Each pixel is size (8)d transfer (1) */364#define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */365#define AddrLong 5 /* FB address is Long aligned (pixel) */366#define BINovly 0x2 /* 8 bit overlay */367#define BINapp0I 0x0 /* Application Buffer 0, Indexed */368#define BINapp1I 0x1 /* Application Buffer 1, Indexed */369#define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */370#define BINattr 0xd /* Attribute Bitmap */371#define RopSrc 0x3372#define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */373#define BitmapExtent32 5 /* Each write hits (32) bits in depth */374#define DataDynamic 0 /* Data register reloaded by direct access */375#define MaskDynamic 1 /* Mask register reloaded by direct access */376#define MaskOtc 0 /* Mask contains Object Count valid bits */377 378#define MaskAddrOffset(offset) (offset)379#define StaticReg(en) (en)380#define BGx(en) (en)381#define FGx(en) (en)382 383#define BAJustPoint(offset) (offset)384#define BAIndexBase(base) (base)385#define BA(F,C,S,A,J,B,I) \386 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))387 388#define IBOvals(R,M,X,S,D,L,B,F) \389 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))390 391#define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \392 WRITE_WORD(val, fb, REG_14)393 394#define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \395 WRITE_WORD(val, fb, REG_11)396 397#define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \398 WRITE_WORD(val, fb, REG_12)399 400#define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \401 WRITE_WORD(plnmsk32, fb, REG_13)402 403#define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \404 WRITE_WORD(fg32, fb, REG_35)405 406#define NGLE_SET_TRANSFERDATA(fb, val) \407 WRITE_WORD(val, fb, REG_8)408 409#define NGLE_SET_DSTXY(fb, val) \410 WRITE_WORD(val, fb, REG_6)411 412#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \413 (u32) (fbaddrbase) + \414 ( (unsigned int) ( (y) << 13 ) | \415 (unsigned int) ( (x) << 2 ) ) \416 )417 418#define NGLE_BINC_SET_DSTADDR(fb, addr) \419 WRITE_WORD(addr, fb, REG_3)420 421#define NGLE_BINC_SET_SRCADDR(fb, addr) \422 WRITE_WORD(addr, fb, REG_2)423 424#define NGLE_BINC_SET_DSTMASK(fb, mask) \425 WRITE_WORD(mask, fb, REG_22)426 427#define NGLE_BINC_WRITE32(fb, data32) \428 WRITE_WORD(data32, fb, REG_23)429 430#define START_COLORMAPLOAD(fb, cmapBltCtlData32) \431 WRITE_WORD((cmapBltCtlData32), fb, REG_38)432 433#define SET_LENXY_START_RECFILL(fb, lenxy) \434 WRITE_WORD(lenxy, fb, REG_9)435 436#define SETUP_COPYAREA(fb) \437 WRITE_BYTE(0, fb, REG_16b1)438 439static void440HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)441{442 u32 DregsHypMiscVideo = REG_33;443 unsigned int value;444 SETUP_HW(fb);445 value = READ_WORD(fb, DregsHypMiscVideo);446 if (enable)447 value |= 0x0A000000;448 else449 value &= ~0x0A000000;450 WRITE_WORD(value, fb, DregsHypMiscVideo);451}452 453 454/* BufferNumbers used by SETUP_ATTR_ACCESS() */455#define BUFF0_CMAP0 0x00001e02456#define BUFF1_CMAP0 0x02001e02457#define BUFF1_CMAP3 0x0c001e02458#define ARTIST_CMAP0 0x00000102459#define HYPER_CMAP8 0x00000100460#define HYPER_CMAP24 0x00000800461 462static void463SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)464{465 SETUP_HW(fb);466 WRITE_WORD(0x2EA0D000, fb, REG_11);467 WRITE_WORD(0x23000302, fb, REG_14);468 WRITE_WORD(BufferNumber, fb, REG_12);469 WRITE_WORD(0xffffffff, fb, REG_8);470}471 472static void473SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)474{475 /* REG_6 seems to have special values when run on a476 RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or477 INTERNAL_EG_X1024). The values are:478 0x2f0: internal (LCD) & external display enabled479 0x2a0: external display only480 0x000: zero on standard artist graphic cards481 */482 WRITE_WORD(0x00000000, fb, REG_6);483 WRITE_WORD((width<<16) | height, fb, REG_9);484 WRITE_WORD(0x05000000, fb, REG_6);485 WRITE_WORD(0x00040001, fb, REG_9);486}487 488static void489FINISH_ATTR_ACCESS(struct stifb_info *fb)490{491 SETUP_HW(fb);492 WRITE_WORD(0x00000000, fb, REG_12);493}494 495static void496elkSetupPlanes(struct stifb_info *fb)497{498 SETUP_RAMDAC(fb);499 SETUP_FB(fb);500}501 502static void503ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)504{505 SETUP_ATTR_ACCESS(fb, BufferNumber);506 SET_ATTR_SIZE(fb, fb->info->var.xres, fb->info->var.yres);507 FINISH_ATTR_ACCESS(fb);508 SETUP_FB(fb);509}510 511 512static void513rattlerSetupPlanes(struct stifb_info *fb)514{515 int saved_id, y;516 517 /* Write RAMDAC pixel read mask register so all overlay518 * planes are display-enabled. (CRX24 uses Bt462 pixel519 * read mask register for overlay planes, not image planes).520 */521 CRX24_SETUP_RAMDAC(fb);522 523 /* change fb->id temporarily to fool SETUP_FB() */524 saved_id = fb->id;525 fb->id = CRX24_OVERLAY_PLANES;526 SETUP_FB(fb);527 fb->id = saved_id;528 529 for (y = 0; y < fb->info->var.yres; ++y)530 fb_memset_io(fb->info->screen_base + y * fb->info->fix.line_length,531 0xff, fb->info->var.xres * fb->info->var.bits_per_pixel/8);532 533 CRX24_SET_OVLY_MASK(fb);534 SETUP_FB(fb);535}536 537 538#define HYPER_CMAP_TYPE 0539#define NGLE_CMAP_INDEXED0_TYPE 0540#define NGLE_CMAP_OVERLAY_TYPE 3541 542/* typedef of LUT (Colormap) BLT Control Register */543typedef union /* Note assumption that fields are packed left-to-right */544{ u32 all;545 struct546 {547 unsigned enable : 1;548 unsigned waitBlank : 1;549 unsigned reserved1 : 4;550 unsigned lutOffset : 10; /* Within destination LUT */551 unsigned lutType : 2; /* Cursor, image, overlay */552 unsigned reserved2 : 4;553 unsigned length : 10;554 } fields;555} NgleLutBltCtl;556 557 558#if 0559static NgleLutBltCtl560setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)561{562 NgleLutBltCtl lutBltCtl;563 564 /* set enable, zero reserved fields */565 lutBltCtl.all = 0x80000000;566 lutBltCtl.fields.length = length;567 568 switch (fb->id)569 {570 case S9000_ID_A1439A: /* CRX24 */571 if (fb->var.bits_per_pixel == 8) {572 lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;573 lutBltCtl.fields.lutOffset = 0;574 } else {575 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;576 lutBltCtl.fields.lutOffset = 0 * 256;577 }578 break;579 580 case S9000_ID_ARTIST:581 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;582 lutBltCtl.fields.lutOffset = 0 * 256;583 break;584 585 default:586 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;587 lutBltCtl.fields.lutOffset = 0;588 break;589 }590 591 /* Offset points to start of LUT. Adjust for within LUT */592 lutBltCtl.fields.lutOffset += offsetWithinLut;593 594 return lutBltCtl;595}596#endif597 598static NgleLutBltCtl599setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)600{601 NgleLutBltCtl lutBltCtl;602 603 /* set enable, zero reserved fields */604 lutBltCtl.all = 0x80000000;605 606 lutBltCtl.fields.length = length;607 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;608 609 /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */610 if (fb->info->var.bits_per_pixel == 8)611 lutBltCtl.fields.lutOffset = 2 * 256;612 else613 lutBltCtl.fields.lutOffset = 0 * 256;614 615 /* Offset points to start of LUT. Adjust for within LUT */616 lutBltCtl.fields.lutOffset += offsetWithinLut;617 618 return lutBltCtl;619}620 621 622static void hyperUndoITE(struct stifb_info *fb)623{624 int nFreeFifoSlots = 0;625 u32 fbAddr;626 627 NGLE_LOCK(fb);628 629 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);630 WRITE_WORD(0xffffffff, fb, REG_32);631 632 /* Write overlay transparency mask so only entry 255 is transparent */633 634 /* Hardware setup for full-depth write to "magic" location */635 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);636 NGLE_QUICK_SET_DST_BM_ACCESS(fb,637 BA(IndexedDcd, Otc04, Ots08, AddrLong,638 BAJustPoint(0), BINovly, BAIndexBase(0)));639 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,640 IBOvals(RopSrc, MaskAddrOffset(0),641 BitmapExtent08, StaticReg(0),642 DataDynamic, MaskOtc, BGx(0), FGx(0)));643 644 /* Now prepare to write to the "magic" location */645 fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);646 NGLE_BINC_SET_DSTADDR(fb, fbAddr);647 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);648 NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);649 650 /* Finally, write a zero to clear the mask */651 NGLE_BINC_WRITE32(fb, 0);652 653 NGLE_UNLOCK(fb);654}655 656static void657ngleDepth8_ClearImagePlanes(struct stifb_info *fb)658{659 /* FIXME! */660}661 662static void663ngleDepth24_ClearImagePlanes(struct stifb_info *fb)664{665 /* FIXME! */666}667 668static void669ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)670{671 int nFreeFifoSlots = 0;672 u32 packed_dst;673 u32 packed_len;674 675 NGLE_LOCK(fb);676 677 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);678 NGLE_QUICK_SET_DST_BM_ACCESS(fb,679 BA(IndexedDcd, Otc32, OtsIndirect,680 AddrLong, BAJustPoint(0),681 BINattr, BAIndexBase(0)));682 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);683 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);684 685 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,686 IBOvals(RopSrc, MaskAddrOffset(0),687 BitmapExtent08, StaticReg(1),688 DataDynamic, MaskOtc,689 BGx(0), FGx(0)));690 packed_dst = 0;691 packed_len = (fb->info->var.xres << 16) | fb->info->var.yres;692 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);693 NGLE_SET_DSTXY(fb, packed_dst);694 SET_LENXY_START_RECFILL(fb, packed_len);695 696 /*697 * In order to work around an ELK hardware problem (Buffy doesn't698 * always flush it's buffers when writing to the attribute699 * planes), at least 4 pixels must be written to the attribute700 * planes starting at (X == 1280) and (Y != to the last Y written701 * by BIF):702 */703 704 if (fb->id == S9000_ID_A1659A) { /* ELK_DEVICE_ID */705 /* It's safe to use scanline zero: */706 packed_dst = (1280 << 16);707 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);708 NGLE_SET_DSTXY(fb, packed_dst);709 packed_len = (4 << 16) | 1;710 SET_LENXY_START_RECFILL(fb, packed_len);711 } /* ELK Hardware Kludge */712 713 /**** Finally, set the Control Plane Register back to zero: ****/714 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);715 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);716 717 NGLE_UNLOCK(fb);718}719 720static void721ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)722{723 int nFreeFifoSlots = 0;724 u32 packed_dst;725 u32 packed_len;726 727 NGLE_LOCK(fb);728 729 /* Hardware setup */730 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);731 NGLE_QUICK_SET_DST_BM_ACCESS(fb,732 BA(IndexedDcd, Otc04, Ots08, AddrLong,733 BAJustPoint(0), BINovly, BAIndexBase(0)));734 735 NGLE_SET_TRANSFERDATA(fb, 0xffffffff); /* Write foreground color */736 737 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);738 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);739 740 packed_dst = 0;741 packed_len = (fb->info->var.xres << 16) | fb->info->var.yres;742 NGLE_SET_DSTXY(fb, packed_dst);743 744 /* Write zeroes to overlay planes */745 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,746 IBOvals(RopSrc, MaskAddrOffset(0),747 BitmapExtent08, StaticReg(0),748 DataDynamic, MaskOtc, BGx(0), FGx(0)));749 750 SET_LENXY_START_RECFILL(fb, packed_len);751 752 NGLE_UNLOCK(fb);753}754 755static void756hyperResetPlanes(struct stifb_info *fb, int enable)757{758 unsigned int controlPlaneReg;759 760 NGLE_LOCK(fb);761 762 if (IS_24_DEVICE(fb))763 if (fb->info->var.bits_per_pixel == 32)764 controlPlaneReg = 0x04000F00;765 else766 controlPlaneReg = 0x00000F00; /* 0x00000800 should be enough, but lets clear all 4 bits */767 else768 controlPlaneReg = 0x00000F00; /* 0x00000100 should be enough, but lets clear all 4 bits */769 770 switch (enable) {771 case ENABLE:772 /* clear screen */773 if (IS_24_DEVICE(fb))774 ngleDepth24_ClearImagePlanes(fb);775 else776 ngleDepth8_ClearImagePlanes(fb);777 778 /* Paint attribute planes for default case.779 * On Hyperdrive, this means all windows using overlay cmap 0. */780 ngleResetAttrPlanes(fb, controlPlaneReg);781 782 /* clear overlay planes */783 ngleClearOverlayPlanes(fb, 0xff, 255);784 785 /**************************************************786 ** Also need to counteract ITE settings787 **************************************************/788 hyperUndoITE(fb);789 break;790 791 case DISABLE:792 /* clear screen */793 if (IS_24_DEVICE(fb))794 ngleDepth24_ClearImagePlanes(fb);795 else796 ngleDepth8_ClearImagePlanes(fb);797 ngleResetAttrPlanes(fb, controlPlaneReg);798 ngleClearOverlayPlanes(fb, 0xff, 0);799 break;800 801 case -1: /* RESET */802 hyperUndoITE(fb);803 ngleResetAttrPlanes(fb, controlPlaneReg);804 break;805 }806 807 NGLE_UNLOCK(fb);808}809 810/* Return pointer to in-memory structure holding ELK device-dependent ROM values. */811 812static void813ngleGetDeviceRomData(struct stifb_info *fb)814{815#if 0816XXX: FIXME: !!!817 int *pBytePerLongDevDepData;/* data byte == LSB */818 int *pRomTable;819 NgleDevRomData *pPackedDevRomData;820 int sizePackedDevRomData = sizeof(*pPackedDevRomData);821 char *pCard8;822 int i;823 char *mapOrigin = NULL;824 825 int romTableIdx;826 827 pPackedDevRomData = fb->ngle_rom;828 829 SETUP_HW(fb);830 if (fb->id == S9000_ID_ARTIST) {831 pPackedDevRomData->cursor_pipeline_delay = 4;832 pPackedDevRomData->video_interleaves = 4;833 } else {834 /* Get pointer to unpacked byte/long data in ROM */835 pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];836 837 /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */838 if (fb->id == S9000_ID_TOMCAT)839 {840 /* jump to the correct ROM table */841 GET_ROMTABLE_INDEX(romTableIdx);842 while (romTableIdx > 0)843 {844 pCard8 = (Card8 *) pPackedDevRomData;845 pRomTable = pBytePerLongDevDepData;846 /* Pack every fourth byte from ROM into structure */847 for (i = 0; i < sizePackedDevRomData; i++)848 {849 *pCard8++ = (Card8) (*pRomTable++);850 }851 852 pBytePerLongDevDepData = (Card32 *)853 ((Card8 *) pBytePerLongDevDepData +854 pPackedDevRomData->sizeof_ngle_data);855 856 romTableIdx--;857 }858 }859 860 pCard8 = (Card8 *) pPackedDevRomData;861 862 /* Pack every fourth byte from ROM into structure */863 for (i = 0; i < sizePackedDevRomData; i++)864 {865 *pCard8++ = (Card8) (*pBytePerLongDevDepData++);866 }867 }868 869 SETUP_FB(fb);870#endif871}872 873 874#define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4875#define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8876#define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10877#define HYPERBOWL_MODE2_8_24 15878 879/* HCRX specific boot-time initialization */880static void __init881SETUP_HCRX(struct stifb_info *fb)882{883 int hyperbowl;884 int nFreeFifoSlots = 0;885 886 if (fb->id != S9000_ID_HCRX)887 return;888 889 /* Initialize Hyperbowl registers */890 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);891 892 if (IS_24_DEVICE(fb)) {893 hyperbowl = (fb->info->var.bits_per_pixel == 32) ?894 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :895 HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;896 897 /* First write to Hyperbowl must happen twice (bug) */898 WRITE_WORD(hyperbowl, fb, REG_40);899 WRITE_WORD(hyperbowl, fb, REG_40);900 901 WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);902 903 WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */904 WRITE_WORD(0x404c4048, fb, REG_43);905 WRITE_WORD(0x034c0348, fb, REG_44);906 WRITE_WORD(0x444c4448, fb, REG_45);907 } else {908 hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;909 910 /* First write to Hyperbowl must happen twice (bug) */911 WRITE_WORD(hyperbowl, fb, REG_40);912 WRITE_WORD(hyperbowl, fb, REG_40);913 914 WRITE_WORD(0x00000000, fb, REG_42);915 WRITE_WORD(0x00000000, fb, REG_43);916 WRITE_WORD(0x00000000, fb, REG_44);917 WRITE_WORD(0x444c4048, fb, REG_45);918 }919}920 921 922/* ------------------- driver specific functions --------------------------- */923 924static int925stifb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)926{927 struct stifb_info *fb = info->par;928 929 if (var->xres != fb->info->var.xres ||930 var->yres != fb->info->var.yres ||931 var->bits_per_pixel != fb->info->var.bits_per_pixel)932 return -EINVAL;933 934 var->xres_virtual = var->xres;935 var->yres_virtual = var->yres;936 var->xoffset = 0;937 var->yoffset = 0;938 var->grayscale = fb->info->var.grayscale;939 var->red.length = fb->info->var.red.length;940 var->green.length = fb->info->var.green.length;941 var->blue.length = fb->info->var.blue.length;942 943 return 0;944}945 946static int947stifb_setcolreg(u_int regno, u_int red, u_int green,948 u_int blue, u_int transp, struct fb_info *info)949{950 struct stifb_info *fb = info->par;951 u32 color;952 953 if (regno >= NR_PALETTE)954 return 1;955 956 red >>= 8;957 green >>= 8;958 blue >>= 8;959 960 DEBUG_OFF();961 962 START_IMAGE_COLORMAP_ACCESS(fb);963 964 if (unlikely(fb->info->var.grayscale)) {965 /* gray = 0.30*R + 0.59*G + 0.11*B */966 color = ((red * 77) +967 (green * 151) +968 (blue * 28)) >> 8;969 } else {970 color = ((red << 16) |971 (green << 8) |972 (blue));973 }974 975 if (fb->info->fix.visual == FB_VISUAL_DIRECTCOLOR) {976 struct fb_var_screeninfo *var = &fb->info->var;977 if (regno < 16)978 ((u32 *)fb->info->pseudo_palette)[regno] =979 regno << var->red.offset |980 regno << var->green.offset |981 regno << var->blue.offset;982 }983 984 WRITE_IMAGE_COLOR(fb, regno, color);985 986 if (fb->id == S9000_ID_HCRX) {987 NgleLutBltCtl lutBltCtl;988 989 lutBltCtl = setHyperLutBltCtl(fb,990 0, /* Offset w/i LUT */991 256); /* Load entire LUT */992 NGLE_BINC_SET_SRCADDR(fb,993 NGLE_LONG_FB_ADDRESS(0, 0x100, 0));994 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */995 START_COLORMAPLOAD(fb, lutBltCtl.all);996 SETUP_FB(fb);997 } else {998 /* cleanup colormap hardware */999 FINISH_IMAGE_COLORMAP_ACCESS(fb);1000 }1001 1002 DEBUG_ON();1003 1004 return 0;1005}1006 1007static int1008stifb_blank(int blank_mode, struct fb_info *info)1009{1010 struct stifb_info *fb = info->par;1011 int enable = (blank_mode == 0) ? ENABLE : DISABLE;1012 1013 switch (fb->id) {1014 case S9000_ID_A1439A:1015 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);1016 break;1017 case CRT_ID_VISUALIZE_EG:1018 case S9000_ID_ARTIST:1019 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);1020 break;1021 case S9000_ID_HCRX:1022 HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);1023 break;1024 case S9000_ID_A1659A:1025 case S9000_ID_TIMBER:1026 case CRX24_OVERLAY_PLANES:1027 default:1028 ENABLE_DISABLE_DISPLAY(fb, enable);1029 break;1030 }1031 1032 SETUP_FB(fb);1033 return 0;1034}1035 1036static void1037stifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)1038{1039 struct stifb_info *fb = info->par;1040 1041 SETUP_COPYAREA(fb);1042 1043 SETUP_HW(fb);1044 if (fb->info->var.bits_per_pixel == 32) {1045 WRITE_WORD(0xBBA0A000, fb, REG_10);1046 1047 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);1048 } else {1049 WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);1050 1051 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);1052 }1053 1054 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,1055 IBOvals(RopSrc, MaskAddrOffset(0),1056 BitmapExtent08, StaticReg(1),1057 DataDynamic, MaskOtc, BGx(0), FGx(0)));1058 1059 WRITE_WORD(((area->sx << 16) | area->sy), fb, REG_24);1060 WRITE_WORD(((area->width << 16) | area->height), fb, REG_7);1061 WRITE_WORD(((area->dx << 16) | area->dy), fb, REG_25);1062 1063 SETUP_FB(fb);1064}1065 1066#define ARTIST_VRAM_SIZE 0x0008041067#define ARTIST_VRAM_SRC 0x0008081068#define ARTIST_VRAM_SIZE_TRIGGER_WINFILL 0x000a041069#define ARTIST_VRAM_DEST_TRIGGER_BLOCKMOVE 0x000b001070#define ARTIST_SRC_BM_ACCESS 0x0180081071#define ARTIST_FGCOLOR 0x0180101072#define ARTIST_BGCOLOR 0x0180141073#define ARTIST_BITMAP_OP 0x01801c1074 1075static void1076stifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)1077{1078 struct stifb_info *fb = info->par;1079 1080 if (rect->rop != ROP_COPY ||1081 (fb->id == S9000_ID_HCRX && fb->info->var.bits_per_pixel == 32))1082 return cfb_fillrect(info, rect);1083 1084 SETUP_HW(fb);1085 1086 if (fb->info->var.bits_per_pixel == 32) {1087 WRITE_WORD(0xBBA0A000, fb, REG_10);1088 1089 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);1090 } else {1091 WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);1092 1093 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);1094 }1095 1096 WRITE_WORD(0x03000300, fb, ARTIST_BITMAP_OP);1097 WRITE_WORD(0x2ea01000, fb, ARTIST_SRC_BM_ACCESS);1098 NGLE_QUICK_SET_DST_BM_ACCESS(fb, 0x2ea01000);1099 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, rect->color);1100 WRITE_WORD(0, fb, ARTIST_BGCOLOR);1101 1102 NGLE_SET_DSTXY(fb, (rect->dx << 16) | (rect->dy));1103 SET_LENXY_START_RECFILL(fb, (rect->width << 16) | (rect->height));1104 1105 SETUP_FB(fb);1106}1107 1108static void __init1109stifb_init_display(struct stifb_info *fb)1110{1111 int id = fb->id;1112 1113 SETUP_FB(fb);1114 1115 /* HCRX specific initialization */1116 SETUP_HCRX(fb);1117 1118 /*1119 if (id == S9000_ID_HCRX)1120 hyperInitSprite(fb);1121 else1122 ngleInitSprite(fb);1123 */1124 1125 /* Initialize the image planes. */1126 switch (id) {1127 case S9000_ID_HCRX:1128 hyperResetPlanes(fb, ENABLE);1129 break;1130 case S9000_ID_A1439A:1131 rattlerSetupPlanes(fb);1132 break;1133 case S9000_ID_A1659A:1134 case S9000_ID_ARTIST:1135 case CRT_ID_VISUALIZE_EG:1136 elkSetupPlanes(fb);1137 break;1138 }1139 1140 /* Clear attribute planes on non HCRX devices. */1141 switch (id) {1142 case S9000_ID_A1659A:1143 case S9000_ID_A1439A:1144 if (fb->info->var.bits_per_pixel == 32)1145 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);1146 else {1147 ngleSetupAttrPlanes(fb, BUFF1_CMAP0);1148 }1149 if (id == S9000_ID_A1439A)1150 ngleClearOverlayPlanes(fb, 0xff, 0);1151 break;1152 case S9000_ID_ARTIST:1153 case CRT_ID_VISUALIZE_EG:1154 if (fb->info->var.bits_per_pixel == 32)1155 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);1156 else {1157 ngleSetupAttrPlanes(fb, ARTIST_CMAP0);1158 }1159 break;1160 }1161 stifb_blank(0, fb->info); /* 0=enable screen */1162 1163 SETUP_FB(fb);1164}1165 1166/* ------------ Interfaces to hardware functions ------------ */1167 1168static const struct fb_ops stifb_ops = {1169 .owner = THIS_MODULE,1170 __FB_DEFAULT_IOMEM_OPS_RDWR,1171 .fb_check_var = stifb_check_var,1172 .fb_setcolreg = stifb_setcolreg,1173 .fb_blank = stifb_blank,1174 .fb_fillrect = stifb_fillrect,1175 .fb_copyarea = stifb_copyarea,1176 .fb_imageblit = cfb_imageblit,1177 __FB_DEFAULT_IOMEM_OPS_MMAP,1178};1179 1180 1181/*1182 * Initialization1183 */1184 1185static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)1186{1187 struct fb_fix_screeninfo *fix;1188 struct fb_var_screeninfo *var;1189 struct stifb_info *fb;1190 struct fb_info *info;1191 unsigned long sti_rom_address;1192 char modestr[32];1193 char *dev_name;1194 int bpp, xres, yres;1195 1196 info = framebuffer_alloc(sizeof(*fb), sti->dev);1197 if (!info)1198 return -ENOMEM;1199 fb = info->par;1200 fb->info = info;1201 1202 /* set struct to a known state */1203 fix = &info->fix;1204 var = &info->var;1205 1206 fb->sti = sti;1207 dev_name = sti->sti_data->inq_outptr.dev_name;1208 /* store upper 32bits of the graphics id */1209 fb->id = fb->sti->graphics_id[0];1210 1211 /* only supported cards are allowed */1212 switch (fb->id) {1213 case CRT_ID_VISUALIZE_EG:1214 /* Visualize cards can run either in "double buffer" or1215 "standard" mode. Depending on the mode, the card reports1216 a different device name, e.g. "INTERNAL_EG_DX1024" in double1217 buffer mode and "INTERNAL_EG_X1024" in standard mode.1218 Since this driver only supports standard mode, we check1219 if the device name contains the string "DX" and tell the1220 user how to reconfigure the card. */1221 if (strstr(dev_name, "DX")) {1222 printk(KERN_WARNING1223"WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"1224"WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",1225 dev_name);1226 goto out_err0;1227 }1228 fallthrough;1229 case S9000_ID_ARTIST:1230 case S9000_ID_HCRX:1231 case S9000_ID_TIMBER:1232 case S9000_ID_A1659A:1233 case S9000_ID_A1439A:1234 break;1235 default:1236 printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",1237 dev_name, fb->id);1238 goto out_err0;1239 }1240 1241 /* default to 8 bpp on most graphic chips */1242 bpp = 8;1243 xres = sti_onscreen_x(fb->sti);1244 yres = sti_onscreen_y(fb->sti);1245 1246 ngleGetDeviceRomData(fb);1247 1248 /* get (virtual) io region base addr */1249 fix->mmio_start = REGION_BASE(fb,2);1250 fix->mmio_len = 0x400000;1251 1252 /* Reject any device not in the NGLE family */1253 switch (fb->id) {1254 case S9000_ID_A1659A: /* CRX/A1659A */1255 break;1256 case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */1257 var->grayscale = 1;1258 fb->id = S9000_ID_A1659A;1259 break;1260 case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */1261 if (strstr(dev_name, "GRAYSCALE") ||1262 strstr(dev_name, "Grayscale") ||1263 strstr(dev_name, "grayscale"))1264 var->grayscale = 1;1265 break;1266 case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */1267 /* FIXME: TomCat supports two heads:1268 * fb.iobase = REGION_BASE(fb_info,3);1269 * fb.screen_base = ioremap(REGION_BASE(fb_info,2),xxx);1270 * for now we only support the left one ! */1271 xres = fb->ngle_rom.x_size_visible;1272 yres = fb->ngle_rom.y_size_visible;1273 fb->id = S9000_ID_A1659A;1274 break;1275 case S9000_ID_A1439A: /* CRX24/A1439A */1276 bpp = 32;1277 break;1278 case S9000_ID_HCRX: /* Hyperdrive/HCRX */1279 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));1280 if ((fb->sti->regions_phys[0] & 0xfc000000) ==1281 (fb->sti->regions_phys[2] & 0xfc000000))1282 sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);1283 else1284 sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);1285 1286 fb->deviceSpecificConfig = gsc_readl(sti_rom_address);1287 if (IS_24_DEVICE(fb)) {1288 if (bpp_pref == 8 || bpp_pref == 32)1289 bpp = bpp_pref;1290 else1291 bpp = 32;1292 } else1293 bpp = 8;1294 READ_WORD(fb, REG_15);1295 SETUP_HW(fb);1296 break;1297 case CRT_ID_VISUALIZE_EG:1298 case S9000_ID_ARTIST: /* Artist */1299 break;1300 default:1301#ifdef FALLBACK_TO_1BPP1302 printk(KERN_WARNING1303 "stifb: Unsupported graphics card (id=0x%08x) "1304 "- now trying 1bpp mode instead\n",1305 fb->id);1306 bpp = 1; /* default to 1 bpp */1307 break;1308#else1309 printk(KERN_WARNING1310 "stifb: Unsupported graphics card (id=0x%08x) "1311 "- skipping.\n",1312 fb->id);1313 goto out_err0;1314#endif1315 }1316 1317 1318 /* get framebuffer physical and virtual base addr & len (64bit ready) */1319 fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);1320 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;1321 1322 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;1323 if (!fix->line_length)1324 fix->line_length = 2048; /* default */1325 1326 /* limit fbsize to max visible screen size */1327 if (fix->smem_len > yres*fix->line_length)1328 fix->smem_len = ALIGN(yres*fix->line_length, 4*1024*1024);1329 1330 fix->accel = FB_ACCEL_NONE;1331 1332 switch (bpp) {1333 case 1:1334 fix->type = FB_TYPE_PLANES; /* well, sort of */1335 fix->visual = FB_VISUAL_MONO10;1336 var->red.length = var->green.length = var->blue.length = 1;1337 break;1338 case 8:1339 fix->type = FB_TYPE_PACKED_PIXELS;1340 fix->visual = FB_VISUAL_PSEUDOCOLOR;1341 var->red.length = var->green.length = var->blue.length = 8;1342 break;1343 case 32:1344 fix->type = FB_TYPE_PACKED_PIXELS;1345 fix->visual = FB_VISUAL_DIRECTCOLOR;1346 var->red.length = var->green.length = var->blue.length = var->transp.length = 8;1347 var->blue.offset = 0;1348 var->green.offset = 8;1349 var->red.offset = 16;1350 var->transp.offset = 24;1351 break;1352 default:1353 break;1354 }1355 1356 var->xres = var->xres_virtual = xres;1357 var->yres = var->yres_virtual = yres;1358 var->bits_per_pixel = bpp;1359 1360 strcpy(fix->id, "stifb");1361 info->fbops = &stifb_ops;1362 info->screen_base = ioremap(REGION_BASE(fb,1), fix->smem_len);1363 if (!info->screen_base) {1364 printk(KERN_ERR "stifb: failed to map memory\n");1365 goto out_err0;1366 }1367 info->screen_size = fix->smem_len;1368 info->flags = FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;1369 info->pseudo_palette = &fb->pseudo_palette;1370 1371 scnprintf(modestr, sizeof(modestr), "%dx%d-%d", xres, yres, bpp);1372 fb_find_mode(&info->var, info, modestr, NULL, 0, NULL, bpp);1373 1374 /* This has to be done !!! */1375 if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))1376 goto out_err1;1377 stifb_init_display(fb);1378 1379 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {1380 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",1381 fix->smem_start, fix->smem_start+fix->smem_len);1382 goto out_err2;1383 }1384 1385 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {1386 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",1387 fix->mmio_start, fix->mmio_start+fix->mmio_len);1388 goto out_err3;1389 }1390 1391 /* save for primary gfx device detection & unregister_framebuffer() */1392 if (register_framebuffer(fb->info) < 0)1393 goto out_err4;1394 1395 fb_info(fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",1396 fix->id,1397 var->xres,1398 var->yres,1399 var->bits_per_pixel,1400 dev_name,1401 fb->id,1402 fix->mmio_start);1403 1404 dev_set_drvdata(sti->dev, info);1405 1406 return 0;1407 1408 1409out_err4:1410 release_mem_region(fix->mmio_start, fix->mmio_len);1411out_err3:1412 release_mem_region(fix->smem_start, fix->smem_len);1413out_err2:1414 fb_dealloc_cmap(&info->cmap);1415out_err1:1416 iounmap(info->screen_base);1417out_err0:1418 framebuffer_release(info);1419 return -ENXIO;1420}1421 1422static int stifb_disabled __initdata;1423 1424int __init1425stifb_setup(char *options);1426 1427static int __init stifb_init(void)1428{1429 struct sti_struct *sti;1430 struct sti_struct *def_sti;1431 int i;1432 1433#ifndef MODULE1434 char *option = NULL;1435 1436 if (fb_get_options("stifb", &option))1437 return -ENODEV;1438 stifb_setup(option);1439#endif1440 if (stifb_disabled) {1441 printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");1442 return -ENXIO;1443 }1444 1445 def_sti = sti_get_rom(0);1446 if (def_sti) {1447 for (i = 1; i <= MAX_STI_ROMS; i++) {1448 sti = sti_get_rom(i);1449 if (!sti)1450 break;1451 if (sti == def_sti) {1452 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);1453 break;1454 }1455 }1456 }1457 1458 for (i = 1; i <= MAX_STI_ROMS; i++) {1459 sti = sti_get_rom(i);1460 if (!sti)1461 break;1462 if (sti == def_sti)1463 continue;1464 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);1465 }1466 return 0;1467}1468 1469/*1470 * Cleanup1471 */1472 1473static void __exit1474stifb_cleanup(void)1475{1476 struct sti_struct *sti;1477 int i;1478 1479 for (i = 1; i <= MAX_STI_ROMS; i++) {1480 sti = sti_get_rom(i);1481 if (!sti)1482 break;1483 if (sti->dev) {1484 struct fb_info *info = dev_get_drvdata(sti->dev);1485 1486 if (!info)1487 continue;1488 unregister_framebuffer(info);1489 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);1490 release_mem_region(info->fix.smem_start, info->fix.smem_len);1491 if (info->screen_base)1492 iounmap(info->screen_base);1493 fb_dealloc_cmap(&info->cmap);1494 framebuffer_release(info);1495 dev_set_drvdata(sti->dev, NULL);1496 }1497 }1498}1499 1500int __init1501stifb_setup(char *options)1502{1503 int i;1504 1505 if (!options || !*options)1506 return 1;1507 1508 if (strncmp(options, "off", 3) == 0) {1509 stifb_disabled = 1;1510 options += 3;1511 }1512 1513 if (strncmp(options, "bpp", 3) == 0) {1514 options += 3;1515 for (i = 0; i < MAX_STI_ROMS; i++) {1516 if (*options++ != ':')1517 break;1518 stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);1519 }1520 }1521 return 1;1522}1523 1524__setup("stifb=", stifb_setup);1525 1526module_init(stifb_init);1527module_exit(stifb_cleanup);1528 1529MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");1530MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");1531MODULE_LICENSE("GPL v2");1532