cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

stifb.c (39034B)


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