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