linux/drivers/video/fbdev/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#include <linux/io.h>
  68
  69#include <asm/grfioctl.h>       /* for HP-UX compatibility */
  70#include <linux/uaccess.h>
  71
  72#include "sticore.h"
  73
  74/* REGION_BASE(fb_info, index) returns the virtual address for region <index> */
  75#define REGION_BASE(fb_info, index) \
  76        F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index])
  77
  78#define NGLEDEVDEPROM_CRT_REGION 1
  79
  80#define NR_PALETTE 256
  81
  82typedef struct {
  83        __s32   video_config_reg;
  84        __s32   misc_video_start;
  85        __s32   horiz_timing_fmt;
  86        __s32   serr_timing_fmt;
  87        __s32   vert_timing_fmt;
  88        __s32   horiz_state;
  89        __s32   vert_state;
  90        __s32   vtg_state_elements;
  91        __s32   pipeline_delay;
  92        __s32   misc_video_end;
  93} video_setup_t;
  94
  95typedef struct {                  
  96        __s16   sizeof_ngle_data;
  97        __s16   x_size_visible;     /* visible screen dim in pixels  */
  98        __s16   y_size_visible;
  99        __s16   pad2[15];
 100        __s16   cursor_pipeline_delay;
 101        __s16   video_interleaves;
 102        __s32   pad3[11];
 103} ngle_rom_t;
 104
 105struct stifb_info {
 106        struct fb_info info;
 107        unsigned int id;
 108        ngle_rom_t ngle_rom;
 109        struct sti_struct *sti;
 110        int deviceSpecificConfig;
 111        u32 pseudo_palette[16];
 112};
 113
 114static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
 115
 116/* ------------------- chipset specific functions -------------------------- */
 117
 118/* offsets to graphic-chip internal registers */
 119
 120#define REG_1           0x000118
 121#define REG_2           0x000480
 122#define REG_3           0x0004a0
 123#define REG_4           0x000600
 124#define REG_6           0x000800
 125#define REG_7           0x000804
 126#define REG_8           0x000820
 127#define REG_9           0x000a04
 128#define REG_10          0x018000
 129#define REG_11          0x018004
 130#define REG_12          0x01800c
 131#define REG_13          0x018018
 132#define REG_14          0x01801c
 133#define REG_15          0x200000
 134#define REG_15b0        0x200000
 135#define REG_16b1        0x200005
 136#define REG_16b3        0x200007
 137#define REG_21          0x200218
 138#define REG_22          0x0005a0
 139#define REG_23          0x0005c0
 140#define REG_24          0x000808
 141#define REG_25          0x000b00
 142#define REG_26          0x200118
 143#define REG_27          0x200308
 144#define REG_32          0x21003c
 145#define REG_33          0x210040
 146#define REG_34          0x200008
 147#define REG_35          0x018010
 148#define REG_38          0x210020
 149#define REG_39          0x210120
 150#define REG_40          0x210130
 151#define REG_42          0x210028
 152#define REG_43          0x21002c
 153#define REG_44          0x210030
 154#define REG_45          0x210034
 155
 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_REGS
 161# 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#else
 166  static int debug_on = 1;
 167# define  DEBUG_OFF() debug_on=0
 168# define  DEBUG_ON()  debug_on=1
 169# 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 0
 182
 183#define NGLE_LOCK(fb_info)      do { } while (0) 
 184#define NGLE_UNLOCK(fb_info)    do { } while (0)
 185
 186static void
 187SETUP_HW(struct stifb_info *fb)
 188{
 189        char stat;
 190
 191        do {
 192                stat = READ_BYTE(fb, REG_15b0);
 193                if (!stat)
 194                        stat = READ_BYTE(fb, REG_15b0);
 195        } while (stat);
 196}
 197
 198
 199static void
 200SETUP_FB(struct stifb_info *fb)
 201{       
 202        unsigned int reg10_value = 0;
 203        
 204        SETUP_HW(fb);
 205        switch (fb->id)
 206        {
 207                case CRT_ID_VISUALIZE_EG:
 208                case S9000_ID_ARTIST:
 209                case S9000_ID_A1659A:
 210                        reg10_value = 0x13601000;
 211                        break;
 212                case S9000_ID_A1439A:
 213                        if (fb->info.var.bits_per_pixel == 32)                                          
 214                                reg10_value = 0xBBA0A000;
 215                        else 
 216                                reg10_value = 0x13601000;
 217                        break;
 218                case S9000_ID_HCRX:
 219                        if (fb->info.var.bits_per_pixel == 32)
 220                                reg10_value = 0xBBA0A000;
 221                        else                                    
 222                                reg10_value = 0x13602000;
 223                        break;
 224                case S9000_ID_TIMBER:
 225                case CRX24_OVERLAY_PLANES:
 226                        reg10_value = 0x13602000;
 227                        break;
 228        }
 229        if (reg10_value)
 230                WRITE_WORD(reg10_value, fb, REG_10);
 231        WRITE_WORD(0x83000300, fb, REG_14);
 232        SETUP_HW(fb);
 233        WRITE_BYTE(1, fb, REG_16b1);
 234}
 235
 236static void
 237START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
 238{
 239        SETUP_HW(fb);
 240        WRITE_WORD(0xBBE0F000, fb, REG_10);
 241        WRITE_WORD(0x03000300, fb, REG_14);
 242        WRITE_WORD(~0, fb, REG_13);
 243}
 244
 245static void
 246WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color) 
 247{
 248        SETUP_HW(fb);
 249        WRITE_WORD(((0x100+index)<<2), fb, REG_3);
 250        WRITE_WORD(color, fb, REG_4);
 251}
 252
 253static void
 254FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) 
 255{               
 256        WRITE_WORD(0x400, fb, REG_2);
 257        if (fb->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                else                                                    
 263                        WRITE_WORD(0x80000100, fb, REG_1);
 264        }
 265        SETUP_FB(fb);
 266}
 267
 268static void
 269SETUP_RAMDAC(struct stifb_info *fb) 
 270{
 271        SETUP_HW(fb);
 272        WRITE_WORD(0x04000000, fb, 0x1020);
 273        WRITE_WORD(0xff000000, fb, 0x1028);
 274}
 275
 276static void 
 277CRX24_SETUP_RAMDAC(struct stifb_info *fb) 
 278{
 279        SETUP_HW(fb);
 280        WRITE_WORD(0x04000000, fb, 0x1000);
 281        WRITE_WORD(0x02000000, fb, 0x1004);
 282        WRITE_WORD(0xff000000, fb, 0x1008);
 283        WRITE_WORD(0x05000000, fb, 0x1000);
 284        WRITE_WORD(0x02000000, fb, 0x1004);
 285        WRITE_WORD(0x03000000, fb, 0x1008);
 286}
 287
 288#if 0
 289static void 
 290HCRX_SETUP_RAMDAC(struct stifb_info *fb)
 291{
 292        WRITE_WORD(0xffffffff, fb, REG_32);
 293}
 294#endif
 295
 296static void 
 297CRX24_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 void
 309ENABLE_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 void 
 318CRX24_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 void
 328ARTIST_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 0x00000100
 347        
 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      0x3
 372#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 void
 440HYPER_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        else
 449                value &= ~0x0A000000;
 450        WRITE_WORD(value, fb, DregsHypMiscVideo);
 451}
 452
 453
 454/* BufferNumbers used by SETUP_ATTR_ACCESS() */
 455#define BUFF0_CMAP0     0x00001e02
 456#define BUFF1_CMAP0     0x02001e02
 457#define BUFF1_CMAP3     0x0c001e02
 458#define ARTIST_CMAP0    0x00000102
 459#define HYPER_CMAP8     0x00000100
 460#define HYPER_CMAP24    0x00000800
 461
 462static void
 463SETUP_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 void
 473SET_ATTR_SIZE(struct stifb_info *fb, int width, int height) 
 474{
 475        /* REG_6 seems to have special values when run on a 
 476           RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
 477           INTERNAL_EG_X1024).  The values are:
 478                0x2f0: internal (LCD) & external display enabled
 479                0x2a0: external display only
 480                0x000: zero on standard artist graphic cards
 481        */ 
 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 void
 489FINISH_ATTR_ACCESS(struct stifb_info *fb) 
 490{
 491        SETUP_HW(fb);
 492        WRITE_WORD(0x00000000, fb, REG_12);
 493}
 494
 495static void
 496elkSetupPlanes(struct stifb_info *fb)
 497{
 498        SETUP_RAMDAC(fb);
 499        SETUP_FB(fb);
 500}
 501
 502static void 
 503ngleSetupAttrPlanes(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 void
 513rattlerSetupPlanes(struct stifb_info *fb)
 514{
 515        int saved_id, y;
 516
 517        /* Write RAMDAC pixel read mask register so all overlay
 518         * planes are display-enabled.  (CRX24 uses Bt462 pixel
 519         * 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(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                         0
 539#define NGLE_CMAP_INDEXED0_TYPE                 0
 540#define NGLE_CMAP_OVERLAY_TYPE                  3
 541
 542/* typedef of LUT (Colormap) BLT Control Register */
 543typedef union   /* Note assumption that fields are packed left-to-right */
 544{       u32 all;
 545        struct
 546        {
 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 0
 559static NgleLutBltCtl
 560setNgleLutBltCtl(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#endif
 597
 598static NgleLutBltCtl
 599setHyperLutBltCtl(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        else
 613                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 void 
 657ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
 658{
 659        /* FIXME! */
 660}
 661
 662static void 
 663ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
 664{
 665        /* FIXME! */
 666}
 667
 668static void
 669ngleResetAttrPlanes(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't
 698         * always flush it's buffers when writing to the attribute
 699         * planes), at least 4 pixels must be written to the attribute
 700         * planes starting at (X == 1280) and (Y != to the last Y written
 701         * 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 void
 721ngleClearOverlayPlanes(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 void 
 756hyperResetPlanes(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                else
 766                        controlPlaneReg = 0x00000F00;   /* 0x00000800 should be enough, but lets clear all 4 bits */
 767        else
 768                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                else
 776                        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 settings 
 787                 **************************************************/
 788                hyperUndoITE(fb);
 789                break;
 790
 791        case DISABLE:
 792                /* clear screen */
 793                if (IS_24_DEVICE(fb))
 794                        ngleDepth24_ClearImagePlanes(fb);
 795                else
 796                        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 void 
 813ngleGetDeviceRomData(struct stifb_info *fb)
 814{
 815#if 0
 816XXX: 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#endif
 871}
 872
 873
 874#define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES     4
 875#define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE      8
 876#define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE           10
 877#define HYPERBOWL_MODE2_8_24                                    15
 878
 879/* HCRX specific boot-time initialization */
 880static void __init
 881SETUP_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 int
 925stifb_setcolreg(u_int regno, u_int red, u_int green,
 926              u_int blue, u_int transp, struct fb_info *info)
 927{
 928        struct stifb_info *fb = container_of(info, struct stifb_info, info);
 929        u32 color;
 930
 931        if (regno >= NR_PALETTE)
 932                return 1;
 933
 934        red   >>= 8;
 935        green >>= 8;
 936        blue  >>= 8;
 937
 938        DEBUG_OFF();
 939
 940        START_IMAGE_COLORMAP_ACCESS(fb);
 941
 942        if (unlikely(fb->info.var.grayscale)) {
 943                /* gray = 0.30*R + 0.59*G + 0.11*B */
 944                color = ((red * 77) +
 945                         (green * 151) +
 946                         (blue * 28)) >> 8;
 947        } else {
 948                color = ((red << 16) |
 949                         (green << 8) |
 950                         (blue));
 951        }
 952
 953        if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
 954                struct fb_var_screeninfo *var = &fb->info.var;
 955                if (regno < 16)
 956                        ((u32 *)fb->info.pseudo_palette)[regno] =
 957                                regno << var->red.offset |
 958                                regno << var->green.offset |
 959                                regno << var->blue.offset;
 960        }
 961
 962        WRITE_IMAGE_COLOR(fb, regno, color);
 963
 964        if (fb->id == S9000_ID_HCRX) {
 965                NgleLutBltCtl lutBltCtl;
 966
 967                lutBltCtl = setHyperLutBltCtl(fb,
 968                                0,      /* Offset w/i LUT */
 969                                256);   /* Load entire LUT */
 970                NGLE_BINC_SET_SRCADDR(fb,
 971                                NGLE_LONG_FB_ADDRESS(0, 0x100, 0)); 
 972                                /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
 973                START_COLORMAPLOAD(fb, lutBltCtl.all);
 974                SETUP_FB(fb);
 975        } else {
 976                /* cleanup colormap hardware */
 977                FINISH_IMAGE_COLORMAP_ACCESS(fb);
 978        }
 979
 980        DEBUG_ON();
 981
 982        return 0;
 983}
 984
 985static int
 986stifb_blank(int blank_mode, struct fb_info *info)
 987{
 988        struct stifb_info *fb = container_of(info, struct stifb_info, info);
 989        int enable = (blank_mode == 0) ? ENABLE : DISABLE;
 990
 991        switch (fb->id) {
 992        case S9000_ID_A1439A:
 993                CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
 994                break;
 995        case CRT_ID_VISUALIZE_EG:
 996        case S9000_ID_ARTIST:
 997                ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
 998                break;
 999        case S9000_ID_HCRX:
1000                HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
1001                break;
1002        case S9000_ID_A1659A:   /* fall through */
1003        case S9000_ID_TIMBER:
1004        case CRX24_OVERLAY_PLANES:
1005        default:
1006                ENABLE_DISABLE_DISPLAY(fb, enable);
1007                break;
1008        }
1009        
1010        SETUP_FB(fb);
1011        return 0;
1012}
1013
1014static void
1015stifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1016{
1017        struct stifb_info *fb = container_of(info, struct stifb_info, info);
1018
1019        SETUP_COPYAREA(fb);
1020
1021        SETUP_HW(fb);
1022        if (fb->info.var.bits_per_pixel == 32) {
1023                WRITE_WORD(0xBBA0A000, fb, REG_10);
1024
1025                NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
1026        } else {
1027                WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
1028
1029                NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
1030        }
1031
1032        NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
1033                IBOvals(RopSrc, MaskAddrOffset(0),
1034                BitmapExtent08, StaticReg(1),
1035                DataDynamic, MaskOtc, BGx(0), FGx(0)));
1036
1037        WRITE_WORD(((area->sx << 16) | area->sy), fb, REG_24);
1038        WRITE_WORD(((area->width << 16) | area->height), fb, REG_7);
1039        WRITE_WORD(((area->dx << 16) | area->dy), fb, REG_25);
1040
1041        SETUP_FB(fb);
1042}
1043
1044static void __init
1045stifb_init_display(struct stifb_info *fb)
1046{
1047        int id = fb->id;
1048
1049        SETUP_FB(fb);
1050
1051        /* HCRX specific initialization */
1052        SETUP_HCRX(fb);
1053        
1054        /*
1055        if (id == S9000_ID_HCRX)
1056                hyperInitSprite(fb);
1057        else
1058                ngleInitSprite(fb);
1059        */
1060        
1061        /* Initialize the image planes. */ 
1062        switch (id) {
1063         case S9000_ID_HCRX:
1064            hyperResetPlanes(fb, ENABLE);
1065            break;
1066         case S9000_ID_A1439A:
1067            rattlerSetupPlanes(fb);
1068            break;
1069         case S9000_ID_A1659A:
1070         case S9000_ID_ARTIST:
1071         case CRT_ID_VISUALIZE_EG:
1072            elkSetupPlanes(fb);
1073            break;
1074        }
1075
1076        /* Clear attribute planes on non HCRX devices. */
1077        switch (id) {
1078         case S9000_ID_A1659A:
1079         case S9000_ID_A1439A:
1080            if (fb->info.var.bits_per_pixel == 32)
1081                ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1082            else {
1083                ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1084            }
1085            if (id == S9000_ID_A1439A)
1086                ngleClearOverlayPlanes(fb, 0xff, 0);
1087            break;
1088         case S9000_ID_ARTIST:
1089         case CRT_ID_VISUALIZE_EG:
1090            if (fb->info.var.bits_per_pixel == 32)
1091                ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1092            else {
1093                ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1094            }
1095            break;
1096        }
1097        stifb_blank(0, (struct fb_info *)fb);   /* 0=enable screen */
1098
1099        SETUP_FB(fb);
1100}
1101
1102/* ------------ Interfaces to hardware functions ------------ */
1103
1104static struct fb_ops stifb_ops = {
1105        .owner          = THIS_MODULE,
1106        .fb_setcolreg   = stifb_setcolreg,
1107        .fb_blank       = stifb_blank,
1108        .fb_fillrect    = cfb_fillrect,
1109        .fb_copyarea    = stifb_copyarea,
1110        .fb_imageblit   = cfb_imageblit,
1111};
1112
1113
1114/*
1115 *  Initialization
1116 */
1117
1118static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1119{
1120        struct fb_fix_screeninfo *fix;
1121        struct fb_var_screeninfo *var;
1122        struct stifb_info *fb;
1123        struct fb_info *info;
1124        unsigned long sti_rom_address;
1125        char *dev_name;
1126        int bpp, xres, yres;
1127
1128        fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
1129        if (!fb)
1130                return -ENOMEM;
1131        
1132        info = &fb->info;
1133
1134        /* set struct to a known state */
1135        fix = &info->fix;
1136        var = &info->var;
1137
1138        fb->sti = sti;
1139        dev_name = sti->sti_data->inq_outptr.dev_name;
1140        /* store upper 32bits of the graphics id */
1141        fb->id = fb->sti->graphics_id[0];
1142
1143        /* only supported cards are allowed */
1144        switch (fb->id) {
1145        case CRT_ID_VISUALIZE_EG:
1146                /* Visualize cards can run either in "double buffer" or
1147                  "standard" mode. Depending on the mode, the card reports
1148                  a different device name, e.g. "INTERNAL_EG_DX1024" in double
1149                  buffer mode and "INTERNAL_EG_X1024" in standard mode.
1150                  Since this driver only supports standard mode, we check
1151                  if the device name contains the string "DX" and tell the
1152                  user how to reconfigure the card. */
1153                if (strstr(dev_name, "DX")) {
1154                   printk(KERN_WARNING
1155"WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
1156"WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
1157                        dev_name);
1158                   goto out_err0;
1159                }
1160                /* fall through */
1161        case S9000_ID_ARTIST:
1162        case S9000_ID_HCRX:
1163        case S9000_ID_TIMBER:
1164        case S9000_ID_A1659A:
1165        case S9000_ID_A1439A:
1166                break;
1167        default:
1168                printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1169                        dev_name, fb->id);
1170                goto out_err0;
1171        }
1172        
1173        /* default to 8 bpp on most graphic chips */
1174        bpp = 8;
1175        xres = sti_onscreen_x(fb->sti);
1176        yres = sti_onscreen_y(fb->sti);
1177
1178        ngleGetDeviceRomData(fb);
1179
1180        /* get (virtual) io region base addr */
1181        fix->mmio_start = REGION_BASE(fb,2);
1182        fix->mmio_len   = 0x400000;
1183
1184        /* Reject any device not in the NGLE family */
1185        switch (fb->id) {
1186        case S9000_ID_A1659A:   /* CRX/A1659A */
1187                break;
1188        case S9000_ID_ELM:      /* GRX, grayscale but else same as A1659A */
1189                var->grayscale = 1;
1190                fb->id = S9000_ID_A1659A;
1191                break;
1192        case S9000_ID_TIMBER:   /* HP9000/710 Any (may be a grayscale device) */
1193                if (strstr(dev_name, "GRAYSCALE") || 
1194                    strstr(dev_name, "Grayscale") ||
1195                    strstr(dev_name, "grayscale"))
1196                        var->grayscale = 1;
1197                break;
1198        case S9000_ID_TOMCAT:   /* Dual CRX, behaves else like a CRX */
1199                /* FIXME: TomCat supports two heads:
1200                 * fb.iobase = REGION_BASE(fb_info,3);
1201                 * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx);
1202                 * for now we only support the left one ! */
1203                xres = fb->ngle_rom.x_size_visible;
1204                yres = fb->ngle_rom.y_size_visible;
1205                fb->id = S9000_ID_A1659A;
1206                break;
1207        case S9000_ID_A1439A:   /* CRX24/A1439A */
1208                bpp = 32;
1209                break;
1210        case S9000_ID_HCRX:     /* Hyperdrive/HCRX */
1211                memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1212                if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1213                    (fb->sti->regions_phys[2] & 0xfc000000))
1214                        sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1215                else
1216                        sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1217
1218                fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1219                if (IS_24_DEVICE(fb)) {
1220                        if (bpp_pref == 8 || bpp_pref == 32)
1221                                bpp = bpp_pref;
1222                        else
1223                                bpp = 32;
1224                } else
1225                        bpp = 8;
1226                READ_WORD(fb, REG_15);
1227                SETUP_HW(fb);
1228                break;
1229        case CRT_ID_VISUALIZE_EG:
1230        case S9000_ID_ARTIST:   /* Artist */
1231                break;
1232        default: 
1233#ifdef FALLBACK_TO_1BPP
1234                printk(KERN_WARNING 
1235                        "stifb: Unsupported graphics card (id=0x%08x) "
1236                                "- now trying 1bpp mode instead\n",
1237                        fb->id);
1238                bpp = 1;        /* default to 1 bpp */
1239                break;
1240#else
1241                printk(KERN_WARNING 
1242                        "stifb: Unsupported graphics card (id=0x%08x) "
1243                                "- skipping.\n",
1244                        fb->id);
1245                goto out_err0;
1246#endif
1247        }
1248
1249
1250        /* get framebuffer physical and virtual base addr & len (64bit ready) */
1251        fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1252        fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1253
1254        fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1255        if (!fix->line_length)
1256                fix->line_length = 2048; /* default */
1257        
1258        /* limit fbsize to max visible screen size */
1259        if (fix->smem_len > yres*fix->line_length)
1260                fix->smem_len = yres*fix->line_length;
1261        
1262        fix->accel = FB_ACCEL_NONE;
1263
1264        switch (bpp) {
1265            case 1:
1266                fix->type = FB_TYPE_PLANES;     /* well, sort of */
1267                fix->visual = FB_VISUAL_MONO10;
1268                var->red.length = var->green.length = var->blue.length = 1;
1269                break;
1270            case 8:
1271                fix->type = FB_TYPE_PACKED_PIXELS;
1272                fix->visual = FB_VISUAL_PSEUDOCOLOR;
1273                var->red.length = var->green.length = var->blue.length = 8;
1274                break;
1275            case 32:
1276                fix->type = FB_TYPE_PACKED_PIXELS;
1277                fix->visual = FB_VISUAL_DIRECTCOLOR;
1278                var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1279                var->blue.offset = 0;
1280                var->green.offset = 8;
1281                var->red.offset = 16;
1282                var->transp.offset = 24;
1283                break;
1284            default:
1285                break;
1286        }
1287        
1288        var->xres = var->xres_virtual = xres;
1289        var->yres = var->yres_virtual = yres;
1290        var->bits_per_pixel = bpp;
1291
1292        strcpy(fix->id, "stifb");
1293        info->fbops = &stifb_ops;
1294        info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
1295        if (!info->screen_base) {
1296                printk(KERN_ERR "stifb: failed to map memory\n");
1297                goto out_err0;
1298        }
1299        info->screen_size = fix->smem_len;
1300        info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA;
1301        info->pseudo_palette = &fb->pseudo_palette;
1302
1303        /* This has to be done !!! */
1304        if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
1305                goto out_err1;
1306        stifb_init_display(fb);
1307
1308        if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1309                printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1310                                fix->smem_start, fix->smem_start+fix->smem_len);
1311                goto out_err2;
1312        }
1313                
1314        if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1315                printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1316                                fix->mmio_start, fix->mmio_start+fix->mmio_len);
1317                goto out_err3;
1318        }
1319
1320        if (register_framebuffer(&fb->info) < 0)
1321                goto out_err4;
1322
1323        sti->info = info; /* save for unregister_framebuffer() */
1324
1325        fb_info(&fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1326                fix->id,
1327                var->xres, 
1328                var->yres,
1329                var->bits_per_pixel,
1330                dev_name,
1331                fb->id, 
1332                fix->mmio_start);
1333
1334        return 0;
1335
1336
1337out_err4:
1338        release_mem_region(fix->mmio_start, fix->mmio_len);
1339out_err3:
1340        release_mem_region(fix->smem_start, fix->smem_len);
1341out_err2:
1342        fb_dealloc_cmap(&info->cmap);
1343out_err1:
1344        iounmap(info->screen_base);
1345out_err0:
1346        kfree(fb);
1347        return -ENXIO;
1348}
1349
1350static int stifb_disabled __initdata;
1351
1352int __init
1353stifb_setup(char *options);
1354
1355static int __init stifb_init(void)
1356{
1357        struct sti_struct *sti;
1358        struct sti_struct *def_sti;
1359        int i;
1360        
1361#ifndef MODULE
1362        char *option = NULL;
1363
1364        if (fb_get_options("stifb", &option))
1365                return -ENODEV;
1366        stifb_setup(option);
1367#endif
1368        if (stifb_disabled) {
1369                printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1370                return -ENXIO;
1371        }
1372        
1373        def_sti = sti_get_rom(0);
1374        if (def_sti) {
1375                for (i = 1; i <= MAX_STI_ROMS; i++) {
1376                        sti = sti_get_rom(i);
1377                        if (!sti)
1378                                break;
1379                        if (sti == def_sti) {
1380                                stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1381                                break;
1382                        }
1383                }
1384        }
1385
1386        for (i = 1; i <= MAX_STI_ROMS; i++) {
1387                sti = sti_get_rom(i);
1388                if (!sti)
1389                        break;
1390                if (sti == def_sti)
1391                        continue;
1392                stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1393        }
1394        return 0;
1395}
1396
1397/*
1398 *  Cleanup
1399 */
1400
1401static void __exit
1402stifb_cleanup(void)
1403{
1404        struct sti_struct *sti;
1405        int i;
1406        
1407        for (i = 1; i <= MAX_STI_ROMS; i++) {
1408                sti = sti_get_rom(i);
1409                if (!sti)
1410                        break;
1411                if (sti->info) {
1412                        struct fb_info *info = sti->info;
1413                        unregister_framebuffer(sti->info);
1414                        release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1415                        release_mem_region(info->fix.smem_start, info->fix.smem_len);
1416                                if (info->screen_base)
1417                                        iounmap(info->screen_base);
1418                        fb_dealloc_cmap(&info->cmap);
1419                        framebuffer_release(info);
1420                }
1421                sti->info = NULL;
1422        }
1423}
1424
1425int __init
1426stifb_setup(char *options)
1427{
1428        int i;
1429        
1430        if (!options || !*options)
1431                return 1;
1432        
1433        if (strncmp(options, "off", 3) == 0) {
1434                stifb_disabled = 1;
1435                options += 3;
1436        }
1437
1438        if (strncmp(options, "bpp", 3) == 0) {
1439                options += 3;
1440                for (i = 0; i < MAX_STI_ROMS; i++) {
1441                        if (*options++ != ':')
1442                                break;
1443                        stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1444                }
1445        }
1446        return 1;
1447}
1448
1449__setup("stifb=", stifb_setup);
1450
1451module_init(stifb_init);
1452module_exit(stifb_cleanup);
1453
1454MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1455MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1456MODULE_LICENSE("GPL v2");
1457