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