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