root/drivers/video/fbdev/stifb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. SETUP_HW
  2. SETUP_FB
  3. START_IMAGE_COLORMAP_ACCESS
  4. WRITE_IMAGE_COLOR
  5. FINISH_IMAGE_COLORMAP_ACCESS
  6. SETUP_RAMDAC
  7. CRX24_SETUP_RAMDAC
  8. HCRX_SETUP_RAMDAC
  9. CRX24_SET_OVLY_MASK
  10. ENABLE_DISABLE_DISPLAY
  11. CRX24_ENABLE_DISABLE_DISPLAY
  12. ARTIST_ENABLE_DISABLE_DISPLAY
  13. HYPER_ENABLE_DISABLE_DISPLAY
  14. SETUP_ATTR_ACCESS
  15. SET_ATTR_SIZE
  16. FINISH_ATTR_ACCESS
  17. elkSetupPlanes
  18. ngleSetupAttrPlanes
  19. rattlerSetupPlanes
  20. setNgleLutBltCtl
  21. setHyperLutBltCtl
  22. hyperUndoITE
  23. ngleDepth8_ClearImagePlanes
  24. ngleDepth24_ClearImagePlanes
  25. ngleResetAttrPlanes
  26. ngleClearOverlayPlanes
  27. hyperResetPlanes
  28. ngleGetDeviceRomData
  29. SETUP_HCRX
  30. stifb_setcolreg
  31. stifb_blank
  32. stifb_copyarea
  33. stifb_init_display
  34. stifb_init_fb
  35. stifb_init
  36. stifb_cleanup
  37. stifb_setup

   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 
  82 typedef 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 
  95 typedef 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 
 105 struct 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 
 114 static 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 
 186 static void
 187 SETUP_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 
 199 static void
 200 SETUP_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 
 236 static void
 237 START_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 
 245 static void
 246 WRITE_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 
 253 static void
 254 FINISH_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 
 268 static void
 269 SETUP_RAMDAC(struct stifb_info *fb) 
 270 {
 271         SETUP_HW(fb);
 272         WRITE_WORD(0x04000000, fb, 0x1020);
 273         WRITE_WORD(0xff000000, fb, 0x1028);
 274 }
 275 
 276 static void 
 277 CRX24_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
 289 static void 
 290 HCRX_SETUP_RAMDAC(struct stifb_info *fb)
 291 {
 292         WRITE_WORD(0xffffffff, fb, REG_32);
 293 }
 294 #endif
 295 
 296 static void 
 297 CRX24_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 
 308 static void
 309 ENABLE_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 
 317 static void 
 318 CRX24_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 
 327 static void
 328 ARTIST_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 
 439 static void
 440 HYPER_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 
 462 static void
 463 SETUP_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 
 472 static void
 473 SET_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 
 488 static void
 489 FINISH_ATTR_ACCESS(struct stifb_info *fb) 
 490 {
 491         SETUP_HW(fb);
 492         WRITE_WORD(0x00000000, fb, REG_12);
 493 }
 494 
 495 static void
 496 elkSetupPlanes(struct stifb_info *fb)
 497 {
 498         SETUP_RAMDAC(fb);
 499         SETUP_FB(fb);
 500 }
 501 
 502 static void 
 503 ngleSetupAttrPlanes(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 
 512 static void
 513 rattlerSetupPlanes(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 */
 543 typedef 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
 559 static NgleLutBltCtl
 560 setNgleLutBltCtl(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 
 598 static NgleLutBltCtl
 599 setHyperLutBltCtl(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 
 622 static 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 
 656 static void 
 657 ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
 658 {
 659         /* FIXME! */
 660 }
 661 
 662 static void 
 663 ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
 664 {
 665         /* FIXME! */
 666 }
 667 
 668 static void
 669 ngleResetAttrPlanes(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     
 720 static void
 721 ngleClearOverlayPlanes(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 
 755 static void 
 756 hyperResetPlanes(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 
 812 static void 
 813 ngleGetDeviceRomData(struct stifb_info *fb)
 814 {
 815 #if 0
 816 XXX: 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 */
 880 static void __init
 881 SETUP_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 
 924 static int
 925 stifb_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 
 985 static int
 986 stifb_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 
1014 static void
1015 stifb_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 static void __init
1045 stifb_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 
1104 static 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 
1118 static 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 
1337 out_err4:
1338         release_mem_region(fix->mmio_start, fix->mmio_len);
1339 out_err3:
1340         release_mem_region(fix->smem_start, fix->smem_len);
1341 out_err2:
1342         fb_dealloc_cmap(&info->cmap);
1343 out_err1:
1344         iounmap(info->screen_base);
1345 out_err0:
1346         kfree(fb);
1347         return -ENXIO;
1348 }
1349 
1350 static int stifb_disabled __initdata;
1351 
1352 int __init
1353 stifb_setup(char *options);
1354 
1355 static 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 
1401 static void __exit
1402 stifb_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 
1425 int __init
1426 stifb_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 
1451 module_init(stifb_init);
1452 module_exit(stifb_cleanup);
1453 
1454 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1455 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1456 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */