Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * linux/drivers/video/stifb.c - 
0003  * Low level Frame buffer driver for HP workstations with 
0004  * STI (standard text interface) video firmware.
0005  *
0006  * Copyright (C) 2001-2006 Helge Deller <deller@gmx.de>
0007  * Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
0008  * 
0009  * Based on:
0010  * - linux/drivers/video/artistfb.c -- Artist frame buffer driver
0011  *  Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
0012  *   - based on skeletonfb, which was
0013  *  Created 28 Dec 1997 by Geert Uytterhoeven
0014  * - HP Xhp cfb-based X11 window driver for XFree86
0015  *  (c)Copyright 1992 Hewlett-Packard Co.
0016  *
0017  * 
0018  *  The following graphics display devices (NGLE family) are supported by this driver:
0019  *
0020  *  HPA4070A    known as "HCRX", a 1280x1024 color device with 8 planes
0021  *  HPA4071A    known as "HCRX24", a 1280x1024 color device with 24 planes,
0022  *      optionally available with a hardware accelerator as HPA4071A_Z
0023  *  HPA1659A    known as "CRX", a 1280x1024 color device with 8 planes
0024  *  HPA1439A    known as "CRX24", a 1280x1024 color device with 24 planes,
0025  *      optionally available with a hardware accelerator.
0026  *  HPA1924A    known as "GRX", a 1280x1024 grayscale device with 8 planes
0027  *  HPA2269A    known as "Dual CRX", a 1280x1024 color device with 8 planes,
0028  *      implements support for two displays on a single graphics card.
0029  *  HP710C  internal graphics support optionally available on the HP9000s710 SPU,
0030  *      supports 1280x1024 color displays with 8 planes.
0031  *  HP710G  same as HP710C, 1280x1024 grayscale only
0032  *  HP710L  same as HP710C, 1024x768 color only
0033  *  HP712   internal graphics support on HP9000s712 SPU, supports 640x480, 
0034  *      1024x768 or 1280x1024 color displays on 8 planes (Artist)
0035  *
0036  * This file is subject to the terms and conditions of the GNU General Public
0037  * License.  See the file COPYING in the main directory of this archive
0038  * for more details.
0039  */
0040 
0041 /* TODO:
0042  *  - 1bpp mode is completely untested
0043  *  - add support for h/w acceleration
0044  *  - add hardware cursor
0045  *  - automatically disable double buffering (e.g. on RDI precisionbook laptop)
0046  */
0047 
0048 
0049 /* on supported graphic devices you may:
0050  * #define FALLBACK_TO_1BPP to fall back to 1 bpp, or
0051  * #undef  FALLBACK_TO_1BPP to reject support for unsupported cards */
0052 #undef FALLBACK_TO_1BPP
0053 
0054 #undef DEBUG_STIFB_REGS     /* debug sti register accesses */
0055 
0056 
0057 #include <linux/module.h>
0058 #include <linux/kernel.h>
0059 #include <linux/errno.h>
0060 #include <linux/string.h>
0061 #include <linux/mm.h>
0062 #include <linux/slab.h>
0063 #include <linux/delay.h>
0064 #include <linux/fb.h>
0065 #include <linux/init.h>
0066 #include <linux/ioport.h>
0067 #include <linux/io.h>
0068 
0069 #include <asm/grfioctl.h>   /* for HP-UX compatibility */
0070 #include <linux/uaccess.h>
0071 
0072 #include "sticore.h"
0073 
0074 /* REGION_BASE(fb_info, index) returns the virtual address for region <index> */
0075 #define REGION_BASE(fb_info, index) \
0076     F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index])
0077 
0078 #define NGLEDEVDEPROM_CRT_REGION 1
0079 
0080 #define NR_PALETTE 256
0081 
0082 typedef struct {
0083     __s32   video_config_reg;
0084     __s32   misc_video_start;
0085     __s32   horiz_timing_fmt;
0086     __s32   serr_timing_fmt;
0087     __s32   vert_timing_fmt;
0088     __s32   horiz_state;
0089     __s32   vert_state;
0090     __s32   vtg_state_elements;
0091     __s32   pipeline_delay;
0092     __s32   misc_video_end;
0093 } video_setup_t;
0094 
0095 typedef struct {                  
0096     __s16   sizeof_ngle_data;
0097     __s16   x_size_visible;     /* visible screen dim in pixels  */
0098     __s16   y_size_visible;
0099     __s16   pad2[15];
0100     __s16   cursor_pipeline_delay;
0101     __s16   video_interleaves;
0102     __s32   pad3[11];
0103 } ngle_rom_t;
0104 
0105 struct stifb_info {
0106     struct fb_info info;
0107     unsigned int id;
0108     ngle_rom_t ngle_rom;
0109     struct sti_struct *sti;
0110     int deviceSpecificConfig;
0111     u32 pseudo_palette[16];
0112 };
0113 
0114 static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
0115 
0116 /* ------------------- chipset specific functions -------------------------- */
0117 
0118 /* offsets to graphic-chip internal registers */
0119 
0120 #define REG_1       0x000118
0121 #define REG_2       0x000480
0122 #define REG_3       0x0004a0
0123 #define REG_4       0x000600
0124 #define REG_6       0x000800
0125 #define REG_7       0x000804
0126 #define REG_8       0x000820
0127 #define REG_9       0x000a04
0128 #define REG_10      0x018000
0129 #define REG_11      0x018004
0130 #define REG_12      0x01800c
0131 #define REG_13      0x018018
0132 #define REG_14      0x01801c
0133 #define REG_15      0x200000
0134 #define REG_15b0    0x200000
0135 #define REG_16b1    0x200005
0136 #define REG_16b3    0x200007
0137 #define REG_21      0x200218
0138 #define REG_22      0x0005a0
0139 #define REG_23      0x0005c0
0140 #define REG_24      0x000808
0141 #define REG_25      0x000b00
0142 #define REG_26      0x200118
0143 #define REG_27      0x200308
0144 #define REG_32      0x21003c
0145 #define REG_33      0x210040
0146 #define REG_34      0x200008
0147 #define REG_35      0x018010
0148 #define REG_38      0x210020
0149 #define REG_39      0x210120
0150 #define REG_40      0x210130
0151 #define REG_42      0x210028
0152 #define REG_43      0x21002c
0153 #define REG_44      0x210030
0154 #define REG_45      0x210034
0155 
0156 #define READ_BYTE(fb,reg)       gsc_readb((fb)->info.fix.mmio_start + (reg))
0157 #define READ_WORD(fb,reg)       gsc_readl((fb)->info.fix.mmio_start + (reg))
0158 
0159 
0160 #ifndef DEBUG_STIFB_REGS
0161 # define  DEBUG_OFF()
0162 # define  DEBUG_ON()
0163 # define WRITE_BYTE(value,fb,reg)   gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
0164 # define WRITE_WORD(value,fb,reg)   gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
0165 #else
0166   static int debug_on = 1;
0167 # define  DEBUG_OFF() debug_on=0
0168 # define  DEBUG_ON()  debug_on=1
0169 # define WRITE_BYTE(value,fb,reg)   do { if (debug_on) \
0170                         printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
0171                             __func__, reg, value, READ_BYTE(fb,reg));         \
0172                     gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
0173 # define WRITE_WORD(value,fb,reg)   do { if (debug_on) \
0174                         printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
0175                             __func__, reg, value, READ_WORD(fb,reg));         \
0176                     gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
0177 #endif /* DEBUG_STIFB_REGS */
0178 
0179 
0180 #define ENABLE  1   /* for enabling/disabling screen */ 
0181 #define DISABLE 0
0182 
0183 #define NGLE_LOCK(fb_info)  do { } while (0) 
0184 #define NGLE_UNLOCK(fb_info)    do { } while (0)
0185 
0186 static void
0187 SETUP_HW(struct stifb_info *fb)
0188 {
0189     char stat;
0190 
0191     do {
0192         stat = READ_BYTE(fb, REG_15b0);
0193         if (!stat)
0194                 stat = READ_BYTE(fb, REG_15b0);
0195     } while (stat);
0196 }
0197 
0198 
0199 static void
0200 SETUP_FB(struct stifb_info *fb)
0201 {   
0202     unsigned int reg10_value = 0;
0203     
0204     SETUP_HW(fb);
0205     switch (fb->id)
0206     {
0207         case CRT_ID_VISUALIZE_EG:
0208         case S9000_ID_ARTIST:
0209         case S9000_ID_A1659A:
0210             reg10_value = 0x13601000;
0211             break;
0212         case S9000_ID_A1439A:
0213             if (fb->info.var.bits_per_pixel == 32)                      
0214                 reg10_value = 0xBBA0A000;
0215             else 
0216                 reg10_value = 0x13601000;
0217             break;
0218         case S9000_ID_HCRX:
0219             if (fb->info.var.bits_per_pixel == 32)
0220                 reg10_value = 0xBBA0A000;
0221             else                    
0222                 reg10_value = 0x13602000;
0223             break;
0224         case S9000_ID_TIMBER:
0225         case CRX24_OVERLAY_PLANES:
0226             reg10_value = 0x13602000;
0227             break;
0228     }
0229     if (reg10_value)
0230         WRITE_WORD(reg10_value, fb, REG_10);
0231     WRITE_WORD(0x83000300, fb, REG_14);
0232     SETUP_HW(fb);
0233     WRITE_BYTE(1, fb, REG_16b1);
0234 }
0235 
0236 static void
0237 START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
0238 {
0239     SETUP_HW(fb);
0240     WRITE_WORD(0xBBE0F000, fb, REG_10);
0241     WRITE_WORD(0x03000300, fb, REG_14);
0242     WRITE_WORD(~0, fb, REG_13);
0243 }
0244 
0245 static void
0246 WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color) 
0247 {
0248     SETUP_HW(fb);
0249     WRITE_WORD(((0x100+index)<<2), fb, REG_3);
0250     WRITE_WORD(color, fb, REG_4);
0251 }
0252 
0253 static void
0254 FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) 
0255 {       
0256     WRITE_WORD(0x400, fb, REG_2);
0257     if (fb->info.var.bits_per_pixel == 32) {
0258         WRITE_WORD(0x83000100, fb, REG_1);
0259     } else {
0260         if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
0261             WRITE_WORD(0x80000100, fb, REG_26);
0262         else                            
0263             WRITE_WORD(0x80000100, fb, REG_1);
0264     }
0265     SETUP_FB(fb);
0266 }
0267 
0268 static void
0269 SETUP_RAMDAC(struct stifb_info *fb) 
0270 {
0271     SETUP_HW(fb);
0272     WRITE_WORD(0x04000000, fb, 0x1020);
0273     WRITE_WORD(0xff000000, fb, 0x1028);
0274 }
0275 
0276 static void 
0277 CRX24_SETUP_RAMDAC(struct stifb_info *fb) 
0278 {
0279     SETUP_HW(fb);
0280     WRITE_WORD(0x04000000, fb, 0x1000);
0281     WRITE_WORD(0x02000000, fb, 0x1004);
0282     WRITE_WORD(0xff000000, fb, 0x1008);
0283     WRITE_WORD(0x05000000, fb, 0x1000);
0284     WRITE_WORD(0x02000000, fb, 0x1004);
0285     WRITE_WORD(0x03000000, fb, 0x1008);
0286 }
0287 
0288 #if 0
0289 static void 
0290 HCRX_SETUP_RAMDAC(struct stifb_info *fb)
0291 {
0292     WRITE_WORD(0xffffffff, fb, REG_32);
0293 }
0294 #endif
0295 
0296 static void 
0297 CRX24_SET_OVLY_MASK(struct stifb_info *fb)
0298 {
0299     SETUP_HW(fb);
0300     WRITE_WORD(0x13a02000, fb, REG_11);
0301     WRITE_WORD(0x03000300, fb, REG_14);
0302     WRITE_WORD(0x000017f0, fb, REG_3);
0303     WRITE_WORD(0xffffffff, fb, REG_13);
0304     WRITE_WORD(0xffffffff, fb, REG_22);
0305     WRITE_WORD(0x00000000, fb, REG_23);
0306 }
0307 
0308 static void
0309 ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
0310 {
0311     unsigned int value = enable ? 0x43000000 : 0x03000000;
0312         SETUP_HW(fb);
0313         WRITE_WORD(0x06000000,  fb, 0x1030);
0314         WRITE_WORD(value,   fb, 0x1038);
0315 }
0316 
0317 static void 
0318 CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
0319 {
0320     unsigned int value = enable ? 0x10000000 : 0x30000000;
0321     SETUP_HW(fb);
0322     WRITE_WORD(0x01000000,  fb, 0x1000);
0323     WRITE_WORD(0x02000000,  fb, 0x1004);
0324     WRITE_WORD(value,   fb, 0x1008);
0325 }
0326 
0327 static void
0328 ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) 
0329 {
0330     u32 DregsMiscVideo = REG_21;
0331     u32 DregsMiscCtl = REG_27;
0332     
0333     SETUP_HW(fb);
0334     if (enable) {
0335       WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
0336       WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   | 0x00800000, fb, DregsMiscCtl);
0337     } else {
0338       WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
0339       WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   & ~0x00800000, fb, DregsMiscCtl);
0340     }
0341 }
0342 
0343 #define GET_ROMTABLE_INDEX(fb) \
0344     (READ_BYTE(fb, REG_16b3) - 1)
0345 
0346 #define HYPER_CONFIG_PLANES_24 0x00000100
0347     
0348 #define IS_24_DEVICE(fb) \
0349     (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
0350 
0351 #define IS_888_DEVICE(fb) \
0352     (!(IS_24_DEVICE(fb)))
0353 
0354 #define GET_FIFO_SLOTS(fb, cnt, numslots)   \
0355 {   while (cnt < numslots)          \
0356         cnt = READ_WORD(fb, REG_34);    \
0357     cnt -= numslots;            \
0358 }
0359 
0360 #define     IndexedDcd  0   /* Pixel data is indexed (pseudo) color */
0361 #define     Otc04   2   /* Pixels in each longword transfer (4) */
0362 #define     Otc32   5   /* Pixels in each longword transfer (32) */
0363 #define     Ots08   3   /* Each pixel is size (8)d transfer (1) */
0364 #define     OtsIndirect 6   /* Each bit goes through FG/BG color(8) */
0365 #define     AddrLong    5   /* FB address is Long aligned (pixel) */
0366 #define     BINovly 0x2 /* 8 bit overlay */
0367 #define     BINapp0I    0x0 /* Application Buffer 0, Indexed */
0368 #define     BINapp1I    0x1 /* Application Buffer 1, Indexed */
0369 #define     BINapp0F8   0xa /* Application Buffer 0, Fractional 8-8-8 */
0370 #define     BINattr 0xd /* Attribute Bitmap */
0371 #define     RopSrc  0x3
0372 #define     BitmapExtent08  3   /* Each write hits ( 8) bits in depth */
0373 #define     BitmapExtent32  5   /* Each write hits (32) bits in depth */
0374 #define     DataDynamic     0   /* Data register reloaded by direct access */
0375 #define     MaskDynamic     1   /* Mask register reloaded by direct access */
0376 #define     MaskOtc     0   /* Mask contains Object Count valid bits */
0377 
0378 #define MaskAddrOffset(offset) (offset)
0379 #define StaticReg(en) (en)
0380 #define BGx(en) (en)
0381 #define FGx(en) (en)
0382 
0383 #define BAJustPoint(offset) (offset)
0384 #define BAIndexBase(base) (base)
0385 #define BA(F,C,S,A,J,B,I) \
0386     (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
0387 
0388 #define IBOvals(R,M,X,S,D,L,B,F) \
0389     (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
0390 
0391 #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
0392     WRITE_WORD(val, fb, REG_14)
0393 
0394 #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
0395     WRITE_WORD(val, fb, REG_11)
0396 
0397 #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
0398     WRITE_WORD(val, fb, REG_12)
0399 
0400 #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
0401     WRITE_WORD(plnmsk32, fb, REG_13)
0402 
0403 #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
0404     WRITE_WORD(fg32, fb, REG_35)
0405 
0406 #define NGLE_SET_TRANSFERDATA(fb, val) \
0407     WRITE_WORD(val, fb, REG_8)
0408 
0409 #define NGLE_SET_DSTXY(fb, val) \
0410     WRITE_WORD(val, fb, REG_6)
0411 
0412 #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) (        \
0413     (u32) (fbaddrbase) +                    \
0414         (   (unsigned int)  ( (y) << 13      ) |        \
0415         (unsigned int)  ( (x) << 2       )  )   \
0416     )
0417 
0418 #define NGLE_BINC_SET_DSTADDR(fb, addr) \
0419     WRITE_WORD(addr, fb, REG_3)
0420 
0421 #define NGLE_BINC_SET_SRCADDR(fb, addr) \
0422     WRITE_WORD(addr, fb, REG_2)
0423 
0424 #define NGLE_BINC_SET_DSTMASK(fb, mask) \
0425     WRITE_WORD(mask, fb, REG_22)
0426 
0427 #define NGLE_BINC_WRITE32(fb, data32) \
0428     WRITE_WORD(data32, fb, REG_23)
0429 
0430 #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
0431     WRITE_WORD((cmapBltCtlData32), fb, REG_38)
0432 
0433 #define SET_LENXY_START_RECFILL(fb, lenxy) \
0434     WRITE_WORD(lenxy, fb, REG_9)
0435 
0436 #define SETUP_COPYAREA(fb) \
0437     WRITE_BYTE(0, fb, REG_16b1)
0438 
0439 static void
0440 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
0441 {
0442     u32 DregsHypMiscVideo = REG_33;
0443     unsigned int value;
0444     SETUP_HW(fb);
0445     value = READ_WORD(fb, DregsHypMiscVideo);
0446     if (enable)
0447         value |= 0x0A000000;
0448     else
0449         value &= ~0x0A000000;
0450     WRITE_WORD(value, fb, DregsHypMiscVideo);
0451 }
0452 
0453 
0454 /* BufferNumbers used by SETUP_ATTR_ACCESS() */
0455 #define BUFF0_CMAP0 0x00001e02
0456 #define BUFF1_CMAP0 0x02001e02
0457 #define BUFF1_CMAP3 0x0c001e02
0458 #define ARTIST_CMAP0    0x00000102
0459 #define HYPER_CMAP8 0x00000100
0460 #define HYPER_CMAP24    0x00000800
0461 
0462 static void
0463 SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
0464 {
0465     SETUP_HW(fb);
0466     WRITE_WORD(0x2EA0D000, fb, REG_11);
0467     WRITE_WORD(0x23000302, fb, REG_14);
0468     WRITE_WORD(BufferNumber, fb, REG_12);
0469     WRITE_WORD(0xffffffff, fb, REG_8);
0470 }
0471 
0472 static void
0473 SET_ATTR_SIZE(struct stifb_info *fb, int width, int height) 
0474 {
0475     /* REG_6 seems to have special values when run on a 
0476        RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
0477        INTERNAL_EG_X1024).  The values are:
0478         0x2f0: internal (LCD) & external display enabled
0479         0x2a0: external display only
0480         0x000: zero on standard artist graphic cards
0481     */ 
0482     WRITE_WORD(0x00000000, fb, REG_6);
0483     WRITE_WORD((width<<16) | height, fb, REG_9);
0484     WRITE_WORD(0x05000000, fb, REG_6);
0485     WRITE_WORD(0x00040001, fb, REG_9);
0486 }
0487 
0488 static void
0489 FINISH_ATTR_ACCESS(struct stifb_info *fb) 
0490 {
0491     SETUP_HW(fb);
0492     WRITE_WORD(0x00000000, fb, REG_12);
0493 }
0494 
0495 static void
0496 elkSetupPlanes(struct stifb_info *fb)
0497 {
0498     SETUP_RAMDAC(fb);
0499     SETUP_FB(fb);
0500 }
0501 
0502 static void 
0503 ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
0504 {
0505     SETUP_ATTR_ACCESS(fb, BufferNumber);
0506     SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
0507     FINISH_ATTR_ACCESS(fb);
0508     SETUP_FB(fb);
0509 }
0510 
0511 
0512 static void
0513 rattlerSetupPlanes(struct stifb_info *fb)
0514 {
0515     int saved_id, y;
0516 
0517     /* Write RAMDAC pixel read mask register so all overlay
0518      * planes are display-enabled.  (CRX24 uses Bt462 pixel
0519      * read mask register for overlay planes, not image planes).
0520      */
0521     CRX24_SETUP_RAMDAC(fb);
0522     
0523     /* change fb->id temporarily to fool SETUP_FB() */
0524     saved_id = fb->id;
0525     fb->id = CRX24_OVERLAY_PLANES;
0526     SETUP_FB(fb);
0527     fb->id = saved_id;
0528 
0529     for (y = 0; y < fb->info.var.yres; ++y)
0530         fb_memset(fb->info.screen_base + y * fb->info.fix.line_length,
0531             0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8);
0532 
0533     CRX24_SET_OVLY_MASK(fb);
0534     SETUP_FB(fb);
0535 }
0536 
0537 
0538 #define HYPER_CMAP_TYPE             0
0539 #define NGLE_CMAP_INDEXED0_TYPE         0
0540 #define NGLE_CMAP_OVERLAY_TYPE          3
0541 
0542 /* typedef of LUT (Colormap) BLT Control Register */
0543 typedef union   /* Note assumption that fields are packed left-to-right */
0544 {   u32 all;
0545     struct
0546     {
0547         unsigned enable              :  1;
0548         unsigned waitBlank           :  1;
0549         unsigned reserved1           :  4;
0550         unsigned lutOffset           : 10;   /* Within destination LUT */
0551         unsigned lutType             :  2;   /* Cursor, image, overlay */
0552         unsigned reserved2           :  4;
0553         unsigned length              : 10;
0554     } fields;
0555 } NgleLutBltCtl;
0556 
0557 
0558 #if 0
0559 static NgleLutBltCtl
0560 setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
0561 {
0562     NgleLutBltCtl lutBltCtl;
0563 
0564     /* set enable, zero reserved fields */
0565     lutBltCtl.all           = 0x80000000;
0566     lutBltCtl.fields.length = length;
0567 
0568     switch (fb->id) 
0569     {
0570     case S9000_ID_A1439A:       /* CRX24 */
0571         if (fb->var.bits_per_pixel == 8) {
0572             lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
0573             lutBltCtl.fields.lutOffset = 0;
0574         } else {
0575             lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
0576             lutBltCtl.fields.lutOffset = 0 * 256;
0577         }
0578         break;
0579         
0580     case S9000_ID_ARTIST:
0581         lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
0582         lutBltCtl.fields.lutOffset = 0 * 256;
0583         break;
0584         
0585     default:
0586         lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
0587         lutBltCtl.fields.lutOffset = 0;
0588         break;
0589     }
0590 
0591     /* Offset points to start of LUT.  Adjust for within LUT */
0592     lutBltCtl.fields.lutOffset += offsetWithinLut;
0593 
0594     return lutBltCtl;
0595 }
0596 #endif
0597 
0598 static NgleLutBltCtl
0599 setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) 
0600 {
0601     NgleLutBltCtl lutBltCtl;
0602 
0603     /* set enable, zero reserved fields */
0604     lutBltCtl.all = 0x80000000;
0605 
0606     lutBltCtl.fields.length = length;
0607     lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
0608 
0609     /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
0610     if (fb->info.var.bits_per_pixel == 8)
0611         lutBltCtl.fields.lutOffset = 2 * 256;
0612     else
0613         lutBltCtl.fields.lutOffset = 0 * 256;
0614 
0615     /* Offset points to start of LUT.  Adjust for within LUT */
0616     lutBltCtl.fields.lutOffset += offsetWithinLut;
0617 
0618     return lutBltCtl;
0619 }
0620 
0621 
0622 static void hyperUndoITE(struct stifb_info *fb)
0623 {
0624     int nFreeFifoSlots = 0;
0625     u32 fbAddr;
0626 
0627     NGLE_LOCK(fb);
0628 
0629     GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
0630     WRITE_WORD(0xffffffff, fb, REG_32);
0631 
0632     /* Write overlay transparency mask so only entry 255 is transparent */
0633 
0634     /* Hardware setup for full-depth write to "magic" location */
0635     GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
0636     NGLE_QUICK_SET_DST_BM_ACCESS(fb, 
0637         BA(IndexedDcd, Otc04, Ots08, AddrLong,
0638         BAJustPoint(0), BINovly, BAIndexBase(0)));
0639     NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
0640         IBOvals(RopSrc, MaskAddrOffset(0),
0641         BitmapExtent08, StaticReg(0),
0642         DataDynamic, MaskOtc, BGx(0), FGx(0)));
0643 
0644     /* Now prepare to write to the "magic" location */
0645     fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
0646     NGLE_BINC_SET_DSTADDR(fb, fbAddr);
0647     NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
0648     NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
0649 
0650     /* Finally, write a zero to clear the mask */
0651     NGLE_BINC_WRITE32(fb, 0);
0652 
0653     NGLE_UNLOCK(fb);
0654 }
0655 
0656 static void 
0657 ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
0658 {
0659     /* FIXME! */
0660 }
0661 
0662 static void 
0663 ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
0664 {
0665     /* FIXME! */
0666 }
0667 
0668 static void
0669 ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
0670 {
0671     int nFreeFifoSlots = 0;
0672     u32 packed_dst;
0673     u32 packed_len;
0674 
0675     NGLE_LOCK(fb);
0676 
0677     GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
0678     NGLE_QUICK_SET_DST_BM_ACCESS(fb, 
0679                      BA(IndexedDcd, Otc32, OtsIndirect,
0680                     AddrLong, BAJustPoint(0),
0681                     BINattr, BAIndexBase(0)));
0682     NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
0683     NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
0684 
0685     NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
0686                        IBOvals(RopSrc, MaskAddrOffset(0),
0687                            BitmapExtent08, StaticReg(1),
0688                            DataDynamic, MaskOtc,
0689                            BGx(0), FGx(0)));
0690     packed_dst = 0;
0691     packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
0692     GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
0693     NGLE_SET_DSTXY(fb, packed_dst);
0694     SET_LENXY_START_RECFILL(fb, packed_len);
0695 
0696     /*
0697      * In order to work around an ELK hardware problem (Buffy doesn't
0698      * always flush it's buffers when writing to the attribute
0699      * planes), at least 4 pixels must be written to the attribute
0700      * planes starting at (X == 1280) and (Y != to the last Y written
0701      * by BIF):
0702      */
0703 
0704     if (fb->id == S9000_ID_A1659A) {   /* ELK_DEVICE_ID */
0705         /* It's safe to use scanline zero: */
0706         packed_dst = (1280 << 16);
0707         GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
0708         NGLE_SET_DSTXY(fb, packed_dst);
0709         packed_len = (4 << 16) | 1;
0710         SET_LENXY_START_RECFILL(fb, packed_len);
0711     }   /* ELK Hardware Kludge */
0712 
0713     /**** Finally, set the Control Plane Register back to zero: ****/
0714     GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
0715     NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
0716     
0717     NGLE_UNLOCK(fb);
0718 }
0719     
0720 static void
0721 ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
0722 {
0723     int nFreeFifoSlots = 0;
0724     u32 packed_dst;
0725     u32 packed_len;
0726     
0727     NGLE_LOCK(fb);
0728 
0729     /* Hardware setup */
0730     GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
0731     NGLE_QUICK_SET_DST_BM_ACCESS(fb, 
0732                      BA(IndexedDcd, Otc04, Ots08, AddrLong,
0733                     BAJustPoint(0), BINovly, BAIndexBase(0)));
0734 
0735         NGLE_SET_TRANSFERDATA(fb, 0xffffffff);  /* Write foreground color */
0736 
0737         NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
0738         NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
0739     
0740         packed_dst = 0;
0741         packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
0742         NGLE_SET_DSTXY(fb, packed_dst);
0743     
0744         /* Write zeroes to overlay planes */               
0745     NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
0746                        IBOvals(RopSrc, MaskAddrOffset(0),
0747                            BitmapExtent08, StaticReg(0),
0748                            DataDynamic, MaskOtc, BGx(0), FGx(0)));
0749                
0750         SET_LENXY_START_RECFILL(fb, packed_len);
0751 
0752     NGLE_UNLOCK(fb);
0753 }
0754 
0755 static void 
0756 hyperResetPlanes(struct stifb_info *fb, int enable)
0757 {
0758     unsigned int controlPlaneReg;
0759 
0760     NGLE_LOCK(fb);
0761 
0762     if (IS_24_DEVICE(fb))
0763         if (fb->info.var.bits_per_pixel == 32)
0764             controlPlaneReg = 0x04000F00;
0765         else
0766             controlPlaneReg = 0x00000F00;   /* 0x00000800 should be enough, but lets clear all 4 bits */
0767     else
0768         controlPlaneReg = 0x00000F00; /* 0x00000100 should be enough, but lets clear all 4 bits */
0769 
0770     switch (enable) {
0771     case ENABLE:
0772         /* clear screen */
0773         if (IS_24_DEVICE(fb))
0774             ngleDepth24_ClearImagePlanes(fb);
0775         else
0776             ngleDepth8_ClearImagePlanes(fb);
0777 
0778         /* Paint attribute planes for default case.
0779          * On Hyperdrive, this means all windows using overlay cmap 0. */
0780         ngleResetAttrPlanes(fb, controlPlaneReg);
0781 
0782         /* clear overlay planes */
0783             ngleClearOverlayPlanes(fb, 0xff, 255);
0784 
0785         /**************************************************
0786          ** Also need to counteract ITE settings 
0787          **************************************************/
0788         hyperUndoITE(fb);
0789         break;
0790 
0791     case DISABLE:
0792         /* clear screen */
0793         if (IS_24_DEVICE(fb))
0794             ngleDepth24_ClearImagePlanes(fb);
0795         else
0796             ngleDepth8_ClearImagePlanes(fb);
0797         ngleResetAttrPlanes(fb, controlPlaneReg);
0798         ngleClearOverlayPlanes(fb, 0xff, 0);
0799         break;
0800 
0801     case -1:    /* RESET */
0802         hyperUndoITE(fb);
0803         ngleResetAttrPlanes(fb, controlPlaneReg);
0804         break;
0805         }
0806     
0807     NGLE_UNLOCK(fb);
0808 }
0809 
0810 /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
0811 
0812 static void 
0813 ngleGetDeviceRomData(struct stifb_info *fb)
0814 {
0815 #if 0
0816 XXX: FIXME: !!!
0817     int *pBytePerLongDevDepData;/* data byte == LSB */
0818     int     *pRomTable;
0819     NgleDevRomData  *pPackedDevRomData;
0820     int sizePackedDevRomData = sizeof(*pPackedDevRomData);
0821     char    *pCard8;
0822     int i;
0823     char    *mapOrigin = NULL;
0824     
0825     int romTableIdx;
0826 
0827     pPackedDevRomData = fb->ngle_rom;
0828 
0829     SETUP_HW(fb);
0830     if (fb->id == S9000_ID_ARTIST) {
0831         pPackedDevRomData->cursor_pipeline_delay = 4;
0832         pPackedDevRomData->video_interleaves     = 4;
0833     } else {
0834         /* Get pointer to unpacked byte/long data in ROM */
0835         pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
0836 
0837         /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
0838         if (fb->id == S9000_ID_TOMCAT)
0839     {
0840         /*  jump to the correct ROM table  */
0841         GET_ROMTABLE_INDEX(romTableIdx);
0842         while  (romTableIdx > 0)
0843         {
0844         pCard8 = (Card8 *) pPackedDevRomData;
0845         pRomTable = pBytePerLongDevDepData;
0846         /* Pack every fourth byte from ROM into structure */
0847         for (i = 0; i < sizePackedDevRomData; i++)
0848         {
0849             *pCard8++ = (Card8) (*pRomTable++);
0850         }
0851 
0852         pBytePerLongDevDepData = (Card32 *)
0853             ((Card8 *) pBytePerLongDevDepData +
0854                    pPackedDevRomData->sizeof_ngle_data);
0855 
0856         romTableIdx--;
0857         }
0858     }
0859 
0860     pCard8 = (Card8 *) pPackedDevRomData;
0861 
0862     /* Pack every fourth byte from ROM into structure */
0863     for (i = 0; i < sizePackedDevRomData; i++)
0864     {
0865         *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
0866     }
0867     }
0868 
0869     SETUP_FB(fb);
0870 #endif
0871 }
0872 
0873 
0874 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
0875 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE  8
0876 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE       10
0877 #define HYPERBOWL_MODE2_8_24                    15
0878 
0879 /* HCRX specific boot-time initialization */
0880 static void __init
0881 SETUP_HCRX(struct stifb_info *fb)
0882 {
0883     int hyperbowl;
0884         int nFreeFifoSlots = 0;
0885 
0886     if (fb->id != S9000_ID_HCRX)
0887         return;
0888 
0889     /* Initialize Hyperbowl registers */
0890     GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
0891     
0892     if (IS_24_DEVICE(fb)) {
0893         hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
0894             HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
0895             HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
0896 
0897         /* First write to Hyperbowl must happen twice (bug) */
0898         WRITE_WORD(hyperbowl, fb, REG_40);
0899         WRITE_WORD(hyperbowl, fb, REG_40);
0900         
0901         WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
0902         
0903         WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
0904         WRITE_WORD(0x404c4048, fb, REG_43);
0905         WRITE_WORD(0x034c0348, fb, REG_44);
0906         WRITE_WORD(0x444c4448, fb, REG_45);
0907     } else {
0908         hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
0909 
0910         /* First write to Hyperbowl must happen twice (bug) */
0911         WRITE_WORD(hyperbowl, fb, REG_40);
0912         WRITE_WORD(hyperbowl, fb, REG_40);
0913 
0914         WRITE_WORD(0x00000000, fb, REG_42);
0915         WRITE_WORD(0x00000000, fb, REG_43);
0916         WRITE_WORD(0x00000000, fb, REG_44);
0917         WRITE_WORD(0x444c4048, fb, REG_45);
0918     }
0919 }
0920 
0921 
0922 /* ------------------- driver specific functions --------------------------- */
0923 
0924 static int
0925 stifb_setcolreg(u_int regno, u_int red, u_int green,
0926           u_int blue, u_int transp, struct fb_info *info)
0927 {
0928     struct stifb_info *fb = container_of(info, struct stifb_info, info);
0929     u32 color;
0930 
0931     if (regno >= NR_PALETTE)
0932         return 1;
0933 
0934     red   >>= 8;
0935     green >>= 8;
0936     blue  >>= 8;
0937 
0938     DEBUG_OFF();
0939 
0940     START_IMAGE_COLORMAP_ACCESS(fb);
0941 
0942     if (unlikely(fb->info.var.grayscale)) {
0943         /* gray = 0.30*R + 0.59*G + 0.11*B */
0944         color = ((red * 77) +
0945              (green * 151) +
0946              (blue * 28)) >> 8;
0947     } else {
0948         color = ((red << 16) |
0949              (green << 8) |
0950              (blue));
0951     }
0952 
0953     if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
0954         struct fb_var_screeninfo *var = &fb->info.var;
0955         if (regno < 16)
0956             ((u32 *)fb->info.pseudo_palette)[regno] =
0957                 regno << var->red.offset |
0958                 regno << var->green.offset |
0959                 regno << var->blue.offset;
0960     }
0961 
0962     WRITE_IMAGE_COLOR(fb, regno, color);
0963 
0964     if (fb->id == S9000_ID_HCRX) {
0965         NgleLutBltCtl lutBltCtl;
0966 
0967         lutBltCtl = setHyperLutBltCtl(fb,
0968                 0,  /* Offset w/i LUT */
0969                 256);   /* Load entire LUT */
0970         NGLE_BINC_SET_SRCADDR(fb,
0971                 NGLE_LONG_FB_ADDRESS(0, 0x100, 0)); 
0972                 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
0973         START_COLORMAPLOAD(fb, lutBltCtl.all);
0974         SETUP_FB(fb);
0975     } else {
0976         /* cleanup colormap hardware */
0977         FINISH_IMAGE_COLORMAP_ACCESS(fb);
0978     }
0979 
0980     DEBUG_ON();
0981 
0982     return 0;
0983 }
0984 
0985 static int
0986 stifb_blank(int blank_mode, struct fb_info *info)
0987 {
0988     struct stifb_info *fb = container_of(info, struct stifb_info, info);
0989     int enable = (blank_mode == 0) ? ENABLE : DISABLE;
0990 
0991     switch (fb->id) {
0992     case S9000_ID_A1439A:
0993         CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
0994         break;
0995     case CRT_ID_VISUALIZE_EG:
0996     case S9000_ID_ARTIST:
0997         ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
0998         break;
0999     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 
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 #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 
1053 static void
1054 stifb_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 
1085 static void __init
1086 stifb_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 
1145 static 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 
1159 static 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     /* save for primary gfx device detection & unregister_framebuffer() */
1362     sti->info = info;
1363     if (register_framebuffer(&fb->info) < 0)
1364         goto out_err4;
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 
1378 out_err4:
1379     release_mem_region(fix->mmio_start, fix->mmio_len);
1380 out_err3:
1381     release_mem_region(fix->smem_start, fix->smem_len);
1382 out_err2:
1383     fb_dealloc_cmap(&info->cmap);
1384 out_err1:
1385     iounmap(info->screen_base);
1386 out_err0:
1387     kfree(fb);
1388     return -ENXIO;
1389 }
1390 
1391 static int stifb_disabled __initdata;
1392 
1393 int __init
1394 stifb_setup(char *options);
1395 
1396 static 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 
1442 static void __exit
1443 stifb_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 
1466 int __init
1467 stifb_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 
1492 module_init(stifb_init);
1493 module_exit(stifb_cleanup);
1494 
1495 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1496 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1497 MODULE_LICENSE("GPL v2");