File Index
Files and directories
Sign in
FILE

stifb.c

File preview with syntax highlighting.

linux-6.19.14/drivers/video/fbdev/stifb.c C
   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 <video/sticore.h>
  73
  74/* REGION_BASE(fb_info, index) returns the physical address for region <index> */
  75#define REGION_BASE(fb_info, index) \
  76	F_EXTEND(fb_info->sti->regions_phys[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_io(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_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 926{
 927	struct stifb_info *fb = info->par;
 928
 929	if (var->xres != fb->info->var.xres ||
 930	    var->yres != fb->info->var.yres ||
 931	    var->bits_per_pixel != fb->info->var.bits_per_pixel)
 932		return -EINVAL;
 933
 934	var->xres_virtual = var->xres;
 935	var->yres_virtual = var->yres;
 936	var->xoffset = 0;
 937	var->yoffset = 0;
 938	var->grayscale = fb->info->var.grayscale;
 939	var->red.length = fb->info->var.red.length;
 940	var->green.length = fb->info->var.green.length;
 941	var->blue.length = fb->info->var.blue.length;
 942
 943	return 0;
 944}
 945
 946static int
 947stifb_setcolreg(u_int regno, u_int red, u_int green,
 948	      u_int blue, u_int transp, struct fb_info *info)
 949{
 950	struct stifb_info *fb = info->par;
 951	u32 color;
 952
 953	if (regno >= NR_PALETTE)
 954		return 1;
 955
 956	red   >>= 8;
 957	green >>= 8;
 958	blue  >>= 8;
 959
 960	DEBUG_OFF();
 961
 962	START_IMAGE_COLORMAP_ACCESS(fb);
 963
 964	if (unlikely(fb->info->var.grayscale)) {
 965		/* gray = 0.30*R + 0.59*G + 0.11*B */
 966		color = ((red * 77) +
 967			 (green * 151) +
 968			 (blue * 28)) >> 8;
 969	} else {
 970		color = ((red << 16) |
 971			 (green << 8) |
 972			 (blue));
 973	}
 974
 975	if (fb->info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
 976		struct fb_var_screeninfo *var = &fb->info->var;
 977		if (regno < 16)
 978			((u32 *)fb->info->pseudo_palette)[regno] =
 979				regno << var->red.offset |
 980				regno << var->green.offset |
 981				regno << var->blue.offset;
 982	}
 983
 984	WRITE_IMAGE_COLOR(fb, regno, color);
 985
 986	if (fb->id == S9000_ID_HCRX) {
 987		NgleLutBltCtl lutBltCtl;
 988
 989		lutBltCtl = setHyperLutBltCtl(fb,
 990				0,	/* Offset w/i LUT */
 991				256);	/* Load entire LUT */
 992		NGLE_BINC_SET_SRCADDR(fb,
 993				NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
 994				/* 0x100 is same as used in WRITE_IMAGE_COLOR() */
 995		START_COLORMAPLOAD(fb, lutBltCtl.all);
 996		SETUP_FB(fb);
 997	} else {
 998		/* cleanup colormap hardware */
 999		FINISH_IMAGE_COLORMAP_ACCESS(fb);
1000	}
1001
1002	DEBUG_ON();
1003
1004	return 0;
1005}
1006
1007static int
1008stifb_blank(int blank_mode, struct fb_info *info)
1009{
1010	struct stifb_info *fb = info->par;
1011	int enable = (blank_mode == 0) ? ENABLE : DISABLE;
1012
1013	switch (fb->id) {
1014	case S9000_ID_A1439A:
1015		CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
1016		break;
1017	case CRT_ID_VISUALIZE_EG:
1018	case S9000_ID_ARTIST:
1019		ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
1020		break;
1021	case S9000_ID_HCRX:
1022		HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
1023		break;
1024	case S9000_ID_A1659A:
1025	case S9000_ID_TIMBER:
1026	case CRX24_OVERLAY_PLANES:
1027	default:
1028		ENABLE_DISABLE_DISPLAY(fb, enable);
1029		break;
1030	}
1031
1032	SETUP_FB(fb);
1033	return 0;
1034}
1035
1036static void
1037stifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1038{
1039	struct stifb_info *fb = info->par;
1040
1041	SETUP_COPYAREA(fb);
1042
1043	SETUP_HW(fb);
1044	if (fb->info->var.bits_per_pixel == 32) {
1045		WRITE_WORD(0xBBA0A000, fb, REG_10);
1046
1047		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
1048	} else {
1049		WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
1050
1051		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
1052	}
1053
1054	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
1055		IBOvals(RopSrc, MaskAddrOffset(0),
1056		BitmapExtent08, StaticReg(1),
1057		DataDynamic, MaskOtc, BGx(0), FGx(0)));
1058
1059	WRITE_WORD(((area->sx << 16) | area->sy), fb, REG_24);
1060	WRITE_WORD(((area->width << 16) | area->height), fb, REG_7);
1061	WRITE_WORD(((area->dx << 16) | area->dy), fb, REG_25);
1062
1063	SETUP_FB(fb);
1064}
1065
1066#define ARTIST_VRAM_SIZE			0x000804
1067#define ARTIST_VRAM_SRC				0x000808
1068#define ARTIST_VRAM_SIZE_TRIGGER_WINFILL	0x000a04
1069#define ARTIST_VRAM_DEST_TRIGGER_BLOCKMOVE	0x000b00
1070#define ARTIST_SRC_BM_ACCESS			0x018008
1071#define ARTIST_FGCOLOR				0x018010
1072#define ARTIST_BGCOLOR				0x018014
1073#define ARTIST_BITMAP_OP			0x01801c
1074
1075static void
1076stifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
1077{
1078	struct stifb_info *fb = info->par;
1079
1080	if (rect->rop != ROP_COPY ||
1081	    (fb->id == S9000_ID_HCRX && fb->info->var.bits_per_pixel == 32))
1082		return cfb_fillrect(info, rect);
1083
1084	SETUP_HW(fb);
1085
1086	if (fb->info->var.bits_per_pixel == 32) {
1087		WRITE_WORD(0xBBA0A000, fb, REG_10);
1088
1089		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
1090	} else {
1091		WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
1092
1093		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
1094	}
1095
1096	WRITE_WORD(0x03000300, fb, ARTIST_BITMAP_OP);
1097	WRITE_WORD(0x2ea01000, fb, ARTIST_SRC_BM_ACCESS);
1098	NGLE_QUICK_SET_DST_BM_ACCESS(fb, 0x2ea01000);
1099	NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, rect->color);
1100	WRITE_WORD(0, fb, ARTIST_BGCOLOR);
1101
1102	NGLE_SET_DSTXY(fb, (rect->dx << 16) | (rect->dy));
1103	SET_LENXY_START_RECFILL(fb, (rect->width << 16) | (rect->height));
1104
1105	SETUP_FB(fb);
1106}
1107
1108static void __init
1109stifb_init_display(struct stifb_info *fb)
1110{
1111	int id = fb->id;
1112
1113	SETUP_FB(fb);
1114
1115	/* HCRX specific initialization */
1116	SETUP_HCRX(fb);
1117
1118	/*
1119	if (id == S9000_ID_HCRX)
1120		hyperInitSprite(fb);
1121	else
1122		ngleInitSprite(fb);
1123	*/
1124
1125	/* Initialize the image planes. */
1126        switch (id) {
1127	 case S9000_ID_HCRX:
1128	    hyperResetPlanes(fb, ENABLE);
1129	    break;
1130	 case S9000_ID_A1439A:
1131	    rattlerSetupPlanes(fb);
1132	    break;
1133	 case S9000_ID_A1659A:
1134	 case S9000_ID_ARTIST:
1135	 case CRT_ID_VISUALIZE_EG:
1136	    elkSetupPlanes(fb);
1137	    break;
1138	}
1139
1140	/* Clear attribute planes on non HCRX devices. */
1141        switch (id) {
1142	 case S9000_ID_A1659A:
1143	 case S9000_ID_A1439A:
1144	    if (fb->info->var.bits_per_pixel == 32)
1145		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1146	    else {
1147		ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1148	    }
1149	    if (id == S9000_ID_A1439A)
1150		ngleClearOverlayPlanes(fb, 0xff, 0);
1151	    break;
1152	 case S9000_ID_ARTIST:
1153	 case CRT_ID_VISUALIZE_EG:
1154	    if (fb->info->var.bits_per_pixel == 32)
1155		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1156	    else {
1157		ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1158	    }
1159	    break;
1160	}
1161	stifb_blank(0, fb->info);	/* 0=enable screen */
1162
1163	SETUP_FB(fb);
1164}
1165
1166/* ------------ Interfaces to hardware functions ------------ */
1167
1168static const struct fb_ops stifb_ops = {
1169	.owner		= THIS_MODULE,
1170	__FB_DEFAULT_IOMEM_OPS_RDWR,
1171	.fb_check_var	= stifb_check_var,
1172	.fb_setcolreg	= stifb_setcolreg,
1173	.fb_blank	= stifb_blank,
1174	.fb_fillrect	= stifb_fillrect,
1175	.fb_copyarea	= stifb_copyarea,
1176	.fb_imageblit	= cfb_imageblit,
1177	__FB_DEFAULT_IOMEM_OPS_MMAP,
1178};
1179
1180
1181/*
1182 *  Initialization
1183 */
1184
1185static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1186{
1187	struct fb_fix_screeninfo *fix;
1188	struct fb_var_screeninfo *var;
1189	struct stifb_info *fb;
1190	struct fb_info *info;
1191	unsigned long sti_rom_address;
1192	char modestr[32];
1193	char *dev_name;
1194	int bpp, xres, yres;
1195
1196	info = framebuffer_alloc(sizeof(*fb), sti->dev);
1197	if (!info)
1198		return -ENOMEM;
1199	fb = info->par;
1200	fb->info = info;
1201
1202	/* set struct to a known state */
1203	fix = &info->fix;
1204	var = &info->var;
1205
1206	fb->sti = sti;
1207	dev_name = sti->sti_data->inq_outptr.dev_name;
1208	/* store upper 32bits of the graphics id */
1209	fb->id = fb->sti->graphics_id[0];
1210
1211	/* only supported cards are allowed */
1212	switch (fb->id) {
1213	case CRT_ID_VISUALIZE_EG:
1214		/* Visualize cards can run either in "double buffer" or
1215 		  "standard" mode. Depending on the mode, the card reports
1216		  a different device name, e.g. "INTERNAL_EG_DX1024" in double
1217		  buffer mode and "INTERNAL_EG_X1024" in standard mode.
1218		  Since this driver only supports standard mode, we check
1219		  if the device name contains the string "DX" and tell the
1220		  user how to reconfigure the card. */
1221		if (strstr(dev_name, "DX")) {
1222		   printk(KERN_WARNING
1223"WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
1224"WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
1225			dev_name);
1226		   goto out_err0;
1227		}
1228		fallthrough;
1229	case S9000_ID_ARTIST:
1230	case S9000_ID_HCRX:
1231	case S9000_ID_TIMBER:
1232	case S9000_ID_A1659A:
1233	case S9000_ID_A1439A:
1234		break;
1235	default:
1236		printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1237			dev_name, fb->id);
1238		goto out_err0;
1239	}
1240
1241	/* default to 8 bpp on most graphic chips */
1242	bpp = 8;
1243	xres = sti_onscreen_x(fb->sti);
1244	yres = sti_onscreen_y(fb->sti);
1245
1246	ngleGetDeviceRomData(fb);
1247
1248	/* get (virtual) io region base addr */
1249	fix->mmio_start = REGION_BASE(fb,2);
1250	fix->mmio_len   = 0x400000;
1251
1252       	/* Reject any device not in the NGLE family */
1253	switch (fb->id) {
1254	case S9000_ID_A1659A:	/* CRX/A1659A */
1255		break;
1256	case S9000_ID_ELM:	/* GRX, grayscale but else same as A1659A */
1257		var->grayscale = 1;
1258		fb->id = S9000_ID_A1659A;
1259		break;
1260	case S9000_ID_TIMBER:	/* HP9000/710 Any (may be a grayscale device) */
1261		if (strstr(dev_name, "GRAYSCALE") ||
1262		    strstr(dev_name, "Grayscale") ||
1263		    strstr(dev_name, "grayscale"))
1264			var->grayscale = 1;
1265		break;
1266	case S9000_ID_TOMCAT:	/* Dual CRX, behaves else like a CRX */
1267		/* FIXME: TomCat supports two heads:
1268		 * fb.iobase = REGION_BASE(fb_info,3);
1269		 * fb.screen_base = ioremap(REGION_BASE(fb_info,2),xxx);
1270		 * for now we only support the left one ! */
1271		xres = fb->ngle_rom.x_size_visible;
1272		yres = fb->ngle_rom.y_size_visible;
1273		fb->id = S9000_ID_A1659A;
1274		break;
1275	case S9000_ID_A1439A:	/* CRX24/A1439A */
1276		bpp = 32;
1277		break;
1278	case S9000_ID_HCRX:	/* Hyperdrive/HCRX */
1279		memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1280		if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1281		    (fb->sti->regions_phys[2] & 0xfc000000))
1282			sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1283		else
1284			sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1285
1286		fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1287		if (IS_24_DEVICE(fb)) {
1288			if (bpp_pref == 8 || bpp_pref == 32)
1289				bpp = bpp_pref;
1290			else
1291				bpp = 32;
1292		} else
1293			bpp = 8;
1294		READ_WORD(fb, REG_15);
1295		SETUP_HW(fb);
1296		break;
1297	case CRT_ID_VISUALIZE_EG:
1298	case S9000_ID_ARTIST:	/* Artist */
1299		break;
1300	default:
1301#ifdef FALLBACK_TO_1BPP
1302		printk(KERN_WARNING
1303			"stifb: Unsupported graphics card (id=0x%08x) "
1304				"- now trying 1bpp mode instead\n",
1305			fb->id);
1306		bpp = 1;	/* default to 1 bpp */
1307		break;
1308#else
1309		printk(KERN_WARNING
1310			"stifb: Unsupported graphics card (id=0x%08x) "
1311				"- skipping.\n",
1312			fb->id);
1313		goto out_err0;
1314#endif
1315	}
1316
1317
1318	/* get framebuffer physical and virtual base addr & len (64bit ready) */
1319	fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1320	fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1321
1322	fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1323	if (!fix->line_length)
1324		fix->line_length = 2048; /* default */
1325
1326	/* limit fbsize to max visible screen size */
1327	if (fix->smem_len > yres*fix->line_length)
1328		fix->smem_len = ALIGN(yres*fix->line_length, 4*1024*1024);
1329
1330	fix->accel = FB_ACCEL_NONE;
1331
1332	switch (bpp) {
1333	    case 1:
1334		fix->type = FB_TYPE_PLANES;	/* well, sort of */
1335		fix->visual = FB_VISUAL_MONO10;
1336		var->red.length = var->green.length = var->blue.length = 1;
1337		break;
1338	    case 8:
1339		fix->type = FB_TYPE_PACKED_PIXELS;
1340		fix->visual = FB_VISUAL_PSEUDOCOLOR;
1341		var->red.length = var->green.length = var->blue.length = 8;
1342		break;
1343	    case 32:
1344		fix->type = FB_TYPE_PACKED_PIXELS;
1345		fix->visual = FB_VISUAL_DIRECTCOLOR;
1346		var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1347		var->blue.offset = 0;
1348		var->green.offset = 8;
1349		var->red.offset = 16;
1350		var->transp.offset = 24;
1351		break;
1352	    default:
1353		break;
1354	}
1355
1356	var->xres = var->xres_virtual = xres;
1357	var->yres = var->yres_virtual = yres;
1358	var->bits_per_pixel = bpp;
1359
1360	strcpy(fix->id, "stifb");
1361	info->fbops = &stifb_ops;
1362	info->screen_base = ioremap(REGION_BASE(fb,1), fix->smem_len);
1363	if (!info->screen_base) {
1364		printk(KERN_ERR "stifb: failed to map memory\n");
1365		goto out_err0;
1366	}
1367	info->screen_size = fix->smem_len;
1368	info->flags = FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1369	info->pseudo_palette = &fb->pseudo_palette;
1370
1371	scnprintf(modestr, sizeof(modestr), "%dx%d-%d", xres, yres, bpp);
1372	fb_find_mode(&info->var, info, modestr, NULL, 0, NULL, bpp);
1373
1374	/* This has to be done !!! */
1375	if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
1376		goto out_err1;
1377	stifb_init_display(fb);
1378
1379	if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1380		printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1381				fix->smem_start, fix->smem_start+fix->smem_len);
1382		goto out_err2;
1383	}
1384
1385	if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1386		printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1387				fix->mmio_start, fix->mmio_start+fix->mmio_len);
1388		goto out_err3;
1389	}
1390
1391	/* save for primary gfx device detection & unregister_framebuffer() */
1392	if (register_framebuffer(fb->info) < 0)
1393		goto out_err4;
1394
1395	fb_info(fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1396		fix->id,
1397		var->xres,
1398		var->yres,
1399		var->bits_per_pixel,
1400		dev_name,
1401		fb->id,
1402		fix->mmio_start);
1403
1404	dev_set_drvdata(sti->dev, info);
1405
1406	return 0;
1407
1408
1409out_err4:
1410	release_mem_region(fix->mmio_start, fix->mmio_len);
1411out_err3:
1412	release_mem_region(fix->smem_start, fix->smem_len);
1413out_err2:
1414	fb_dealloc_cmap(&info->cmap);
1415out_err1:
1416	iounmap(info->screen_base);
1417out_err0:
1418	framebuffer_release(info);
1419	return -ENXIO;
1420}
1421
1422static int stifb_disabled __initdata;
1423
1424int __init
1425stifb_setup(char *options);
1426
1427static int __init stifb_init(void)
1428{
1429	struct sti_struct *sti;
1430	struct sti_struct *def_sti;
1431	int i;
1432
1433#ifndef MODULE
1434	char *option = NULL;
1435
1436	if (fb_get_options("stifb", &option))
1437		return -ENODEV;
1438	stifb_setup(option);
1439#endif
1440	if (stifb_disabled) {
1441		printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1442		return -ENXIO;
1443	}
1444
1445	def_sti = sti_get_rom(0);
1446	if (def_sti) {
1447		for (i = 1; i <= MAX_STI_ROMS; i++) {
1448			sti = sti_get_rom(i);
1449			if (!sti)
1450				break;
1451			if (sti == def_sti) {
1452				stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1453				break;
1454			}
1455		}
1456	}
1457
1458	for (i = 1; i <= MAX_STI_ROMS; i++) {
1459		sti = sti_get_rom(i);
1460		if (!sti)
1461			break;
1462		if (sti == def_sti)
1463			continue;
1464		stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1465	}
1466	return 0;
1467}
1468
1469/*
1470 *  Cleanup
1471 */
1472
1473static void __exit
1474stifb_cleanup(void)
1475{
1476	struct sti_struct *sti;
1477	int i;
1478
1479	for (i = 1; i <= MAX_STI_ROMS; i++) {
1480		sti = sti_get_rom(i);
1481		if (!sti)
1482			break;
1483		if (sti->dev) {
1484			struct fb_info *info = dev_get_drvdata(sti->dev);
1485
1486			if (!info)
1487				continue;
1488			unregister_framebuffer(info);
1489			release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1490		        release_mem_region(info->fix.smem_start, info->fix.smem_len);
1491				if (info->screen_base)
1492					iounmap(info->screen_base);
1493		        fb_dealloc_cmap(&info->cmap);
1494		        framebuffer_release(info);
1495			dev_set_drvdata(sti->dev, NULL);
1496		}
1497	}
1498}
1499
1500int __init
1501stifb_setup(char *options)
1502{
1503	int i;
1504
1505	if (!options || !*options)
1506		return 1;
1507
1508	if (strncmp(options, "off", 3) == 0) {
1509		stifb_disabled = 1;
1510		options += 3;
1511	}
1512
1513	if (strncmp(options, "bpp", 3) == 0) {
1514		options += 3;
1515		for (i = 0; i < MAX_STI_ROMS; i++) {
1516			if (*options++ != ':')
1517				break;
1518			stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1519		}
1520	}
1521	return 1;
1522}
1523
1524__setup("stifb=", stifb_setup);
1525
1526module_init(stifb_init);
1527module_exit(stifb_cleanup);
1528
1529MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1530MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1531MODULE_LICENSE("GPL v2");
~/ Read-only file preview.