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