162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * linux/drivers/video/stifb.c -
362306a36Sopenharmony_ci * Low level Frame buffer driver for HP workstations with
462306a36Sopenharmony_ci * STI (standard text interface) video firmware.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2001-2006 Helge Deller <deller@gmx.de>
762306a36Sopenharmony_ci * Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Based on:
1062306a36Sopenharmony_ci * - linux/drivers/video/artistfb.c -- Artist frame buffer driver
1162306a36Sopenharmony_ci *	Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
1262306a36Sopenharmony_ci *   - based on skeletonfb, which was
1362306a36Sopenharmony_ci *	Created 28 Dec 1997 by Geert Uytterhoeven
1462306a36Sopenharmony_ci * - HP Xhp cfb-based X11 window driver for XFree86
1562306a36Sopenharmony_ci *	(c)Copyright 1992 Hewlett-Packard Co.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *  The following graphics display devices (NGLE family) are supported by this driver:
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *  HPA4070A	known as "HCRX", a 1280x1024 color device with 8 planes
2162306a36Sopenharmony_ci *  HPA4071A	known as "HCRX24", a 1280x1024 color device with 24 planes,
2262306a36Sopenharmony_ci *		optionally available with a hardware accelerator as HPA4071A_Z
2362306a36Sopenharmony_ci *  HPA1659A	known as "CRX", a 1280x1024 color device with 8 planes
2462306a36Sopenharmony_ci *  HPA1439A	known as "CRX24", a 1280x1024 color device with 24 planes,
2562306a36Sopenharmony_ci *		optionally available with a hardware accelerator.
2662306a36Sopenharmony_ci *  HPA1924A	known as "GRX", a 1280x1024 grayscale device with 8 planes
2762306a36Sopenharmony_ci *  HPA2269A	known as "Dual CRX", a 1280x1024 color device with 8 planes,
2862306a36Sopenharmony_ci *		implements support for two displays on a single graphics card.
2962306a36Sopenharmony_ci *  HP710C	internal graphics support optionally available on the HP9000s710 SPU,
3062306a36Sopenharmony_ci *		supports 1280x1024 color displays with 8 planes.
3162306a36Sopenharmony_ci *  HP710G	same as HP710C, 1280x1024 grayscale only
3262306a36Sopenharmony_ci *  HP710L	same as HP710C, 1024x768 color only
3362306a36Sopenharmony_ci *  HP712	internal graphics support on HP9000s712 SPU, supports 640x480,
3462306a36Sopenharmony_ci *		1024x768 or 1280x1024 color displays on 8 planes (Artist)
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
3762306a36Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
3862306a36Sopenharmony_ci * for more details.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* TODO:
4262306a36Sopenharmony_ci *	- 1bpp mode is completely untested
4362306a36Sopenharmony_ci *	- add support for h/w acceleration
4462306a36Sopenharmony_ci *	- add hardware cursor
4562306a36Sopenharmony_ci *	- automatically disable double buffering (e.g. on RDI precisionbook laptop)
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* on supported graphic devices you may:
5062306a36Sopenharmony_ci * #define FALLBACK_TO_1BPP to fall back to 1 bpp, or
5162306a36Sopenharmony_ci * #undef  FALLBACK_TO_1BPP to reject support for unsupported cards */
5262306a36Sopenharmony_ci#undef FALLBACK_TO_1BPP
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#undef DEBUG_STIFB_REGS		/* debug sti register accesses */
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#include <linux/module.h>
5862306a36Sopenharmony_ci#include <linux/kernel.h>
5962306a36Sopenharmony_ci#include <linux/errno.h>
6062306a36Sopenharmony_ci#include <linux/string.h>
6162306a36Sopenharmony_ci#include <linux/mm.h>
6262306a36Sopenharmony_ci#include <linux/slab.h>
6362306a36Sopenharmony_ci#include <linux/delay.h>
6462306a36Sopenharmony_ci#include <linux/fb.h>
6562306a36Sopenharmony_ci#include <linux/init.h>
6662306a36Sopenharmony_ci#include <linux/ioport.h>
6762306a36Sopenharmony_ci#include <linux/io.h>
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#include <asm/grfioctl.h>	/* for HP-UX compatibility */
7062306a36Sopenharmony_ci#include <linux/uaccess.h>
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#include <video/sticore.h>
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/* REGION_BASE(fb_info, index) returns the physical address for region <index> */
7562306a36Sopenharmony_ci#define REGION_BASE(fb_info, index) \
7662306a36Sopenharmony_ci	F_EXTEND(fb_info->sti->regions_phys[index])
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#define NGLEDEVDEPROM_CRT_REGION 1
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#define NR_PALETTE 256
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_citypedef struct {
8362306a36Sopenharmony_ci	__s32	video_config_reg;
8462306a36Sopenharmony_ci	__s32	misc_video_start;
8562306a36Sopenharmony_ci	__s32	horiz_timing_fmt;
8662306a36Sopenharmony_ci	__s32	serr_timing_fmt;
8762306a36Sopenharmony_ci	__s32	vert_timing_fmt;
8862306a36Sopenharmony_ci	__s32	horiz_state;
8962306a36Sopenharmony_ci	__s32	vert_state;
9062306a36Sopenharmony_ci	__s32	vtg_state_elements;
9162306a36Sopenharmony_ci	__s32	pipeline_delay;
9262306a36Sopenharmony_ci	__s32	misc_video_end;
9362306a36Sopenharmony_ci} video_setup_t;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_citypedef struct {
9662306a36Sopenharmony_ci	__s16	sizeof_ngle_data;
9762306a36Sopenharmony_ci	__s16	x_size_visible;	    /* visible screen dim in pixels  */
9862306a36Sopenharmony_ci	__s16	y_size_visible;
9962306a36Sopenharmony_ci	__s16	pad2[15];
10062306a36Sopenharmony_ci	__s16	cursor_pipeline_delay;
10162306a36Sopenharmony_ci	__s16	video_interleaves;
10262306a36Sopenharmony_ci	__s32	pad3[11];
10362306a36Sopenharmony_ci} ngle_rom_t;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistruct stifb_info {
10662306a36Sopenharmony_ci	struct fb_info info;
10762306a36Sopenharmony_ci	unsigned int id;
10862306a36Sopenharmony_ci	ngle_rom_t ngle_rom;
10962306a36Sopenharmony_ci	struct sti_struct *sti;
11062306a36Sopenharmony_ci	int deviceSpecificConfig;
11162306a36Sopenharmony_ci	u32 pseudo_palette[16];
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic int __initdata stifb_bpp_pref[MAX_STI_ROMS];
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci/* ------------------- chipset specific functions -------------------------- */
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/* offsets to graphic-chip internal registers */
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define REG_1		0x000118
12162306a36Sopenharmony_ci#define REG_2		0x000480
12262306a36Sopenharmony_ci#define REG_3		0x0004a0
12362306a36Sopenharmony_ci#define REG_4		0x000600
12462306a36Sopenharmony_ci#define REG_6		0x000800
12562306a36Sopenharmony_ci#define REG_7		0x000804
12662306a36Sopenharmony_ci#define REG_8		0x000820
12762306a36Sopenharmony_ci#define REG_9		0x000a04
12862306a36Sopenharmony_ci#define REG_10		0x018000
12962306a36Sopenharmony_ci#define REG_11		0x018004
13062306a36Sopenharmony_ci#define REG_12		0x01800c
13162306a36Sopenharmony_ci#define REG_13		0x018018
13262306a36Sopenharmony_ci#define REG_14  	0x01801c
13362306a36Sopenharmony_ci#define REG_15		0x200000
13462306a36Sopenharmony_ci#define REG_15b0	0x200000
13562306a36Sopenharmony_ci#define REG_16b1	0x200005
13662306a36Sopenharmony_ci#define REG_16b3	0x200007
13762306a36Sopenharmony_ci#define REG_21		0x200218
13862306a36Sopenharmony_ci#define REG_22		0x0005a0
13962306a36Sopenharmony_ci#define REG_23		0x0005c0
14062306a36Sopenharmony_ci#define REG_24		0x000808
14162306a36Sopenharmony_ci#define REG_25		0x000b00
14262306a36Sopenharmony_ci#define REG_26		0x200118
14362306a36Sopenharmony_ci#define REG_27		0x200308
14462306a36Sopenharmony_ci#define REG_32		0x21003c
14562306a36Sopenharmony_ci#define REG_33		0x210040
14662306a36Sopenharmony_ci#define REG_34		0x200008
14762306a36Sopenharmony_ci#define REG_35		0x018010
14862306a36Sopenharmony_ci#define REG_38		0x210020
14962306a36Sopenharmony_ci#define REG_39		0x210120
15062306a36Sopenharmony_ci#define REG_40		0x210130
15162306a36Sopenharmony_ci#define REG_42		0x210028
15262306a36Sopenharmony_ci#define REG_43		0x21002c
15362306a36Sopenharmony_ci#define REG_44		0x210030
15462306a36Sopenharmony_ci#define REG_45		0x210034
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci#define READ_BYTE(fb,reg)		gsc_readb((fb)->info.fix.mmio_start + (reg))
15762306a36Sopenharmony_ci#define READ_WORD(fb,reg)		gsc_readl((fb)->info.fix.mmio_start + (reg))
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci#ifndef DEBUG_STIFB_REGS
16162306a36Sopenharmony_ci# define  DEBUG_OFF()
16262306a36Sopenharmony_ci# define  DEBUG_ON()
16362306a36Sopenharmony_ci# define WRITE_BYTE(value,fb,reg)	gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
16462306a36Sopenharmony_ci# define WRITE_WORD(value,fb,reg)	gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
16562306a36Sopenharmony_ci#else
16662306a36Sopenharmony_ci  static int debug_on = 1;
16762306a36Sopenharmony_ci# define  DEBUG_OFF() debug_on=0
16862306a36Sopenharmony_ci# define  DEBUG_ON()  debug_on=1
16962306a36Sopenharmony_ci# define WRITE_BYTE(value,fb,reg)	do { if (debug_on) \
17062306a36Sopenharmony_ci						printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
17162306a36Sopenharmony_ci							__func__, reg, value, READ_BYTE(fb,reg)); 		  \
17262306a36Sopenharmony_ci					gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
17362306a36Sopenharmony_ci# define WRITE_WORD(value,fb,reg)	do { if (debug_on) \
17462306a36Sopenharmony_ci						printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
17562306a36Sopenharmony_ci							__func__, reg, value, READ_WORD(fb,reg)); 		  \
17662306a36Sopenharmony_ci					gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
17762306a36Sopenharmony_ci#endif /* DEBUG_STIFB_REGS */
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci#define ENABLE	1	/* for enabling/disabling screen */
18162306a36Sopenharmony_ci#define DISABLE 0
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#define NGLE_LOCK(fb_info)	do { } while (0)
18462306a36Sopenharmony_ci#define NGLE_UNLOCK(fb_info)	do { } while (0)
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic void
18762306a36Sopenharmony_ciSETUP_HW(struct stifb_info *fb)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	char stat;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	do {
19262306a36Sopenharmony_ci		stat = READ_BYTE(fb, REG_15b0);
19362306a36Sopenharmony_ci		if (!stat)
19462306a36Sopenharmony_ci	    		stat = READ_BYTE(fb, REG_15b0);
19562306a36Sopenharmony_ci	} while (stat);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic void
20062306a36Sopenharmony_ciSETUP_FB(struct stifb_info *fb)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	unsigned int reg10_value = 0;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	SETUP_HW(fb);
20562306a36Sopenharmony_ci	switch (fb->id)
20662306a36Sopenharmony_ci	{
20762306a36Sopenharmony_ci		case CRT_ID_VISUALIZE_EG:
20862306a36Sopenharmony_ci		case S9000_ID_ARTIST:
20962306a36Sopenharmony_ci		case S9000_ID_A1659A:
21062306a36Sopenharmony_ci			reg10_value = 0x13601000;
21162306a36Sopenharmony_ci			break;
21262306a36Sopenharmony_ci		case S9000_ID_A1439A:
21362306a36Sopenharmony_ci			if (fb->info.var.bits_per_pixel == 32)
21462306a36Sopenharmony_ci				reg10_value = 0xBBA0A000;
21562306a36Sopenharmony_ci			else
21662306a36Sopenharmony_ci				reg10_value = 0x13601000;
21762306a36Sopenharmony_ci			break;
21862306a36Sopenharmony_ci		case S9000_ID_HCRX:
21962306a36Sopenharmony_ci			if (fb->info.var.bits_per_pixel == 32)
22062306a36Sopenharmony_ci				reg10_value = 0xBBA0A000;
22162306a36Sopenharmony_ci			else
22262306a36Sopenharmony_ci				reg10_value = 0x13602000;
22362306a36Sopenharmony_ci			break;
22462306a36Sopenharmony_ci		case S9000_ID_TIMBER:
22562306a36Sopenharmony_ci		case CRX24_OVERLAY_PLANES:
22662306a36Sopenharmony_ci			reg10_value = 0x13602000;
22762306a36Sopenharmony_ci			break;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci	if (reg10_value)
23062306a36Sopenharmony_ci		WRITE_WORD(reg10_value, fb, REG_10);
23162306a36Sopenharmony_ci	WRITE_WORD(0x83000300, fb, REG_14);
23262306a36Sopenharmony_ci	SETUP_HW(fb);
23362306a36Sopenharmony_ci	WRITE_BYTE(1, fb, REG_16b1);
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic void
23762306a36Sopenharmony_ciSTART_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	SETUP_HW(fb);
24062306a36Sopenharmony_ci	WRITE_WORD(0xBBE0F000, fb, REG_10);
24162306a36Sopenharmony_ci	WRITE_WORD(0x03000300, fb, REG_14);
24262306a36Sopenharmony_ci	WRITE_WORD(~0, fb, REG_13);
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic void
24662306a36Sopenharmony_ciWRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	SETUP_HW(fb);
24962306a36Sopenharmony_ci	WRITE_WORD(((0x100+index)<<2), fb, REG_3);
25062306a36Sopenharmony_ci	WRITE_WORD(color, fb, REG_4);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic void
25462306a36Sopenharmony_ciFINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	WRITE_WORD(0x400, fb, REG_2);
25762306a36Sopenharmony_ci	if (fb->info.var.bits_per_pixel == 32) {
25862306a36Sopenharmony_ci		WRITE_WORD(0x83000100, fb, REG_1);
25962306a36Sopenharmony_ci	} else {
26062306a36Sopenharmony_ci		if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
26162306a36Sopenharmony_ci			WRITE_WORD(0x80000100, fb, REG_26);
26262306a36Sopenharmony_ci		else
26362306a36Sopenharmony_ci			WRITE_WORD(0x80000100, fb, REG_1);
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci	SETUP_FB(fb);
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic void
26962306a36Sopenharmony_ciSETUP_RAMDAC(struct stifb_info *fb)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	SETUP_HW(fb);
27262306a36Sopenharmony_ci	WRITE_WORD(0x04000000, fb, 0x1020);
27362306a36Sopenharmony_ci	WRITE_WORD(0xff000000, fb, 0x1028);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic void
27762306a36Sopenharmony_ciCRX24_SETUP_RAMDAC(struct stifb_info *fb)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	SETUP_HW(fb);
28062306a36Sopenharmony_ci	WRITE_WORD(0x04000000, fb, 0x1000);
28162306a36Sopenharmony_ci	WRITE_WORD(0x02000000, fb, 0x1004);
28262306a36Sopenharmony_ci	WRITE_WORD(0xff000000, fb, 0x1008);
28362306a36Sopenharmony_ci	WRITE_WORD(0x05000000, fb, 0x1000);
28462306a36Sopenharmony_ci	WRITE_WORD(0x02000000, fb, 0x1004);
28562306a36Sopenharmony_ci	WRITE_WORD(0x03000000, fb, 0x1008);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci#if 0
28962306a36Sopenharmony_cistatic void
29062306a36Sopenharmony_ciHCRX_SETUP_RAMDAC(struct stifb_info *fb)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	WRITE_WORD(0xffffffff, fb, REG_32);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci#endif
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic void
29762306a36Sopenharmony_ciCRX24_SET_OVLY_MASK(struct stifb_info *fb)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	SETUP_HW(fb);
30062306a36Sopenharmony_ci	WRITE_WORD(0x13a02000, fb, REG_11);
30162306a36Sopenharmony_ci	WRITE_WORD(0x03000300, fb, REG_14);
30262306a36Sopenharmony_ci	WRITE_WORD(0x000017f0, fb, REG_3);
30362306a36Sopenharmony_ci	WRITE_WORD(0xffffffff, fb, REG_13);
30462306a36Sopenharmony_ci	WRITE_WORD(0xffffffff, fb, REG_22);
30562306a36Sopenharmony_ci	WRITE_WORD(0x00000000, fb, REG_23);
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic void
30962306a36Sopenharmony_ciENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	unsigned int value = enable ? 0x43000000 : 0x03000000;
31262306a36Sopenharmony_ci        SETUP_HW(fb);
31362306a36Sopenharmony_ci        WRITE_WORD(0x06000000,	fb, 0x1030);
31462306a36Sopenharmony_ci        WRITE_WORD(value, 	fb, 0x1038);
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic void
31862306a36Sopenharmony_ciCRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	unsigned int value = enable ? 0x10000000 : 0x30000000;
32162306a36Sopenharmony_ci	SETUP_HW(fb);
32262306a36Sopenharmony_ci	WRITE_WORD(0x01000000,	fb, 0x1000);
32362306a36Sopenharmony_ci	WRITE_WORD(0x02000000,	fb, 0x1004);
32462306a36Sopenharmony_ci	WRITE_WORD(value,	fb, 0x1008);
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic void
32862306a36Sopenharmony_ciARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	u32 DregsMiscVideo = REG_21;
33162306a36Sopenharmony_ci	u32 DregsMiscCtl = REG_27;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	SETUP_HW(fb);
33462306a36Sopenharmony_ci	if (enable) {
33562306a36Sopenharmony_ci	  WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
33662306a36Sopenharmony_ci	  WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   | 0x00800000, fb, DregsMiscCtl);
33762306a36Sopenharmony_ci	} else {
33862306a36Sopenharmony_ci	  WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
33962306a36Sopenharmony_ci	  WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   & ~0x00800000, fb, DregsMiscCtl);
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci#define GET_ROMTABLE_INDEX(fb) \
34462306a36Sopenharmony_ci	(READ_BYTE(fb, REG_16b3) - 1)
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci#define HYPER_CONFIG_PLANES_24 0x00000100
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci#define IS_24_DEVICE(fb) \
34962306a36Sopenharmony_ci	(fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci#define IS_888_DEVICE(fb) \
35262306a36Sopenharmony_ci	(!(IS_24_DEVICE(fb)))
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci#define GET_FIFO_SLOTS(fb, cnt, numslots)	\
35562306a36Sopenharmony_ci{	while (cnt < numslots) 			\
35662306a36Sopenharmony_ci		cnt = READ_WORD(fb, REG_34);	\
35762306a36Sopenharmony_ci	cnt -= numslots;			\
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci#define	    IndexedDcd	0	/* Pixel data is indexed (pseudo) color */
36162306a36Sopenharmony_ci#define	    Otc04	2	/* Pixels in each longword transfer (4) */
36262306a36Sopenharmony_ci#define	    Otc32	5	/* Pixels in each longword transfer (32) */
36362306a36Sopenharmony_ci#define	    Ots08	3	/* Each pixel is size (8)d transfer (1) */
36462306a36Sopenharmony_ci#define	    OtsIndirect	6	/* Each bit goes through FG/BG color(8) */
36562306a36Sopenharmony_ci#define	    AddrLong	5	/* FB address is Long aligned (pixel) */
36662306a36Sopenharmony_ci#define	    BINovly	0x2	/* 8 bit overlay */
36762306a36Sopenharmony_ci#define	    BINapp0I	0x0	/* Application Buffer 0, Indexed */
36862306a36Sopenharmony_ci#define	    BINapp1I	0x1	/* Application Buffer 1, Indexed */
36962306a36Sopenharmony_ci#define	    BINapp0F8	0xa	/* Application Buffer 0, Fractional 8-8-8 */
37062306a36Sopenharmony_ci#define	    BINattr	0xd	/* Attribute Bitmap */
37162306a36Sopenharmony_ci#define	    RopSrc 	0x3
37262306a36Sopenharmony_ci#define	    BitmapExtent08  3	/* Each write hits ( 8) bits in depth */
37362306a36Sopenharmony_ci#define	    BitmapExtent32  5	/* Each write hits (32) bits in depth */
37462306a36Sopenharmony_ci#define	    DataDynamic	    0	/* Data register reloaded by direct access */
37562306a36Sopenharmony_ci#define	    MaskDynamic	    1	/* Mask register reloaded by direct access */
37662306a36Sopenharmony_ci#define	    MaskOtc	    0	/* Mask contains Object Count valid bits */
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci#define MaskAddrOffset(offset) (offset)
37962306a36Sopenharmony_ci#define StaticReg(en) (en)
38062306a36Sopenharmony_ci#define BGx(en) (en)
38162306a36Sopenharmony_ci#define FGx(en) (en)
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci#define BAJustPoint(offset) (offset)
38462306a36Sopenharmony_ci#define BAIndexBase(base) (base)
38562306a36Sopenharmony_ci#define BA(F,C,S,A,J,B,I) \
38662306a36Sopenharmony_ci	(((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci#define IBOvals(R,M,X,S,D,L,B,F) \
38962306a36Sopenharmony_ci	(((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci#define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
39262306a36Sopenharmony_ci	WRITE_WORD(val, fb, REG_14)
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci#define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
39562306a36Sopenharmony_ci	WRITE_WORD(val, fb, REG_11)
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci#define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
39862306a36Sopenharmony_ci	WRITE_WORD(val, fb, REG_12)
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci#define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
40162306a36Sopenharmony_ci	WRITE_WORD(plnmsk32, fb, REG_13)
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci#define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
40462306a36Sopenharmony_ci	WRITE_WORD(fg32, fb, REG_35)
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci#define NGLE_SET_TRANSFERDATA(fb, val) \
40762306a36Sopenharmony_ci	WRITE_WORD(val, fb, REG_8)
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci#define NGLE_SET_DSTXY(fb, val) \
41062306a36Sopenharmony_ci	WRITE_WORD(val, fb, REG_6)
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) (		\
41362306a36Sopenharmony_ci	(u32) (fbaddrbase) +					\
41462306a36Sopenharmony_ci	    (	(unsigned int)  ( (y) << 13      ) |		\
41562306a36Sopenharmony_ci		(unsigned int)  ( (x) << 2       )	)	\
41662306a36Sopenharmony_ci	)
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci#define NGLE_BINC_SET_DSTADDR(fb, addr) \
41962306a36Sopenharmony_ci	WRITE_WORD(addr, fb, REG_3)
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci#define NGLE_BINC_SET_SRCADDR(fb, addr) \
42262306a36Sopenharmony_ci	WRITE_WORD(addr, fb, REG_2)
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci#define NGLE_BINC_SET_DSTMASK(fb, mask) \
42562306a36Sopenharmony_ci	WRITE_WORD(mask, fb, REG_22)
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci#define NGLE_BINC_WRITE32(fb, data32) \
42862306a36Sopenharmony_ci	WRITE_WORD(data32, fb, REG_23)
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci#define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
43162306a36Sopenharmony_ci	WRITE_WORD((cmapBltCtlData32), fb, REG_38)
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci#define SET_LENXY_START_RECFILL(fb, lenxy) \
43462306a36Sopenharmony_ci	WRITE_WORD(lenxy, fb, REG_9)
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci#define SETUP_COPYAREA(fb) \
43762306a36Sopenharmony_ci	WRITE_BYTE(0, fb, REG_16b1)
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic void
44062306a36Sopenharmony_ciHYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	u32 DregsHypMiscVideo = REG_33;
44362306a36Sopenharmony_ci	unsigned int value;
44462306a36Sopenharmony_ci	SETUP_HW(fb);
44562306a36Sopenharmony_ci	value = READ_WORD(fb, DregsHypMiscVideo);
44662306a36Sopenharmony_ci	if (enable)
44762306a36Sopenharmony_ci		value |= 0x0A000000;
44862306a36Sopenharmony_ci	else
44962306a36Sopenharmony_ci		value &= ~0x0A000000;
45062306a36Sopenharmony_ci	WRITE_WORD(value, fb, DregsHypMiscVideo);
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci/* BufferNumbers used by SETUP_ATTR_ACCESS() */
45562306a36Sopenharmony_ci#define BUFF0_CMAP0	0x00001e02
45662306a36Sopenharmony_ci#define BUFF1_CMAP0	0x02001e02
45762306a36Sopenharmony_ci#define BUFF1_CMAP3	0x0c001e02
45862306a36Sopenharmony_ci#define ARTIST_CMAP0	0x00000102
45962306a36Sopenharmony_ci#define HYPER_CMAP8	0x00000100
46062306a36Sopenharmony_ci#define HYPER_CMAP24	0x00000800
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic void
46362306a36Sopenharmony_ciSETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	SETUP_HW(fb);
46662306a36Sopenharmony_ci	WRITE_WORD(0x2EA0D000, fb, REG_11);
46762306a36Sopenharmony_ci	WRITE_WORD(0x23000302, fb, REG_14);
46862306a36Sopenharmony_ci	WRITE_WORD(BufferNumber, fb, REG_12);
46962306a36Sopenharmony_ci	WRITE_WORD(0xffffffff, fb, REG_8);
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic void
47362306a36Sopenharmony_ciSET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	/* REG_6 seems to have special values when run on a
47662306a36Sopenharmony_ci	   RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
47762306a36Sopenharmony_ci	   INTERNAL_EG_X1024).  The values are:
47862306a36Sopenharmony_ci		0x2f0: internal (LCD) & external display enabled
47962306a36Sopenharmony_ci		0x2a0: external display only
48062306a36Sopenharmony_ci		0x000: zero on standard artist graphic cards
48162306a36Sopenharmony_ci	*/
48262306a36Sopenharmony_ci	WRITE_WORD(0x00000000, fb, REG_6);
48362306a36Sopenharmony_ci	WRITE_WORD((width<<16) | height, fb, REG_9);
48462306a36Sopenharmony_ci	WRITE_WORD(0x05000000, fb, REG_6);
48562306a36Sopenharmony_ci	WRITE_WORD(0x00040001, fb, REG_9);
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic void
48962306a36Sopenharmony_ciFINISH_ATTR_ACCESS(struct stifb_info *fb)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	SETUP_HW(fb);
49262306a36Sopenharmony_ci	WRITE_WORD(0x00000000, fb, REG_12);
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic void
49662306a36Sopenharmony_cielkSetupPlanes(struct stifb_info *fb)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	SETUP_RAMDAC(fb);
49962306a36Sopenharmony_ci	SETUP_FB(fb);
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic void
50362306a36Sopenharmony_cingleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	SETUP_ATTR_ACCESS(fb, BufferNumber);
50662306a36Sopenharmony_ci	SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
50762306a36Sopenharmony_ci	FINISH_ATTR_ACCESS(fb);
50862306a36Sopenharmony_ci	SETUP_FB(fb);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic void
51362306a36Sopenharmony_cirattlerSetupPlanes(struct stifb_info *fb)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	int saved_id, y;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci 	/* Write RAMDAC pixel read mask register so all overlay
51862306a36Sopenharmony_ci	 * planes are display-enabled.  (CRX24 uses Bt462 pixel
51962306a36Sopenharmony_ci	 * read mask register for overlay planes, not image planes).
52062306a36Sopenharmony_ci	 */
52162306a36Sopenharmony_ci	CRX24_SETUP_RAMDAC(fb);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* change fb->id temporarily to fool SETUP_FB() */
52462306a36Sopenharmony_ci	saved_id = fb->id;
52562306a36Sopenharmony_ci	fb->id = CRX24_OVERLAY_PLANES;
52662306a36Sopenharmony_ci	SETUP_FB(fb);
52762306a36Sopenharmony_ci	fb->id = saved_id;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	for (y = 0; y < fb->info.var.yres; ++y)
53062306a36Sopenharmony_ci		fb_memset_io(fb->info.screen_base + y * fb->info.fix.line_length,
53162306a36Sopenharmony_ci			     0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	CRX24_SET_OVLY_MASK(fb);
53462306a36Sopenharmony_ci	SETUP_FB(fb);
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci#define HYPER_CMAP_TYPE				0
53962306a36Sopenharmony_ci#define NGLE_CMAP_INDEXED0_TYPE			0
54062306a36Sopenharmony_ci#define NGLE_CMAP_OVERLAY_TYPE			3
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci/* typedef of LUT (Colormap) BLT Control Register */
54362306a36Sopenharmony_citypedef union	/* Note assumption that fields are packed left-to-right */
54462306a36Sopenharmony_ci{	u32 all;
54562306a36Sopenharmony_ci	struct
54662306a36Sopenharmony_ci	{
54762306a36Sopenharmony_ci		unsigned enable              :  1;
54862306a36Sopenharmony_ci		unsigned waitBlank           :  1;
54962306a36Sopenharmony_ci		unsigned reserved1           :  4;
55062306a36Sopenharmony_ci		unsigned lutOffset           : 10;   /* Within destination LUT */
55162306a36Sopenharmony_ci		unsigned lutType             :  2;   /* Cursor, image, overlay */
55262306a36Sopenharmony_ci		unsigned reserved2           :  4;
55362306a36Sopenharmony_ci		unsigned length              : 10;
55462306a36Sopenharmony_ci	} fields;
55562306a36Sopenharmony_ci} NgleLutBltCtl;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci#if 0
55962306a36Sopenharmony_cistatic NgleLutBltCtl
56062306a36Sopenharmony_cisetNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	NgleLutBltCtl lutBltCtl;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	/* set enable, zero reserved fields */
56562306a36Sopenharmony_ci	lutBltCtl.all           = 0x80000000;
56662306a36Sopenharmony_ci	lutBltCtl.fields.length = length;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	switch (fb->id)
56962306a36Sopenharmony_ci	{
57062306a36Sopenharmony_ci	case S9000_ID_A1439A:		/* CRX24 */
57162306a36Sopenharmony_ci		if (fb->var.bits_per_pixel == 8) {
57262306a36Sopenharmony_ci			lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
57362306a36Sopenharmony_ci			lutBltCtl.fields.lutOffset = 0;
57462306a36Sopenharmony_ci		} else {
57562306a36Sopenharmony_ci			lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
57662306a36Sopenharmony_ci			lutBltCtl.fields.lutOffset = 0 * 256;
57762306a36Sopenharmony_ci		}
57862306a36Sopenharmony_ci		break;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	case S9000_ID_ARTIST:
58162306a36Sopenharmony_ci		lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
58262306a36Sopenharmony_ci		lutBltCtl.fields.lutOffset = 0 * 256;
58362306a36Sopenharmony_ci		break;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	default:
58662306a36Sopenharmony_ci		lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
58762306a36Sopenharmony_ci		lutBltCtl.fields.lutOffset = 0;
58862306a36Sopenharmony_ci		break;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/* Offset points to start of LUT.  Adjust for within LUT */
59262306a36Sopenharmony_ci	lutBltCtl.fields.lutOffset += offsetWithinLut;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	return lutBltCtl;
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci#endif
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic NgleLutBltCtl
59962306a36Sopenharmony_cisetHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	NgleLutBltCtl lutBltCtl;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	/* set enable, zero reserved fields */
60462306a36Sopenharmony_ci	lutBltCtl.all = 0x80000000;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	lutBltCtl.fields.length = length;
60762306a36Sopenharmony_ci	lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
61062306a36Sopenharmony_ci	if (fb->info.var.bits_per_pixel == 8)
61162306a36Sopenharmony_ci		lutBltCtl.fields.lutOffset = 2 * 256;
61262306a36Sopenharmony_ci	else
61362306a36Sopenharmony_ci		lutBltCtl.fields.lutOffset = 0 * 256;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	/* Offset points to start of LUT.  Adjust for within LUT */
61662306a36Sopenharmony_ci	lutBltCtl.fields.lutOffset += offsetWithinLut;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	return lutBltCtl;
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic void hyperUndoITE(struct stifb_info *fb)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	int nFreeFifoSlots = 0;
62562306a36Sopenharmony_ci	u32 fbAddr;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	NGLE_LOCK(fb);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
63062306a36Sopenharmony_ci	WRITE_WORD(0xffffffff, fb, REG_32);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	/* Write overlay transparency mask so only entry 255 is transparent */
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	/* Hardware setup for full-depth write to "magic" location */
63562306a36Sopenharmony_ci	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
63662306a36Sopenharmony_ci	NGLE_QUICK_SET_DST_BM_ACCESS(fb,
63762306a36Sopenharmony_ci		BA(IndexedDcd, Otc04, Ots08, AddrLong,
63862306a36Sopenharmony_ci		BAJustPoint(0), BINovly, BAIndexBase(0)));
63962306a36Sopenharmony_ci	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
64062306a36Sopenharmony_ci		IBOvals(RopSrc, MaskAddrOffset(0),
64162306a36Sopenharmony_ci		BitmapExtent08, StaticReg(0),
64262306a36Sopenharmony_ci		DataDynamic, MaskOtc, BGx(0), FGx(0)));
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	/* Now prepare to write to the "magic" location */
64562306a36Sopenharmony_ci	fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
64662306a36Sopenharmony_ci	NGLE_BINC_SET_DSTADDR(fb, fbAddr);
64762306a36Sopenharmony_ci	NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
64862306a36Sopenharmony_ci	NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	/* Finally, write a zero to clear the mask */
65162306a36Sopenharmony_ci	NGLE_BINC_WRITE32(fb, 0);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	NGLE_UNLOCK(fb);
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic void
65762306a36Sopenharmony_cingleDepth8_ClearImagePlanes(struct stifb_info *fb)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	/* FIXME! */
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic void
66362306a36Sopenharmony_cingleDepth24_ClearImagePlanes(struct stifb_info *fb)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	/* FIXME! */
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cistatic void
66962306a36Sopenharmony_cingleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	int nFreeFifoSlots = 0;
67262306a36Sopenharmony_ci	u32 packed_dst;
67362306a36Sopenharmony_ci	u32 packed_len;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	NGLE_LOCK(fb);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
67862306a36Sopenharmony_ci	NGLE_QUICK_SET_DST_BM_ACCESS(fb,
67962306a36Sopenharmony_ci				     BA(IndexedDcd, Otc32, OtsIndirect,
68062306a36Sopenharmony_ci					AddrLong, BAJustPoint(0),
68162306a36Sopenharmony_ci					BINattr, BAIndexBase(0)));
68262306a36Sopenharmony_ci	NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
68362306a36Sopenharmony_ci	NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
68662306a36Sopenharmony_ci				       IBOvals(RopSrc, MaskAddrOffset(0),
68762306a36Sopenharmony_ci					       BitmapExtent08, StaticReg(1),
68862306a36Sopenharmony_ci					       DataDynamic, MaskOtc,
68962306a36Sopenharmony_ci					       BGx(0), FGx(0)));
69062306a36Sopenharmony_ci	packed_dst = 0;
69162306a36Sopenharmony_ci	packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
69262306a36Sopenharmony_ci	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
69362306a36Sopenharmony_ci	NGLE_SET_DSTXY(fb, packed_dst);
69462306a36Sopenharmony_ci	SET_LENXY_START_RECFILL(fb, packed_len);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	/*
69762306a36Sopenharmony_ci	 * In order to work around an ELK hardware problem (Buffy doesn't
69862306a36Sopenharmony_ci	 * always flush it's buffers when writing to the attribute
69962306a36Sopenharmony_ci	 * planes), at least 4 pixels must be written to the attribute
70062306a36Sopenharmony_ci	 * planes starting at (X == 1280) and (Y != to the last Y written
70162306a36Sopenharmony_ci	 * by BIF):
70262306a36Sopenharmony_ci	 */
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (fb->id == S9000_ID_A1659A) {   /* ELK_DEVICE_ID */
70562306a36Sopenharmony_ci		/* It's safe to use scanline zero: */
70662306a36Sopenharmony_ci		packed_dst = (1280 << 16);
70762306a36Sopenharmony_ci		GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
70862306a36Sopenharmony_ci		NGLE_SET_DSTXY(fb, packed_dst);
70962306a36Sopenharmony_ci		packed_len = (4 << 16) | 1;
71062306a36Sopenharmony_ci		SET_LENXY_START_RECFILL(fb, packed_len);
71162306a36Sopenharmony_ci	}   /* ELK Hardware Kludge */
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	/**** Finally, set the Control Plane Register back to zero: ****/
71462306a36Sopenharmony_ci	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
71562306a36Sopenharmony_ci	NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	NGLE_UNLOCK(fb);
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic void
72162306a36Sopenharmony_cingleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	int nFreeFifoSlots = 0;
72462306a36Sopenharmony_ci	u32 packed_dst;
72562306a36Sopenharmony_ci	u32 packed_len;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	NGLE_LOCK(fb);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	/* Hardware setup */
73062306a36Sopenharmony_ci	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
73162306a36Sopenharmony_ci	NGLE_QUICK_SET_DST_BM_ACCESS(fb,
73262306a36Sopenharmony_ci				     BA(IndexedDcd, Otc04, Ots08, AddrLong,
73362306a36Sopenharmony_ci					BAJustPoint(0), BINovly, BAIndexBase(0)));
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci        NGLE_SET_TRANSFERDATA(fb, 0xffffffff);  /* Write foreground color */
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci        NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
73862306a36Sopenharmony_ci        NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci        packed_dst = 0;
74162306a36Sopenharmony_ci        packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
74262306a36Sopenharmony_ci        NGLE_SET_DSTXY(fb, packed_dst);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	/* Write zeroes to overlay planes */
74562306a36Sopenharmony_ci	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
74662306a36Sopenharmony_ci				       IBOvals(RopSrc, MaskAddrOffset(0),
74762306a36Sopenharmony_ci					       BitmapExtent08, StaticReg(0),
74862306a36Sopenharmony_ci					       DataDynamic, MaskOtc, BGx(0), FGx(0)));
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci        SET_LENXY_START_RECFILL(fb, packed_len);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	NGLE_UNLOCK(fb);
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic void
75662306a36Sopenharmony_cihyperResetPlanes(struct stifb_info *fb, int enable)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	unsigned int controlPlaneReg;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	NGLE_LOCK(fb);
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (IS_24_DEVICE(fb))
76362306a36Sopenharmony_ci		if (fb->info.var.bits_per_pixel == 32)
76462306a36Sopenharmony_ci			controlPlaneReg = 0x04000F00;
76562306a36Sopenharmony_ci		else
76662306a36Sopenharmony_ci			controlPlaneReg = 0x00000F00;   /* 0x00000800 should be enough, but lets clear all 4 bits */
76762306a36Sopenharmony_ci	else
76862306a36Sopenharmony_ci		controlPlaneReg = 0x00000F00; /* 0x00000100 should be enough, but lets clear all 4 bits */
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	switch (enable) {
77162306a36Sopenharmony_ci	case ENABLE:
77262306a36Sopenharmony_ci		/* clear screen */
77362306a36Sopenharmony_ci		if (IS_24_DEVICE(fb))
77462306a36Sopenharmony_ci			ngleDepth24_ClearImagePlanes(fb);
77562306a36Sopenharmony_ci		else
77662306a36Sopenharmony_ci			ngleDepth8_ClearImagePlanes(fb);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci		/* Paint attribute planes for default case.
77962306a36Sopenharmony_ci		 * On Hyperdrive, this means all windows using overlay cmap 0. */
78062306a36Sopenharmony_ci		ngleResetAttrPlanes(fb, controlPlaneReg);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci		/* clear overlay planes */
78362306a36Sopenharmony_ci	        ngleClearOverlayPlanes(fb, 0xff, 255);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci		/**************************************************
78662306a36Sopenharmony_ci		 ** Also need to counteract ITE settings
78762306a36Sopenharmony_ci		 **************************************************/
78862306a36Sopenharmony_ci		hyperUndoITE(fb);
78962306a36Sopenharmony_ci		break;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	case DISABLE:
79262306a36Sopenharmony_ci		/* clear screen */
79362306a36Sopenharmony_ci		if (IS_24_DEVICE(fb))
79462306a36Sopenharmony_ci			ngleDepth24_ClearImagePlanes(fb);
79562306a36Sopenharmony_ci		else
79662306a36Sopenharmony_ci			ngleDepth8_ClearImagePlanes(fb);
79762306a36Sopenharmony_ci		ngleResetAttrPlanes(fb, controlPlaneReg);
79862306a36Sopenharmony_ci		ngleClearOverlayPlanes(fb, 0xff, 0);
79962306a36Sopenharmony_ci		break;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	case -1:	/* RESET */
80262306a36Sopenharmony_ci		hyperUndoITE(fb);
80362306a36Sopenharmony_ci		ngleResetAttrPlanes(fb, controlPlaneReg);
80462306a36Sopenharmony_ci		break;
80562306a36Sopenharmony_ci    	}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	NGLE_UNLOCK(fb);
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci/* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic void
81362306a36Sopenharmony_cingleGetDeviceRomData(struct stifb_info *fb)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci#if 0
81662306a36Sopenharmony_ciXXX: FIXME: !!!
81762306a36Sopenharmony_ci	int	*pBytePerLongDevDepData;/* data byte == LSB */
81862306a36Sopenharmony_ci	int 	*pRomTable;
81962306a36Sopenharmony_ci	NgleDevRomData	*pPackedDevRomData;
82062306a36Sopenharmony_ci	int	sizePackedDevRomData = sizeof(*pPackedDevRomData);
82162306a36Sopenharmony_ci	char	*pCard8;
82262306a36Sopenharmony_ci	int	i;
82362306a36Sopenharmony_ci	char	*mapOrigin = NULL;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	int romTableIdx;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	pPackedDevRomData = fb->ngle_rom;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	SETUP_HW(fb);
83062306a36Sopenharmony_ci	if (fb->id == S9000_ID_ARTIST) {
83162306a36Sopenharmony_ci		pPackedDevRomData->cursor_pipeline_delay = 4;
83262306a36Sopenharmony_ci		pPackedDevRomData->video_interleaves     = 4;
83362306a36Sopenharmony_ci	} else {
83462306a36Sopenharmony_ci		/* Get pointer to unpacked byte/long data in ROM */
83562306a36Sopenharmony_ci		pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci		/* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
83862306a36Sopenharmony_ci		if (fb->id == S9000_ID_TOMCAT)
83962306a36Sopenharmony_ci	{
84062306a36Sopenharmony_ci	    /*  jump to the correct ROM table  */
84162306a36Sopenharmony_ci	    GET_ROMTABLE_INDEX(romTableIdx);
84262306a36Sopenharmony_ci	    while  (romTableIdx > 0)
84362306a36Sopenharmony_ci	    {
84462306a36Sopenharmony_ci		pCard8 = (Card8 *) pPackedDevRomData;
84562306a36Sopenharmony_ci		pRomTable = pBytePerLongDevDepData;
84662306a36Sopenharmony_ci		/* Pack every fourth byte from ROM into structure */
84762306a36Sopenharmony_ci		for (i = 0; i < sizePackedDevRomData; i++)
84862306a36Sopenharmony_ci		{
84962306a36Sopenharmony_ci		    *pCard8++ = (Card8) (*pRomTable++);
85062306a36Sopenharmony_ci		}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci		pBytePerLongDevDepData = (Card32 *)
85362306a36Sopenharmony_ci			((Card8 *) pBytePerLongDevDepData +
85462306a36Sopenharmony_ci			       pPackedDevRomData->sizeof_ngle_data);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci		romTableIdx--;
85762306a36Sopenharmony_ci	    }
85862306a36Sopenharmony_ci	}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	pCard8 = (Card8 *) pPackedDevRomData;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	/* Pack every fourth byte from ROM into structure */
86362306a36Sopenharmony_ci	for (i = 0; i < sizePackedDevRomData; i++)
86462306a36Sopenharmony_ci	{
86562306a36Sopenharmony_ci	    *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci    }
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci    SETUP_FB(fb);
87062306a36Sopenharmony_ci#endif
87162306a36Sopenharmony_ci}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci#define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES	4
87562306a36Sopenharmony_ci#define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE	8
87662306a36Sopenharmony_ci#define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE		10
87762306a36Sopenharmony_ci#define HYPERBOWL_MODE2_8_24					15
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci/* HCRX specific boot-time initialization */
88062306a36Sopenharmony_cistatic void __init
88162306a36Sopenharmony_ciSETUP_HCRX(struct stifb_info *fb)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	int	hyperbowl;
88462306a36Sopenharmony_ci        int	nFreeFifoSlots = 0;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	if (fb->id != S9000_ID_HCRX)
88762306a36Sopenharmony_ci		return;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	/* Initialize Hyperbowl registers */
89062306a36Sopenharmony_ci	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	if (IS_24_DEVICE(fb)) {
89362306a36Sopenharmony_ci		hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
89462306a36Sopenharmony_ci			HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
89562306a36Sopenharmony_ci			HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci		/* First write to Hyperbowl must happen twice (bug) */
89862306a36Sopenharmony_ci		WRITE_WORD(hyperbowl, fb, REG_40);
89962306a36Sopenharmony_ci		WRITE_WORD(hyperbowl, fb, REG_40);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci		WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci		WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
90462306a36Sopenharmony_ci		WRITE_WORD(0x404c4048, fb, REG_43);
90562306a36Sopenharmony_ci		WRITE_WORD(0x034c0348, fb, REG_44);
90662306a36Sopenharmony_ci		WRITE_WORD(0x444c4448, fb, REG_45);
90762306a36Sopenharmony_ci	} else {
90862306a36Sopenharmony_ci		hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci		/* First write to Hyperbowl must happen twice (bug) */
91162306a36Sopenharmony_ci		WRITE_WORD(hyperbowl, fb, REG_40);
91262306a36Sopenharmony_ci		WRITE_WORD(hyperbowl, fb, REG_40);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci		WRITE_WORD(0x00000000, fb, REG_42);
91562306a36Sopenharmony_ci		WRITE_WORD(0x00000000, fb, REG_43);
91662306a36Sopenharmony_ci		WRITE_WORD(0x00000000, fb, REG_44);
91762306a36Sopenharmony_ci		WRITE_WORD(0x444c4048, fb, REG_45);
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci/* ------------------- driver specific functions --------------------------- */
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cistatic int
92562306a36Sopenharmony_cistifb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	struct stifb_info *fb = container_of(info, struct stifb_info, info);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	if (var->xres != fb->info.var.xres ||
93062306a36Sopenharmony_ci	    var->yres != fb->info.var.yres ||
93162306a36Sopenharmony_ci	    var->bits_per_pixel != fb->info.var.bits_per_pixel)
93262306a36Sopenharmony_ci		return -EINVAL;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	var->xres_virtual = var->xres;
93562306a36Sopenharmony_ci	var->yres_virtual = var->yres;
93662306a36Sopenharmony_ci	var->xoffset = 0;
93762306a36Sopenharmony_ci	var->yoffset = 0;
93862306a36Sopenharmony_ci	var->grayscale = fb->info.var.grayscale;
93962306a36Sopenharmony_ci	var->red.length = fb->info.var.red.length;
94062306a36Sopenharmony_ci	var->green.length = fb->info.var.green.length;
94162306a36Sopenharmony_ci	var->blue.length = fb->info.var.blue.length;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	return 0;
94462306a36Sopenharmony_ci}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_cistatic int
94762306a36Sopenharmony_cistifb_setcolreg(u_int regno, u_int red, u_int green,
94862306a36Sopenharmony_ci	      u_int blue, u_int transp, struct fb_info *info)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	struct stifb_info *fb = container_of(info, struct stifb_info, info);
95162306a36Sopenharmony_ci	u32 color;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	if (regno >= NR_PALETTE)
95462306a36Sopenharmony_ci		return 1;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	red   >>= 8;
95762306a36Sopenharmony_ci	green >>= 8;
95862306a36Sopenharmony_ci	blue  >>= 8;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	DEBUG_OFF();
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	START_IMAGE_COLORMAP_ACCESS(fb);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	if (unlikely(fb->info.var.grayscale)) {
96562306a36Sopenharmony_ci		/* gray = 0.30*R + 0.59*G + 0.11*B */
96662306a36Sopenharmony_ci		color = ((red * 77) +
96762306a36Sopenharmony_ci			 (green * 151) +
96862306a36Sopenharmony_ci			 (blue * 28)) >> 8;
96962306a36Sopenharmony_ci	} else {
97062306a36Sopenharmony_ci		color = ((red << 16) |
97162306a36Sopenharmony_ci			 (green << 8) |
97262306a36Sopenharmony_ci			 (blue));
97362306a36Sopenharmony_ci	}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
97662306a36Sopenharmony_ci		struct fb_var_screeninfo *var = &fb->info.var;
97762306a36Sopenharmony_ci		if (regno < 16)
97862306a36Sopenharmony_ci			((u32 *)fb->info.pseudo_palette)[regno] =
97962306a36Sopenharmony_ci				regno << var->red.offset |
98062306a36Sopenharmony_ci				regno << var->green.offset |
98162306a36Sopenharmony_ci				regno << var->blue.offset;
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	WRITE_IMAGE_COLOR(fb, regno, color);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	if (fb->id == S9000_ID_HCRX) {
98762306a36Sopenharmony_ci		NgleLutBltCtl lutBltCtl;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci		lutBltCtl = setHyperLutBltCtl(fb,
99062306a36Sopenharmony_ci				0,	/* Offset w/i LUT */
99162306a36Sopenharmony_ci				256);	/* Load entire LUT */
99262306a36Sopenharmony_ci		NGLE_BINC_SET_SRCADDR(fb,
99362306a36Sopenharmony_ci				NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
99462306a36Sopenharmony_ci				/* 0x100 is same as used in WRITE_IMAGE_COLOR() */
99562306a36Sopenharmony_ci		START_COLORMAPLOAD(fb, lutBltCtl.all);
99662306a36Sopenharmony_ci		SETUP_FB(fb);
99762306a36Sopenharmony_ci	} else {
99862306a36Sopenharmony_ci		/* cleanup colormap hardware */
99962306a36Sopenharmony_ci		FINISH_IMAGE_COLORMAP_ACCESS(fb);
100062306a36Sopenharmony_ci	}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	DEBUG_ON();
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	return 0;
100562306a36Sopenharmony_ci}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_cistatic int
100862306a36Sopenharmony_cistifb_blank(int blank_mode, struct fb_info *info)
100962306a36Sopenharmony_ci{
101062306a36Sopenharmony_ci	struct stifb_info *fb = container_of(info, struct stifb_info, info);
101162306a36Sopenharmony_ci	int enable = (blank_mode == 0) ? ENABLE : DISABLE;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	switch (fb->id) {
101462306a36Sopenharmony_ci	case S9000_ID_A1439A:
101562306a36Sopenharmony_ci		CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
101662306a36Sopenharmony_ci		break;
101762306a36Sopenharmony_ci	case CRT_ID_VISUALIZE_EG:
101862306a36Sopenharmony_ci	case S9000_ID_ARTIST:
101962306a36Sopenharmony_ci		ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
102062306a36Sopenharmony_ci		break;
102162306a36Sopenharmony_ci	case S9000_ID_HCRX:
102262306a36Sopenharmony_ci		HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
102362306a36Sopenharmony_ci		break;
102462306a36Sopenharmony_ci	case S9000_ID_A1659A:
102562306a36Sopenharmony_ci	case S9000_ID_TIMBER:
102662306a36Sopenharmony_ci	case CRX24_OVERLAY_PLANES:
102762306a36Sopenharmony_ci	default:
102862306a36Sopenharmony_ci		ENABLE_DISABLE_DISPLAY(fb, enable);
102962306a36Sopenharmony_ci		break;
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	SETUP_FB(fb);
103362306a36Sopenharmony_ci	return 0;
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cistatic void
103762306a36Sopenharmony_cistifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
103862306a36Sopenharmony_ci{
103962306a36Sopenharmony_ci	struct stifb_info *fb = container_of(info, struct stifb_info, info);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	SETUP_COPYAREA(fb);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	SETUP_HW(fb);
104462306a36Sopenharmony_ci	if (fb->info.var.bits_per_pixel == 32) {
104562306a36Sopenharmony_ci		WRITE_WORD(0xBBA0A000, fb, REG_10);
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
104862306a36Sopenharmony_ci	} else {
104962306a36Sopenharmony_ci		WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
105262306a36Sopenharmony_ci	}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
105562306a36Sopenharmony_ci		IBOvals(RopSrc, MaskAddrOffset(0),
105662306a36Sopenharmony_ci		BitmapExtent08, StaticReg(1),
105762306a36Sopenharmony_ci		DataDynamic, MaskOtc, BGx(0), FGx(0)));
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	WRITE_WORD(((area->sx << 16) | area->sy), fb, REG_24);
106062306a36Sopenharmony_ci	WRITE_WORD(((area->width << 16) | area->height), fb, REG_7);
106162306a36Sopenharmony_ci	WRITE_WORD(((area->dx << 16) | area->dy), fb, REG_25);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	SETUP_FB(fb);
106462306a36Sopenharmony_ci}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci#define ARTIST_VRAM_SIZE			0x000804
106762306a36Sopenharmony_ci#define ARTIST_VRAM_SRC				0x000808
106862306a36Sopenharmony_ci#define ARTIST_VRAM_SIZE_TRIGGER_WINFILL	0x000a04
106962306a36Sopenharmony_ci#define ARTIST_VRAM_DEST_TRIGGER_BLOCKMOVE	0x000b00
107062306a36Sopenharmony_ci#define ARTIST_SRC_BM_ACCESS			0x018008
107162306a36Sopenharmony_ci#define ARTIST_FGCOLOR				0x018010
107262306a36Sopenharmony_ci#define ARTIST_BGCOLOR				0x018014
107362306a36Sopenharmony_ci#define ARTIST_BITMAP_OP			0x01801c
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_cistatic void
107662306a36Sopenharmony_cistifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
107762306a36Sopenharmony_ci{
107862306a36Sopenharmony_ci	struct stifb_info *fb = container_of(info, struct stifb_info, info);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	if (rect->rop != ROP_COPY ||
108162306a36Sopenharmony_ci	    (fb->id == S9000_ID_HCRX && fb->info.var.bits_per_pixel == 32))
108262306a36Sopenharmony_ci		return cfb_fillrect(info, rect);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	SETUP_HW(fb);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	if (fb->info.var.bits_per_pixel == 32) {
108762306a36Sopenharmony_ci		WRITE_WORD(0xBBA0A000, fb, REG_10);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
109062306a36Sopenharmony_ci	} else {
109162306a36Sopenharmony_ci		WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
109462306a36Sopenharmony_ci	}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	WRITE_WORD(0x03000300, fb, ARTIST_BITMAP_OP);
109762306a36Sopenharmony_ci	WRITE_WORD(0x2ea01000, fb, ARTIST_SRC_BM_ACCESS);
109862306a36Sopenharmony_ci	NGLE_QUICK_SET_DST_BM_ACCESS(fb, 0x2ea01000);
109962306a36Sopenharmony_ci	NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, rect->color);
110062306a36Sopenharmony_ci	WRITE_WORD(0, fb, ARTIST_BGCOLOR);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	NGLE_SET_DSTXY(fb, (rect->dx << 16) | (rect->dy));
110362306a36Sopenharmony_ci	SET_LENXY_START_RECFILL(fb, (rect->width << 16) | (rect->height));
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	SETUP_FB(fb);
110662306a36Sopenharmony_ci}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_cistatic void __init
110962306a36Sopenharmony_cistifb_init_display(struct stifb_info *fb)
111062306a36Sopenharmony_ci{
111162306a36Sopenharmony_ci	int id = fb->id;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	SETUP_FB(fb);
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	/* HCRX specific initialization */
111662306a36Sopenharmony_ci	SETUP_HCRX(fb);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	/*
111962306a36Sopenharmony_ci	if (id == S9000_ID_HCRX)
112062306a36Sopenharmony_ci		hyperInitSprite(fb);
112162306a36Sopenharmony_ci	else
112262306a36Sopenharmony_ci		ngleInitSprite(fb);
112362306a36Sopenharmony_ci	*/
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	/* Initialize the image planes. */
112662306a36Sopenharmony_ci        switch (id) {
112762306a36Sopenharmony_ci	 case S9000_ID_HCRX:
112862306a36Sopenharmony_ci	    hyperResetPlanes(fb, ENABLE);
112962306a36Sopenharmony_ci	    break;
113062306a36Sopenharmony_ci	 case S9000_ID_A1439A:
113162306a36Sopenharmony_ci	    rattlerSetupPlanes(fb);
113262306a36Sopenharmony_ci	    break;
113362306a36Sopenharmony_ci	 case S9000_ID_A1659A:
113462306a36Sopenharmony_ci	 case S9000_ID_ARTIST:
113562306a36Sopenharmony_ci	 case CRT_ID_VISUALIZE_EG:
113662306a36Sopenharmony_ci	    elkSetupPlanes(fb);
113762306a36Sopenharmony_ci	    break;
113862306a36Sopenharmony_ci	}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	/* Clear attribute planes on non HCRX devices. */
114162306a36Sopenharmony_ci        switch (id) {
114262306a36Sopenharmony_ci	 case S9000_ID_A1659A:
114362306a36Sopenharmony_ci	 case S9000_ID_A1439A:
114462306a36Sopenharmony_ci	    if (fb->info.var.bits_per_pixel == 32)
114562306a36Sopenharmony_ci		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
114662306a36Sopenharmony_ci	    else {
114762306a36Sopenharmony_ci		ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
114862306a36Sopenharmony_ci	    }
114962306a36Sopenharmony_ci	    if (id == S9000_ID_A1439A)
115062306a36Sopenharmony_ci		ngleClearOverlayPlanes(fb, 0xff, 0);
115162306a36Sopenharmony_ci	    break;
115262306a36Sopenharmony_ci	 case S9000_ID_ARTIST:
115362306a36Sopenharmony_ci	 case CRT_ID_VISUALIZE_EG:
115462306a36Sopenharmony_ci	    if (fb->info.var.bits_per_pixel == 32)
115562306a36Sopenharmony_ci		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
115662306a36Sopenharmony_ci	    else {
115762306a36Sopenharmony_ci		ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
115862306a36Sopenharmony_ci	    }
115962306a36Sopenharmony_ci	    break;
116062306a36Sopenharmony_ci	}
116162306a36Sopenharmony_ci	stifb_blank(0, (struct fb_info *)fb);	/* 0=enable screen */
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	SETUP_FB(fb);
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci/* ------------ Interfaces to hardware functions ------------ */
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_cistatic const struct fb_ops stifb_ops = {
116962306a36Sopenharmony_ci	.owner		= THIS_MODULE,
117062306a36Sopenharmony_ci	.fb_check_var	= stifb_check_var,
117162306a36Sopenharmony_ci	.fb_setcolreg	= stifb_setcolreg,
117262306a36Sopenharmony_ci	.fb_blank	= stifb_blank,
117362306a36Sopenharmony_ci	.fb_fillrect	= stifb_fillrect,
117462306a36Sopenharmony_ci	.fb_copyarea	= stifb_copyarea,
117562306a36Sopenharmony_ci	.fb_imageblit	= cfb_imageblit,
117662306a36Sopenharmony_ci};
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci/*
118062306a36Sopenharmony_ci *  Initialization
118162306a36Sopenharmony_ci */
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_cistatic int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	struct fb_fix_screeninfo *fix;
118662306a36Sopenharmony_ci	struct fb_var_screeninfo *var;
118762306a36Sopenharmony_ci	struct stifb_info *fb;
118862306a36Sopenharmony_ci	struct fb_info *info;
118962306a36Sopenharmony_ci	unsigned long sti_rom_address;
119062306a36Sopenharmony_ci	char modestr[32];
119162306a36Sopenharmony_ci	char *dev_name;
119262306a36Sopenharmony_ci	int bpp, xres, yres;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
119562306a36Sopenharmony_ci	if (!fb)
119662306a36Sopenharmony_ci		return -ENOMEM;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	info = &fb->info;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	/* set struct to a known state */
120162306a36Sopenharmony_ci	fix = &info->fix;
120262306a36Sopenharmony_ci	var = &info->var;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	fb->sti = sti;
120562306a36Sopenharmony_ci	dev_name = sti->sti_data->inq_outptr.dev_name;
120662306a36Sopenharmony_ci	/* store upper 32bits of the graphics id */
120762306a36Sopenharmony_ci	fb->id = fb->sti->graphics_id[0];
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	/* only supported cards are allowed */
121062306a36Sopenharmony_ci	switch (fb->id) {
121162306a36Sopenharmony_ci	case CRT_ID_VISUALIZE_EG:
121262306a36Sopenharmony_ci		/* Visualize cards can run either in "double buffer" or
121362306a36Sopenharmony_ci 		  "standard" mode. Depending on the mode, the card reports
121462306a36Sopenharmony_ci		  a different device name, e.g. "INTERNAL_EG_DX1024" in double
121562306a36Sopenharmony_ci		  buffer mode and "INTERNAL_EG_X1024" in standard mode.
121662306a36Sopenharmony_ci		  Since this driver only supports standard mode, we check
121762306a36Sopenharmony_ci		  if the device name contains the string "DX" and tell the
121862306a36Sopenharmony_ci		  user how to reconfigure the card. */
121962306a36Sopenharmony_ci		if (strstr(dev_name, "DX")) {
122062306a36Sopenharmony_ci		   printk(KERN_WARNING
122162306a36Sopenharmony_ci"WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
122262306a36Sopenharmony_ci"WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
122362306a36Sopenharmony_ci			dev_name);
122462306a36Sopenharmony_ci		   goto out_err0;
122562306a36Sopenharmony_ci		}
122662306a36Sopenharmony_ci		fallthrough;
122762306a36Sopenharmony_ci	case S9000_ID_ARTIST:
122862306a36Sopenharmony_ci	case S9000_ID_HCRX:
122962306a36Sopenharmony_ci	case S9000_ID_TIMBER:
123062306a36Sopenharmony_ci	case S9000_ID_A1659A:
123162306a36Sopenharmony_ci	case S9000_ID_A1439A:
123262306a36Sopenharmony_ci		break;
123362306a36Sopenharmony_ci	default:
123462306a36Sopenharmony_ci		printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
123562306a36Sopenharmony_ci			dev_name, fb->id);
123662306a36Sopenharmony_ci		goto out_err0;
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	/* default to 8 bpp on most graphic chips */
124062306a36Sopenharmony_ci	bpp = 8;
124162306a36Sopenharmony_ci	xres = sti_onscreen_x(fb->sti);
124262306a36Sopenharmony_ci	yres = sti_onscreen_y(fb->sti);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	ngleGetDeviceRomData(fb);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	/* get (virtual) io region base addr */
124762306a36Sopenharmony_ci	fix->mmio_start = REGION_BASE(fb,2);
124862306a36Sopenharmony_ci	fix->mmio_len   = 0x400000;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci       	/* Reject any device not in the NGLE family */
125162306a36Sopenharmony_ci	switch (fb->id) {
125262306a36Sopenharmony_ci	case S9000_ID_A1659A:	/* CRX/A1659A */
125362306a36Sopenharmony_ci		break;
125462306a36Sopenharmony_ci	case S9000_ID_ELM:	/* GRX, grayscale but else same as A1659A */
125562306a36Sopenharmony_ci		var->grayscale = 1;
125662306a36Sopenharmony_ci		fb->id = S9000_ID_A1659A;
125762306a36Sopenharmony_ci		break;
125862306a36Sopenharmony_ci	case S9000_ID_TIMBER:	/* HP9000/710 Any (may be a grayscale device) */
125962306a36Sopenharmony_ci		if (strstr(dev_name, "GRAYSCALE") ||
126062306a36Sopenharmony_ci		    strstr(dev_name, "Grayscale") ||
126162306a36Sopenharmony_ci		    strstr(dev_name, "grayscale"))
126262306a36Sopenharmony_ci			var->grayscale = 1;
126362306a36Sopenharmony_ci		break;
126462306a36Sopenharmony_ci	case S9000_ID_TOMCAT:	/* Dual CRX, behaves else like a CRX */
126562306a36Sopenharmony_ci		/* FIXME: TomCat supports two heads:
126662306a36Sopenharmony_ci		 * fb.iobase = REGION_BASE(fb_info,3);
126762306a36Sopenharmony_ci		 * fb.screen_base = ioremap(REGION_BASE(fb_info,2),xxx);
126862306a36Sopenharmony_ci		 * for now we only support the left one ! */
126962306a36Sopenharmony_ci		xres = fb->ngle_rom.x_size_visible;
127062306a36Sopenharmony_ci		yres = fb->ngle_rom.y_size_visible;
127162306a36Sopenharmony_ci		fb->id = S9000_ID_A1659A;
127262306a36Sopenharmony_ci		break;
127362306a36Sopenharmony_ci	case S9000_ID_A1439A:	/* CRX24/A1439A */
127462306a36Sopenharmony_ci		bpp = 32;
127562306a36Sopenharmony_ci		break;
127662306a36Sopenharmony_ci	case S9000_ID_HCRX:	/* Hyperdrive/HCRX */
127762306a36Sopenharmony_ci		memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
127862306a36Sopenharmony_ci		if ((fb->sti->regions_phys[0] & 0xfc000000) ==
127962306a36Sopenharmony_ci		    (fb->sti->regions_phys[2] & 0xfc000000))
128062306a36Sopenharmony_ci			sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
128162306a36Sopenharmony_ci		else
128262306a36Sopenharmony_ci			sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci		fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
128562306a36Sopenharmony_ci		if (IS_24_DEVICE(fb)) {
128662306a36Sopenharmony_ci			if (bpp_pref == 8 || bpp_pref == 32)
128762306a36Sopenharmony_ci				bpp = bpp_pref;
128862306a36Sopenharmony_ci			else
128962306a36Sopenharmony_ci				bpp = 32;
129062306a36Sopenharmony_ci		} else
129162306a36Sopenharmony_ci			bpp = 8;
129262306a36Sopenharmony_ci		READ_WORD(fb, REG_15);
129362306a36Sopenharmony_ci		SETUP_HW(fb);
129462306a36Sopenharmony_ci		break;
129562306a36Sopenharmony_ci	case CRT_ID_VISUALIZE_EG:
129662306a36Sopenharmony_ci	case S9000_ID_ARTIST:	/* Artist */
129762306a36Sopenharmony_ci		break;
129862306a36Sopenharmony_ci	default:
129962306a36Sopenharmony_ci#ifdef FALLBACK_TO_1BPP
130062306a36Sopenharmony_ci		printk(KERN_WARNING
130162306a36Sopenharmony_ci			"stifb: Unsupported graphics card (id=0x%08x) "
130262306a36Sopenharmony_ci				"- now trying 1bpp mode instead\n",
130362306a36Sopenharmony_ci			fb->id);
130462306a36Sopenharmony_ci		bpp = 1;	/* default to 1 bpp */
130562306a36Sopenharmony_ci		break;
130662306a36Sopenharmony_ci#else
130762306a36Sopenharmony_ci		printk(KERN_WARNING
130862306a36Sopenharmony_ci			"stifb: Unsupported graphics card (id=0x%08x) "
130962306a36Sopenharmony_ci				"- skipping.\n",
131062306a36Sopenharmony_ci			fb->id);
131162306a36Sopenharmony_ci		goto out_err0;
131262306a36Sopenharmony_ci#endif
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	/* get framebuffer physical and virtual base addr & len (64bit ready) */
131762306a36Sopenharmony_ci	fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
131862306a36Sopenharmony_ci	fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
132162306a36Sopenharmony_ci	if (!fix->line_length)
132262306a36Sopenharmony_ci		fix->line_length = 2048; /* default */
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	/* limit fbsize to max visible screen size */
132562306a36Sopenharmony_ci	if (fix->smem_len > yres*fix->line_length)
132662306a36Sopenharmony_ci		fix->smem_len = ALIGN(yres*fix->line_length, 4*1024*1024);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	fix->accel = FB_ACCEL_NONE;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	switch (bpp) {
133162306a36Sopenharmony_ci	    case 1:
133262306a36Sopenharmony_ci		fix->type = FB_TYPE_PLANES;	/* well, sort of */
133362306a36Sopenharmony_ci		fix->visual = FB_VISUAL_MONO10;
133462306a36Sopenharmony_ci		var->red.length = var->green.length = var->blue.length = 1;
133562306a36Sopenharmony_ci		break;
133662306a36Sopenharmony_ci	    case 8:
133762306a36Sopenharmony_ci		fix->type = FB_TYPE_PACKED_PIXELS;
133862306a36Sopenharmony_ci		fix->visual = FB_VISUAL_PSEUDOCOLOR;
133962306a36Sopenharmony_ci		var->red.length = var->green.length = var->blue.length = 8;
134062306a36Sopenharmony_ci		break;
134162306a36Sopenharmony_ci	    case 32:
134262306a36Sopenharmony_ci		fix->type = FB_TYPE_PACKED_PIXELS;
134362306a36Sopenharmony_ci		fix->visual = FB_VISUAL_DIRECTCOLOR;
134462306a36Sopenharmony_ci		var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
134562306a36Sopenharmony_ci		var->blue.offset = 0;
134662306a36Sopenharmony_ci		var->green.offset = 8;
134762306a36Sopenharmony_ci		var->red.offset = 16;
134862306a36Sopenharmony_ci		var->transp.offset = 24;
134962306a36Sopenharmony_ci		break;
135062306a36Sopenharmony_ci	    default:
135162306a36Sopenharmony_ci		break;
135262306a36Sopenharmony_ci	}
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	var->xres = var->xres_virtual = xres;
135562306a36Sopenharmony_ci	var->yres = var->yres_virtual = yres;
135662306a36Sopenharmony_ci	var->bits_per_pixel = bpp;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	strcpy(fix->id, "stifb");
135962306a36Sopenharmony_ci	info->fbops = &stifb_ops;
136062306a36Sopenharmony_ci	info->screen_base = ioremap(REGION_BASE(fb,1), fix->smem_len);
136162306a36Sopenharmony_ci	if (!info->screen_base) {
136262306a36Sopenharmony_ci		printk(KERN_ERR "stifb: failed to map memory\n");
136362306a36Sopenharmony_ci		goto out_err0;
136462306a36Sopenharmony_ci	}
136562306a36Sopenharmony_ci	info->screen_size = fix->smem_len;
136662306a36Sopenharmony_ci	info->flags = FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
136762306a36Sopenharmony_ci	info->pseudo_palette = &fb->pseudo_palette;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	scnprintf(modestr, sizeof(modestr), "%dx%d-%d", xres, yres, bpp);
137062306a36Sopenharmony_ci	fb_find_mode(&info->var, info, modestr, NULL, 0, NULL, bpp);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	/* This has to be done !!! */
137362306a36Sopenharmony_ci	if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
137462306a36Sopenharmony_ci		goto out_err1;
137562306a36Sopenharmony_ci	stifb_init_display(fb);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
137862306a36Sopenharmony_ci		printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
137962306a36Sopenharmony_ci				fix->smem_start, fix->smem_start+fix->smem_len);
138062306a36Sopenharmony_ci		goto out_err2;
138162306a36Sopenharmony_ci	}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
138462306a36Sopenharmony_ci		printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
138562306a36Sopenharmony_ci				fix->mmio_start, fix->mmio_start+fix->mmio_len);
138662306a36Sopenharmony_ci		goto out_err3;
138762306a36Sopenharmony_ci	}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	/* save for primary gfx device detection & unregister_framebuffer() */
139062306a36Sopenharmony_ci	sti->info = info;
139162306a36Sopenharmony_ci	if (register_framebuffer(&fb->info) < 0)
139262306a36Sopenharmony_ci		goto out_err4;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	fb_info(&fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
139562306a36Sopenharmony_ci		fix->id,
139662306a36Sopenharmony_ci		var->xres,
139762306a36Sopenharmony_ci		var->yres,
139862306a36Sopenharmony_ci		var->bits_per_pixel,
139962306a36Sopenharmony_ci		dev_name,
140062306a36Sopenharmony_ci		fb->id,
140162306a36Sopenharmony_ci		fix->mmio_start);
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	return 0;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ciout_err4:
140762306a36Sopenharmony_ci	release_mem_region(fix->mmio_start, fix->mmio_len);
140862306a36Sopenharmony_ciout_err3:
140962306a36Sopenharmony_ci	release_mem_region(fix->smem_start, fix->smem_len);
141062306a36Sopenharmony_ciout_err2:
141162306a36Sopenharmony_ci	fb_dealloc_cmap(&info->cmap);
141262306a36Sopenharmony_ciout_err1:
141362306a36Sopenharmony_ci	iounmap(info->screen_base);
141462306a36Sopenharmony_ciout_err0:
141562306a36Sopenharmony_ci	kfree(fb);
141662306a36Sopenharmony_ci	sti->info = NULL;
141762306a36Sopenharmony_ci	return -ENXIO;
141862306a36Sopenharmony_ci}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_cistatic int stifb_disabled __initdata;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ciint __init
142362306a36Sopenharmony_cistifb_setup(char *options);
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_cistatic int __init stifb_init(void)
142662306a36Sopenharmony_ci{
142762306a36Sopenharmony_ci	struct sti_struct *sti;
142862306a36Sopenharmony_ci	struct sti_struct *def_sti;
142962306a36Sopenharmony_ci	int i;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci#ifndef MODULE
143262306a36Sopenharmony_ci	char *option = NULL;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	if (fb_get_options("stifb", &option))
143562306a36Sopenharmony_ci		return -ENODEV;
143662306a36Sopenharmony_ci	stifb_setup(option);
143762306a36Sopenharmony_ci#endif
143862306a36Sopenharmony_ci	if (stifb_disabled) {
143962306a36Sopenharmony_ci		printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
144062306a36Sopenharmony_ci		return -ENXIO;
144162306a36Sopenharmony_ci	}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	def_sti = sti_get_rom(0);
144462306a36Sopenharmony_ci	if (def_sti) {
144562306a36Sopenharmony_ci		for (i = 1; i <= MAX_STI_ROMS; i++) {
144662306a36Sopenharmony_ci			sti = sti_get_rom(i);
144762306a36Sopenharmony_ci			if (!sti)
144862306a36Sopenharmony_ci				break;
144962306a36Sopenharmony_ci			if (sti == def_sti) {
145062306a36Sopenharmony_ci				stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
145162306a36Sopenharmony_ci				break;
145262306a36Sopenharmony_ci			}
145362306a36Sopenharmony_ci		}
145462306a36Sopenharmony_ci	}
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	for (i = 1; i <= MAX_STI_ROMS; i++) {
145762306a36Sopenharmony_ci		sti = sti_get_rom(i);
145862306a36Sopenharmony_ci		if (!sti)
145962306a36Sopenharmony_ci			break;
146062306a36Sopenharmony_ci		if (sti == def_sti)
146162306a36Sopenharmony_ci			continue;
146262306a36Sopenharmony_ci		stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
146362306a36Sopenharmony_ci	}
146462306a36Sopenharmony_ci	return 0;
146562306a36Sopenharmony_ci}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci/*
146862306a36Sopenharmony_ci *  Cleanup
146962306a36Sopenharmony_ci */
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_cistatic void __exit
147262306a36Sopenharmony_cistifb_cleanup(void)
147362306a36Sopenharmony_ci{
147462306a36Sopenharmony_ci	struct sti_struct *sti;
147562306a36Sopenharmony_ci	int i;
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	for (i = 1; i <= MAX_STI_ROMS; i++) {
147862306a36Sopenharmony_ci		sti = sti_get_rom(i);
147962306a36Sopenharmony_ci		if (!sti)
148062306a36Sopenharmony_ci			break;
148162306a36Sopenharmony_ci		if (sti->info) {
148262306a36Sopenharmony_ci			struct fb_info *info = sti->info;
148362306a36Sopenharmony_ci			unregister_framebuffer(sti->info);
148462306a36Sopenharmony_ci			release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
148562306a36Sopenharmony_ci		        release_mem_region(info->fix.smem_start, info->fix.smem_len);
148662306a36Sopenharmony_ci				if (info->screen_base)
148762306a36Sopenharmony_ci					iounmap(info->screen_base);
148862306a36Sopenharmony_ci		        fb_dealloc_cmap(&info->cmap);
148962306a36Sopenharmony_ci		        framebuffer_release(info);
149062306a36Sopenharmony_ci		}
149162306a36Sopenharmony_ci		sti->info = NULL;
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ciint __init
149662306a36Sopenharmony_cistifb_setup(char *options)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	int i;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	if (!options || !*options)
150162306a36Sopenharmony_ci		return 1;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	if (strncmp(options, "off", 3) == 0) {
150462306a36Sopenharmony_ci		stifb_disabled = 1;
150562306a36Sopenharmony_ci		options += 3;
150662306a36Sopenharmony_ci	}
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	if (strncmp(options, "bpp", 3) == 0) {
150962306a36Sopenharmony_ci		options += 3;
151062306a36Sopenharmony_ci		for (i = 0; i < MAX_STI_ROMS; i++) {
151162306a36Sopenharmony_ci			if (*options++ != ':')
151262306a36Sopenharmony_ci				break;
151362306a36Sopenharmony_ci			stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
151462306a36Sopenharmony_ci		}
151562306a36Sopenharmony_ci	}
151662306a36Sopenharmony_ci	return 1;
151762306a36Sopenharmony_ci}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci__setup("stifb=", stifb_setup);
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_cimodule_init(stifb_init);
152262306a36Sopenharmony_cimodule_exit(stifb_cleanup);
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ciMODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
152562306a36Sopenharmony_ciMODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
152662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1527