xref: /openbmc/linux/drivers/video/fbdev/stifb.c (revision d2a8e92f)
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 <linux/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 		fb_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:
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 #define ARTIST_VRAM_SIZE			0x000804
1045 #define ARTIST_VRAM_SRC				0x000808
1046 #define ARTIST_VRAM_SIZE_TRIGGER_WINFILL	0x000a04
1047 #define ARTIST_VRAM_DEST_TRIGGER_BLOCKMOVE	0x000b00
1048 #define ARTIST_SRC_BM_ACCESS			0x018008
1049 #define ARTIST_FGCOLOR				0x018010
1050 #define ARTIST_BGCOLOR				0x018014
1051 #define ARTIST_BITMAP_OP			0x01801c
1052 
1053 static void
1054 stifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
1055 {
1056 	struct stifb_info *fb = container_of(info, struct stifb_info, info);
1057 
1058 	if (rect->rop != ROP_COPY ||
1059 	    (fb->id == S9000_ID_HCRX && fb->info.var.bits_per_pixel == 32))
1060 		return cfb_fillrect(info, rect);
1061 
1062 	SETUP_HW(fb);
1063 
1064 	if (fb->info.var.bits_per_pixel == 32) {
1065 		WRITE_WORD(0xBBA0A000, fb, REG_10);
1066 
1067 		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
1068 	} else {
1069 		WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
1070 
1071 		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
1072 	}
1073 
1074 	WRITE_WORD(0x03000300, fb, ARTIST_BITMAP_OP);
1075 	WRITE_WORD(0x2ea01000, fb, ARTIST_SRC_BM_ACCESS);
1076 	NGLE_QUICK_SET_DST_BM_ACCESS(fb, 0x2ea01000);
1077 	NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, rect->color);
1078 	WRITE_WORD(0, fb, ARTIST_BGCOLOR);
1079 
1080 	NGLE_SET_DSTXY(fb, (rect->dx << 16) | (rect->dy));
1081 	SET_LENXY_START_RECFILL(fb, (rect->width << 16) | (rect->height));
1082 
1083 	SETUP_FB(fb);
1084 }
1085 
1086 static void __init
1087 stifb_init_display(struct stifb_info *fb)
1088 {
1089 	int id = fb->id;
1090 
1091 	SETUP_FB(fb);
1092 
1093 	/* HCRX specific initialization */
1094 	SETUP_HCRX(fb);
1095 
1096 	/*
1097 	if (id == S9000_ID_HCRX)
1098 		hyperInitSprite(fb);
1099 	else
1100 		ngleInitSprite(fb);
1101 	*/
1102 
1103 	/* Initialize the image planes. */
1104         switch (id) {
1105 	 case S9000_ID_HCRX:
1106 	    hyperResetPlanes(fb, ENABLE);
1107 	    break;
1108 	 case S9000_ID_A1439A:
1109 	    rattlerSetupPlanes(fb);
1110 	    break;
1111 	 case S9000_ID_A1659A:
1112 	 case S9000_ID_ARTIST:
1113 	 case CRT_ID_VISUALIZE_EG:
1114 	    elkSetupPlanes(fb);
1115 	    break;
1116 	}
1117 
1118 	/* Clear attribute planes on non HCRX devices. */
1119         switch (id) {
1120 	 case S9000_ID_A1659A:
1121 	 case S9000_ID_A1439A:
1122 	    if (fb->info.var.bits_per_pixel == 32)
1123 		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1124 	    else {
1125 		ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1126 	    }
1127 	    if (id == S9000_ID_A1439A)
1128 		ngleClearOverlayPlanes(fb, 0xff, 0);
1129 	    break;
1130 	 case S9000_ID_ARTIST:
1131 	 case CRT_ID_VISUALIZE_EG:
1132 	    if (fb->info.var.bits_per_pixel == 32)
1133 		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1134 	    else {
1135 		ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1136 	    }
1137 	    break;
1138 	}
1139 	stifb_blank(0, (struct fb_info *)fb);	/* 0=enable screen */
1140 
1141 	SETUP_FB(fb);
1142 }
1143 
1144 /* ------------ Interfaces to hardware functions ------------ */
1145 
1146 static const struct fb_ops stifb_ops = {
1147 	.owner		= THIS_MODULE,
1148 	.fb_setcolreg	= stifb_setcolreg,
1149 	.fb_blank	= stifb_blank,
1150 	.fb_fillrect	= stifb_fillrect,
1151 	.fb_copyarea	= stifb_copyarea,
1152 	.fb_imageblit	= cfb_imageblit,
1153 };
1154 
1155 
1156 /*
1157  *  Initialization
1158  */
1159 
1160 static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1161 {
1162 	struct fb_fix_screeninfo *fix;
1163 	struct fb_var_screeninfo *var;
1164 	struct stifb_info *fb;
1165 	struct fb_info *info;
1166 	unsigned long sti_rom_address;
1167 	char *dev_name;
1168 	int bpp, xres, yres;
1169 
1170 	fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
1171 	if (!fb)
1172 		return -ENOMEM;
1173 
1174 	info = &fb->info;
1175 
1176 	/* set struct to a known state */
1177 	fix = &info->fix;
1178 	var = &info->var;
1179 
1180 	fb->sti = sti;
1181 	dev_name = sti->sti_data->inq_outptr.dev_name;
1182 	/* store upper 32bits of the graphics id */
1183 	fb->id = fb->sti->graphics_id[0];
1184 
1185 	/* only supported cards are allowed */
1186 	switch (fb->id) {
1187 	case CRT_ID_VISUALIZE_EG:
1188 		/* Visualize cards can run either in "double buffer" or
1189  		  "standard" mode. Depending on the mode, the card reports
1190 		  a different device name, e.g. "INTERNAL_EG_DX1024" in double
1191 		  buffer mode and "INTERNAL_EG_X1024" in standard mode.
1192 		  Since this driver only supports standard mode, we check
1193 		  if the device name contains the string "DX" and tell the
1194 		  user how to reconfigure the card. */
1195 		if (strstr(dev_name, "DX")) {
1196 		   printk(KERN_WARNING
1197 "WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
1198 "WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
1199 			dev_name);
1200 		   goto out_err0;
1201 		}
1202 		fallthrough;
1203 	case S9000_ID_ARTIST:
1204 	case S9000_ID_HCRX:
1205 	case S9000_ID_TIMBER:
1206 	case S9000_ID_A1659A:
1207 	case S9000_ID_A1439A:
1208 		break;
1209 	default:
1210 		printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1211 			dev_name, fb->id);
1212 		goto out_err0;
1213 	}
1214 
1215 	/* default to 8 bpp on most graphic chips */
1216 	bpp = 8;
1217 	xres = sti_onscreen_x(fb->sti);
1218 	yres = sti_onscreen_y(fb->sti);
1219 
1220 	ngleGetDeviceRomData(fb);
1221 
1222 	/* get (virtual) io region base addr */
1223 	fix->mmio_start = REGION_BASE(fb,2);
1224 	fix->mmio_len   = 0x400000;
1225 
1226        	/* Reject any device not in the NGLE family */
1227 	switch (fb->id) {
1228 	case S9000_ID_A1659A:	/* CRX/A1659A */
1229 		break;
1230 	case S9000_ID_ELM:	/* GRX, grayscale but else same as A1659A */
1231 		var->grayscale = 1;
1232 		fb->id = S9000_ID_A1659A;
1233 		break;
1234 	case S9000_ID_TIMBER:	/* HP9000/710 Any (may be a grayscale device) */
1235 		if (strstr(dev_name, "GRAYSCALE") ||
1236 		    strstr(dev_name, "Grayscale") ||
1237 		    strstr(dev_name, "grayscale"))
1238 			var->grayscale = 1;
1239 		break;
1240 	case S9000_ID_TOMCAT:	/* Dual CRX, behaves else like a CRX */
1241 		/* FIXME: TomCat supports two heads:
1242 		 * fb.iobase = REGION_BASE(fb_info,3);
1243 		 * fb.screen_base = ioremap(REGION_BASE(fb_info,2),xxx);
1244 		 * for now we only support the left one ! */
1245 		xres = fb->ngle_rom.x_size_visible;
1246 		yres = fb->ngle_rom.y_size_visible;
1247 		fb->id = S9000_ID_A1659A;
1248 		break;
1249 	case S9000_ID_A1439A:	/* CRX24/A1439A */
1250 		bpp = 32;
1251 		break;
1252 	case S9000_ID_HCRX:	/* Hyperdrive/HCRX */
1253 		memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1254 		if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1255 		    (fb->sti->regions_phys[2] & 0xfc000000))
1256 			sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1257 		else
1258 			sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1259 
1260 		fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1261 		if (IS_24_DEVICE(fb)) {
1262 			if (bpp_pref == 8 || bpp_pref == 32)
1263 				bpp = bpp_pref;
1264 			else
1265 				bpp = 32;
1266 		} else
1267 			bpp = 8;
1268 		READ_WORD(fb, REG_15);
1269 		SETUP_HW(fb);
1270 		break;
1271 	case CRT_ID_VISUALIZE_EG:
1272 	case S9000_ID_ARTIST:	/* Artist */
1273 		break;
1274 	default:
1275 #ifdef FALLBACK_TO_1BPP
1276 	       	printk(KERN_WARNING
1277 			"stifb: Unsupported graphics card (id=0x%08x) "
1278 				"- now trying 1bpp mode instead\n",
1279 			fb->id);
1280 		bpp = 1;	/* default to 1 bpp */
1281 		break;
1282 #else
1283 	       	printk(KERN_WARNING
1284 			"stifb: Unsupported graphics card (id=0x%08x) "
1285 				"- skipping.\n",
1286 			fb->id);
1287 		goto out_err0;
1288 #endif
1289 	}
1290 
1291 
1292 	/* get framebuffer physical and virtual base addr & len (64bit ready) */
1293 	fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1294 	fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1295 
1296 	fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1297 	if (!fix->line_length)
1298 		fix->line_length = 2048; /* default */
1299 
1300 	/* limit fbsize to max visible screen size */
1301 	if (fix->smem_len > yres*fix->line_length)
1302 		fix->smem_len = ALIGN(yres*fix->line_length, 4*1024*1024);
1303 
1304 	fix->accel = FB_ACCEL_NONE;
1305 
1306 	switch (bpp) {
1307 	    case 1:
1308 		fix->type = FB_TYPE_PLANES;	/* well, sort of */
1309 		fix->visual = FB_VISUAL_MONO10;
1310 		var->red.length = var->green.length = var->blue.length = 1;
1311 		break;
1312 	    case 8:
1313 		fix->type = FB_TYPE_PACKED_PIXELS;
1314 		fix->visual = FB_VISUAL_PSEUDOCOLOR;
1315 		var->red.length = var->green.length = var->blue.length = 8;
1316 		break;
1317 	    case 32:
1318 		fix->type = FB_TYPE_PACKED_PIXELS;
1319 		fix->visual = FB_VISUAL_DIRECTCOLOR;
1320 		var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1321 		var->blue.offset = 0;
1322 		var->green.offset = 8;
1323 		var->red.offset = 16;
1324 		var->transp.offset = 24;
1325 		break;
1326 	    default:
1327 		break;
1328 	}
1329 
1330 	var->xres = var->xres_virtual = xres;
1331 	var->yres = var->yres_virtual = yres;
1332 	var->bits_per_pixel = bpp;
1333 
1334 	strcpy(fix->id, "stifb");
1335 	info->fbops = &stifb_ops;
1336 	info->screen_base = ioremap(REGION_BASE(fb,1), fix->smem_len);
1337 	if (!info->screen_base) {
1338 		printk(KERN_ERR "stifb: failed to map memory\n");
1339 		goto out_err0;
1340 	}
1341 	info->screen_size = fix->smem_len;
1342 	info->flags = FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1343 	info->pseudo_palette = &fb->pseudo_palette;
1344 
1345 	/* This has to be done !!! */
1346 	if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
1347 		goto out_err1;
1348 	stifb_init_display(fb);
1349 
1350 	if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1351 		printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1352 				fix->smem_start, fix->smem_start+fix->smem_len);
1353 		goto out_err2;
1354 	}
1355 
1356 	if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1357 		printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1358 				fix->mmio_start, fix->mmio_start+fix->mmio_len);
1359 		goto out_err3;
1360 	}
1361 
1362 	/* save for primary gfx device detection & unregister_framebuffer() */
1363 	sti->info = info;
1364 	if (register_framebuffer(&fb->info) < 0)
1365 		goto out_err4;
1366 
1367 	fb_info(&fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1368 		fix->id,
1369 		var->xres,
1370 		var->yres,
1371 		var->bits_per_pixel,
1372 		dev_name,
1373 		fb->id,
1374 		fix->mmio_start);
1375 
1376 	return 0;
1377 
1378 
1379 out_err4:
1380 	release_mem_region(fix->mmio_start, fix->mmio_len);
1381 out_err3:
1382 	release_mem_region(fix->smem_start, fix->smem_len);
1383 out_err2:
1384 	fb_dealloc_cmap(&info->cmap);
1385 out_err1:
1386 	iounmap(info->screen_base);
1387 out_err0:
1388 	kfree(fb);
1389 	return -ENXIO;
1390 }
1391 
1392 static int stifb_disabled __initdata;
1393 
1394 int __init
1395 stifb_setup(char *options);
1396 
1397 static int __init stifb_init(void)
1398 {
1399 	struct sti_struct *sti;
1400 	struct sti_struct *def_sti;
1401 	int i;
1402 
1403 #ifndef MODULE
1404 	char *option = NULL;
1405 
1406 	if (fb_get_options("stifb", &option))
1407 		return -ENODEV;
1408 	stifb_setup(option);
1409 #endif
1410 	if (stifb_disabled) {
1411 		printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1412 		return -ENXIO;
1413 	}
1414 
1415 	def_sti = sti_get_rom(0);
1416 	if (def_sti) {
1417 		for (i = 1; i <= MAX_STI_ROMS; i++) {
1418 			sti = sti_get_rom(i);
1419 			if (!sti)
1420 				break;
1421 			if (sti == def_sti) {
1422 				stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1423 				break;
1424 			}
1425 		}
1426 	}
1427 
1428 	for (i = 1; i <= MAX_STI_ROMS; i++) {
1429 		sti = sti_get_rom(i);
1430 		if (!sti)
1431 			break;
1432 		if (sti == def_sti)
1433 			continue;
1434 		stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1435 	}
1436 	return 0;
1437 }
1438 
1439 /*
1440  *  Cleanup
1441  */
1442 
1443 static void __exit
1444 stifb_cleanup(void)
1445 {
1446 	struct sti_struct *sti;
1447 	int i;
1448 
1449 	for (i = 1; i <= MAX_STI_ROMS; i++) {
1450 		sti = sti_get_rom(i);
1451 		if (!sti)
1452 			break;
1453 		if (sti->info) {
1454 			struct fb_info *info = sti->info;
1455 			unregister_framebuffer(sti->info);
1456 			release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1457 		        release_mem_region(info->fix.smem_start, info->fix.smem_len);
1458 				if (info->screen_base)
1459 					iounmap(info->screen_base);
1460 		        fb_dealloc_cmap(&info->cmap);
1461 		        framebuffer_release(info);
1462 		}
1463 		sti->info = NULL;
1464 	}
1465 }
1466 
1467 int __init
1468 stifb_setup(char *options)
1469 {
1470 	int i;
1471 
1472 	if (!options || !*options)
1473 		return 1;
1474 
1475 	if (strncmp(options, "off", 3) == 0) {
1476 		stifb_disabled = 1;
1477 		options += 3;
1478 	}
1479 
1480 	if (strncmp(options, "bpp", 3) == 0) {
1481 		options += 3;
1482 		for (i = 0; i < MAX_STI_ROMS; i++) {
1483 			if (*options++ != ':')
1484 				break;
1485 			stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1486 		}
1487 	}
1488 	return 1;
1489 }
1490 
1491 __setup("stifb=", stifb_setup);
1492 
1493 module_init(stifb_init);
1494 module_exit(stifb_cleanup);
1495 
1496 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1497 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1498 MODULE_LICENSE("GPL v2");
1499