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:
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
1044#define ARTIST_VRAM_SIZE                        0x000804
1045#define ARTIST_VRAM_SRC                         0x000808
1046#define ARTIST_VRAM_SIZE_TRIGGER_WINFILL        0x000a04
1047#define ARTIST_VRAM_DEST_TRIGGER_BLOCKMOVE      0x000b00
1048#define ARTIST_SRC_BM_ACCESS                    0x018008
1049#define ARTIST_FGCOLOR                          0x018010
1050#define ARTIST_BGCOLOR                          0x018014
1051#define ARTIST_BITMAP_OP                        0x01801c
1052
1053static void
1054stifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
1055{
1056        struct stifb_info *fb = container_of(info, struct stifb_info, info);
1057
1058        if (rect->rop != ROP_COPY)
1059                return cfb_fillrect(info, rect);
1060
1061        SETUP_HW(fb);
1062
1063        if (fb->info.var.bits_per_pixel == 32) {
1064                WRITE_WORD(0xBBA0A000, fb, REG_10);
1065
1066                NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
1067        } else {
1068                WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
1069
1070                NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
1071        }
1072
1073        WRITE_WORD(0x03000300, fb, ARTIST_BITMAP_OP);
1074        WRITE_WORD(0x2ea01000, fb, ARTIST_SRC_BM_ACCESS);
1075        NGLE_QUICK_SET_DST_BM_ACCESS(fb, 0x2ea01000);
1076        NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, rect->color);
1077        WRITE_WORD(0, fb, ARTIST_BGCOLOR);
1078
1079        NGLE_SET_DSTXY(fb, (rect->dx << 16) | (rect->dy));
1080        SET_LENXY_START_RECFILL(fb, (rect->width << 16) | (rect->height));
1081
1082        SETUP_FB(fb);
1083}
1084
1085static void __init
1086stifb_init_display(struct stifb_info *fb)
1087{
1088        int id = fb->id;
1089
1090        SETUP_FB(fb);
1091
1092        /* HCRX specific initialization */
1093        SETUP_HCRX(fb);
1094        
1095        /*
1096        if (id == S9000_ID_HCRX)
1097                hyperInitSprite(fb);
1098        else
1099                ngleInitSprite(fb);
1100        */
1101        
1102        /* Initialize the image planes. */ 
1103        switch (id) {
1104         case S9000_ID_HCRX:
1105            hyperResetPlanes(fb, ENABLE);
1106            break;
1107         case S9000_ID_A1439A:
1108            rattlerSetupPlanes(fb);
1109            break;
1110         case S9000_ID_A1659A:
1111         case S9000_ID_ARTIST:
1112         case CRT_ID_VISUALIZE_EG:
1113            elkSetupPlanes(fb);
1114            break;
1115        }
1116
1117        /* Clear attribute planes on non HCRX devices. */
1118        switch (id) {
1119         case S9000_ID_A1659A:
1120         case S9000_ID_A1439A:
1121            if (fb->info.var.bits_per_pixel == 32)
1122                ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1123            else {
1124                ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1125            }
1126            if (id == S9000_ID_A1439A)
1127                ngleClearOverlayPlanes(fb, 0xff, 0);
1128            break;
1129         case S9000_ID_ARTIST:
1130         case CRT_ID_VISUALIZE_EG:
1131            if (fb->info.var.bits_per_pixel == 32)
1132                ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1133            else {
1134                ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1135            }
1136            break;
1137        }
1138        stifb_blank(0, (struct fb_info *)fb);   /* 0=enable screen */
1139
1140        SETUP_FB(fb);
1141}
1142
1143/* ------------ Interfaces to hardware functions ------------ */
1144
1145static const struct fb_ops stifb_ops = {
1146        .owner          = THIS_MODULE,
1147        .fb_setcolreg   = stifb_setcolreg,
1148        .fb_blank       = stifb_blank,
1149        .fb_fillrect    = stifb_fillrect,
1150        .fb_copyarea    = stifb_copyarea,
1151        .fb_imageblit   = cfb_imageblit,
1152};
1153
1154
1155/*
1156 *  Initialization
1157 */
1158
1159static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1160{
1161        struct fb_fix_screeninfo *fix;
1162        struct fb_var_screeninfo *var;
1163        struct stifb_info *fb;
1164        struct fb_info *info;
1165        unsigned long sti_rom_address;
1166        char *dev_name;
1167        int bpp, xres, yres;
1168
1169        fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
1170        if (!fb)
1171                return -ENOMEM;
1172        
1173        info = &fb->info;
1174
1175        /* set struct to a known state */
1176        fix = &info->fix;
1177        var = &info->var;
1178
1179        fb->sti = sti;
1180        dev_name = sti->sti_data->inq_outptr.dev_name;
1181        /* store upper 32bits of the graphics id */
1182        fb->id = fb->sti->graphics_id[0];
1183
1184        /* only supported cards are allowed */
1185        switch (fb->id) {
1186        case CRT_ID_VISUALIZE_EG:
1187                /* Visualize cards can run either in "double buffer" or
1188                  "standard" mode. Depending on the mode, the card reports
1189                  a different device name, e.g. "INTERNAL_EG_DX1024" in double
1190                  buffer mode and "INTERNAL_EG_X1024" in standard mode.
1191                  Since this driver only supports standard mode, we check
1192                  if the device name contains the string "DX" and tell the
1193                  user how to reconfigure the card. */
1194                if (strstr(dev_name, "DX")) {
1195                   printk(KERN_WARNING
1196"WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
1197"WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
1198                        dev_name);
1199                   goto out_err0;
1200                }
1201                fallthrough;
1202        case S9000_ID_ARTIST:
1203        case S9000_ID_HCRX:
1204        case S9000_ID_TIMBER:
1205        case S9000_ID_A1659A:
1206        case S9000_ID_A1439A:
1207                break;
1208        default:
1209                printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1210                        dev_name, fb->id);
1211                goto out_err0;
1212        }
1213        
1214        /* default to 8 bpp on most graphic chips */
1215        bpp = 8;
1216        xres = sti_onscreen_x(fb->sti);
1217        yres = sti_onscreen_y(fb->sti);
1218
1219        ngleGetDeviceRomData(fb);
1220
1221        /* get (virtual) io region base addr */
1222        fix->mmio_start = REGION_BASE(fb,2);
1223        fix->mmio_len   = 0x400000;
1224
1225        /* Reject any device not in the NGLE family */
1226        switch (fb->id) {
1227        case S9000_ID_A1659A:   /* CRX/A1659A */
1228                break;
1229        case S9000_ID_ELM:      /* GRX, grayscale but else same as A1659A */
1230                var->grayscale = 1;
1231                fb->id = S9000_ID_A1659A;
1232                break;
1233        case S9000_ID_TIMBER:   /* HP9000/710 Any (may be a grayscale device) */
1234                if (strstr(dev_name, "GRAYSCALE") || 
1235                    strstr(dev_name, "Grayscale") ||
1236                    strstr(dev_name, "grayscale"))
1237                        var->grayscale = 1;
1238                break;
1239        case S9000_ID_TOMCAT:   /* Dual CRX, behaves else like a CRX */
1240                /* FIXME: TomCat supports two heads:
1241                 * fb.iobase = REGION_BASE(fb_info,3);
1242                 * fb.screen_base = ioremap(REGION_BASE(fb_info,2),xxx);
1243                 * for now we only support the left one ! */
1244                xres = fb->ngle_rom.x_size_visible;
1245                yres = fb->ngle_rom.y_size_visible;
1246                fb->id = S9000_ID_A1659A;
1247                break;
1248        case S9000_ID_A1439A:   /* CRX24/A1439A */
1249                bpp = 32;
1250                break;
1251        case S9000_ID_HCRX:     /* Hyperdrive/HCRX */
1252                memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1253                if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1254                    (fb->sti->regions_phys[2] & 0xfc000000))
1255                        sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1256                else
1257                        sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1258
1259                fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1260                if (IS_24_DEVICE(fb)) {
1261                        if (bpp_pref == 8 || bpp_pref == 32)
1262                                bpp = bpp_pref;
1263                        else
1264                                bpp = 32;
1265                } else
1266                        bpp = 8;
1267                READ_WORD(fb, REG_15);
1268                SETUP_HW(fb);
1269                break;
1270        case CRT_ID_VISUALIZE_EG:
1271        case S9000_ID_ARTIST:   /* Artist */
1272                break;
1273        default: 
1274#ifdef FALLBACK_TO_1BPP
1275                printk(KERN_WARNING 
1276                        "stifb: Unsupported graphics card (id=0x%08x) "
1277                                "- now trying 1bpp mode instead\n",
1278                        fb->id);
1279                bpp = 1;        /* default to 1 bpp */
1280                break;
1281#else
1282                printk(KERN_WARNING 
1283                        "stifb: Unsupported graphics card (id=0x%08x) "
1284                                "- skipping.\n",
1285                        fb->id);
1286                goto out_err0;
1287#endif
1288        }
1289
1290
1291        /* get framebuffer physical and virtual base addr & len (64bit ready) */
1292        fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1293        fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1294
1295        fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1296        if (!fix->line_length)
1297                fix->line_length = 2048; /* default */
1298        
1299        /* limit fbsize to max visible screen size */
1300        if (fix->smem_len > yres*fix->line_length)
1301                fix->smem_len = yres*fix->line_length;
1302        
1303        fix->accel = FB_ACCEL_NONE;
1304
1305        switch (bpp) {
1306            case 1:
1307                fix->type = FB_TYPE_PLANES;     /* well, sort of */
1308                fix->visual = FB_VISUAL_MONO10;
1309                var->red.length = var->green.length = var->blue.length = 1;
1310                break;
1311            case 8:
1312                fix->type = FB_TYPE_PACKED_PIXELS;
1313                fix->visual = FB_VISUAL_PSEUDOCOLOR;
1314                var->red.length = var->green.length = var->blue.length = 8;
1315                break;
1316            case 32:
1317                fix->type = FB_TYPE_PACKED_PIXELS;
1318                fix->visual = FB_VISUAL_DIRECTCOLOR;
1319                var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1320                var->blue.offset = 0;
1321                var->green.offset = 8;
1322                var->red.offset = 16;
1323                var->transp.offset = 24;
1324                break;
1325            default:
1326                break;
1327        }
1328        
1329        var->xres = var->xres_virtual = xres;
1330        var->yres = var->yres_virtual = yres;
1331        var->bits_per_pixel = bpp;
1332
1333        strcpy(fix->id, "stifb");
1334        info->fbops = &stifb_ops;
1335        info->screen_base = ioremap(REGION_BASE(fb,1), fix->smem_len);
1336        if (!info->screen_base) {
1337                printk(KERN_ERR "stifb: failed to map memory\n");
1338                goto out_err0;
1339        }
1340        info->screen_size = fix->smem_len;
1341        info->flags = FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1342        info->pseudo_palette = &fb->pseudo_palette;
1343
1344        /* This has to be done !!! */
1345        if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
1346                goto out_err1;
1347        stifb_init_display(fb);
1348
1349        if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1350                printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1351                                fix->smem_start, fix->smem_start+fix->smem_len);
1352                goto out_err2;
1353        }
1354                
1355        if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1356                printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1357                                fix->mmio_start, fix->mmio_start+fix->mmio_len);
1358                goto out_err3;
1359        }
1360
1361        if (register_framebuffer(&fb->info) < 0)
1362                goto out_err4;
1363
1364        sti->info = info; /* save for unregister_framebuffer() */
1365
1366        fb_info(&fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1367                fix->id,
1368                var->xres, 
1369                var->yres,
1370                var->bits_per_pixel,
1371                dev_name,
1372                fb->id, 
1373                fix->mmio_start);
1374
1375        return 0;
1376
1377
1378out_err4:
1379        release_mem_region(fix->mmio_start, fix->mmio_len);
1380out_err3:
1381        release_mem_region(fix->smem_start, fix->smem_len);
1382out_err2:
1383        fb_dealloc_cmap(&info->cmap);
1384out_err1:
1385        iounmap(info->screen_base);
1386out_err0:
1387        kfree(fb);
1388        return -ENXIO;
1389}
1390
1391static int stifb_disabled __initdata;
1392
1393int __init
1394stifb_setup(char *options);
1395
1396static int __init stifb_init(void)
1397{
1398        struct sti_struct *sti;
1399        struct sti_struct *def_sti;
1400        int i;
1401        
1402#ifndef MODULE
1403        char *option = NULL;
1404
1405        if (fb_get_options("stifb", &option))
1406                return -ENODEV;
1407        stifb_setup(option);
1408#endif
1409        if (stifb_disabled) {
1410                printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1411                return -ENXIO;
1412        }
1413        
1414        def_sti = sti_get_rom(0);
1415        if (def_sti) {
1416                for (i = 1; i <= MAX_STI_ROMS; i++) {
1417                        sti = sti_get_rom(i);
1418                        if (!sti)
1419                                break;
1420                        if (sti == def_sti) {
1421                                stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1422                                break;
1423                        }
1424                }
1425        }
1426
1427        for (i = 1; i <= MAX_STI_ROMS; i++) {
1428                sti = sti_get_rom(i);
1429                if (!sti)
1430                        break;
1431                if (sti == def_sti)
1432                        continue;
1433                stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1434        }
1435        return 0;
1436}
1437
1438/*
1439 *  Cleanup
1440 */
1441
1442static void __exit
1443stifb_cleanup(void)
1444{
1445        struct sti_struct *sti;
1446        int i;
1447        
1448        for (i = 1; i <= MAX_STI_ROMS; i++) {
1449                sti = sti_get_rom(i);
1450                if (!sti)
1451                        break;
1452                if (sti->info) {
1453                        struct fb_info *info = sti->info;
1454                        unregister_framebuffer(sti->info);
1455                        release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1456                        release_mem_region(info->fix.smem_start, info->fix.smem_len);
1457                                if (info->screen_base)
1458                                        iounmap(info->screen_base);
1459                        fb_dealloc_cmap(&info->cmap);
1460                        framebuffer_release(info);
1461                }
1462                sti->info = NULL;
1463        }
1464}
1465
1466int __init
1467stifb_setup(char *options)
1468{
1469        int i;
1470        
1471        if (!options || !*options)
1472                return 1;
1473        
1474        if (strncmp(options, "off", 3) == 0) {
1475                stifb_disabled = 1;
1476                options += 3;
1477        }
1478
1479        if (strncmp(options, "bpp", 3) == 0) {
1480                options += 3;
1481                for (i = 0; i < MAX_STI_ROMS; i++) {
1482                        if (*options++ != ':')
1483                                break;
1484                        stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1485                }
1486        }
1487        return 1;
1488}
1489
1490__setup("stifb=", stifb_setup);
1491
1492module_init(stifb_init);
1493module_exit(stifb_cleanup);
1494
1495MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1496MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1497MODULE_LICENSE("GPL v2");
1498