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