xref: /linux/drivers/video/fbdev/stifb.c (revision 8e07e0e3964ca4e23ce7b68e2096fe660a888942)
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 <video/sticore.h>
73 
74 /* REGION_BASE(fb_info, index) returns the physical address for region <index> */
75 #define REGION_BASE(fb_info, index) \
76 	F_EXTEND(fb_info->sti->regions_phys[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_io(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_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
926 {
927 	struct stifb_info *fb = container_of(info, struct stifb_info, info);
928 
929 	if (var->xres != fb->info.var.xres ||
930 	    var->yres != fb->info.var.yres ||
931 	    var->bits_per_pixel != fb->info.var.bits_per_pixel)
932 		return -EINVAL;
933 
934 	var->xres_virtual = var->xres;
935 	var->yres_virtual = var->yres;
936 	var->xoffset = 0;
937 	var->yoffset = 0;
938 	var->grayscale = fb->info.var.grayscale;
939 	var->red.length = fb->info.var.red.length;
940 	var->green.length = fb->info.var.green.length;
941 	var->blue.length = fb->info.var.blue.length;
942 
943 	return 0;
944 }
945 
946 static int
947 stifb_setcolreg(u_int regno, u_int red, u_int green,
948 	      u_int blue, u_int transp, struct fb_info *info)
949 {
950 	struct stifb_info *fb = container_of(info, struct stifb_info, info);
951 	u32 color;
952 
953 	if (regno >= NR_PALETTE)
954 		return 1;
955 
956 	red   >>= 8;
957 	green >>= 8;
958 	blue  >>= 8;
959 
960 	DEBUG_OFF();
961 
962 	START_IMAGE_COLORMAP_ACCESS(fb);
963 
964 	if (unlikely(fb->info.var.grayscale)) {
965 		/* gray = 0.30*R + 0.59*G + 0.11*B */
966 		color = ((red * 77) +
967 			 (green * 151) +
968 			 (blue * 28)) >> 8;
969 	} else {
970 		color = ((red << 16) |
971 			 (green << 8) |
972 			 (blue));
973 	}
974 
975 	if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
976 		struct fb_var_screeninfo *var = &fb->info.var;
977 		if (regno < 16)
978 			((u32 *)fb->info.pseudo_palette)[regno] =
979 				regno << var->red.offset |
980 				regno << var->green.offset |
981 				regno << var->blue.offset;
982 	}
983 
984 	WRITE_IMAGE_COLOR(fb, regno, color);
985 
986 	if (fb->id == S9000_ID_HCRX) {
987 		NgleLutBltCtl lutBltCtl;
988 
989 		lutBltCtl = setHyperLutBltCtl(fb,
990 				0,	/* Offset w/i LUT */
991 				256);	/* Load entire LUT */
992 		NGLE_BINC_SET_SRCADDR(fb,
993 				NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
994 				/* 0x100 is same as used in WRITE_IMAGE_COLOR() */
995 		START_COLORMAPLOAD(fb, lutBltCtl.all);
996 		SETUP_FB(fb);
997 	} else {
998 		/* cleanup colormap hardware */
999 		FINISH_IMAGE_COLORMAP_ACCESS(fb);
1000 	}
1001 
1002 	DEBUG_ON();
1003 
1004 	return 0;
1005 }
1006 
1007 static int
1008 stifb_blank(int blank_mode, struct fb_info *info)
1009 {
1010 	struct stifb_info *fb = container_of(info, struct stifb_info, info);
1011 	int enable = (blank_mode == 0) ? ENABLE : DISABLE;
1012 
1013 	switch (fb->id) {
1014 	case S9000_ID_A1439A:
1015 		CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
1016 		break;
1017 	case CRT_ID_VISUALIZE_EG:
1018 	case S9000_ID_ARTIST:
1019 		ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
1020 		break;
1021 	case S9000_ID_HCRX:
1022 		HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
1023 		break;
1024 	case S9000_ID_A1659A:
1025 	case S9000_ID_TIMBER:
1026 	case CRX24_OVERLAY_PLANES:
1027 	default:
1028 		ENABLE_DISABLE_DISPLAY(fb, enable);
1029 		break;
1030 	}
1031 
1032 	SETUP_FB(fb);
1033 	return 0;
1034 }
1035 
1036 static void
1037 stifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1038 {
1039 	struct stifb_info *fb = container_of(info, struct stifb_info, info);
1040 
1041 	SETUP_COPYAREA(fb);
1042 
1043 	SETUP_HW(fb);
1044 	if (fb->info.var.bits_per_pixel == 32) {
1045 		WRITE_WORD(0xBBA0A000, fb, REG_10);
1046 
1047 		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
1048 	} else {
1049 		WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
1050 
1051 		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
1052 	}
1053 
1054 	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
1055 		IBOvals(RopSrc, MaskAddrOffset(0),
1056 		BitmapExtent08, StaticReg(1),
1057 		DataDynamic, MaskOtc, BGx(0), FGx(0)));
1058 
1059 	WRITE_WORD(((area->sx << 16) | area->sy), fb, REG_24);
1060 	WRITE_WORD(((area->width << 16) | area->height), fb, REG_7);
1061 	WRITE_WORD(((area->dx << 16) | area->dy), fb, REG_25);
1062 
1063 	SETUP_FB(fb);
1064 }
1065 
1066 #define ARTIST_VRAM_SIZE			0x000804
1067 #define ARTIST_VRAM_SRC				0x000808
1068 #define ARTIST_VRAM_SIZE_TRIGGER_WINFILL	0x000a04
1069 #define ARTIST_VRAM_DEST_TRIGGER_BLOCKMOVE	0x000b00
1070 #define ARTIST_SRC_BM_ACCESS			0x018008
1071 #define ARTIST_FGCOLOR				0x018010
1072 #define ARTIST_BGCOLOR				0x018014
1073 #define ARTIST_BITMAP_OP			0x01801c
1074 
1075 static void
1076 stifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
1077 {
1078 	struct stifb_info *fb = container_of(info, struct stifb_info, info);
1079 
1080 	if (rect->rop != ROP_COPY ||
1081 	    (fb->id == S9000_ID_HCRX && fb->info.var.bits_per_pixel == 32))
1082 		return cfb_fillrect(info, rect);
1083 
1084 	SETUP_HW(fb);
1085 
1086 	if (fb->info.var.bits_per_pixel == 32) {
1087 		WRITE_WORD(0xBBA0A000, fb, REG_10);
1088 
1089 		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
1090 	} else {
1091 		WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
1092 
1093 		NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
1094 	}
1095 
1096 	WRITE_WORD(0x03000300, fb, ARTIST_BITMAP_OP);
1097 	WRITE_WORD(0x2ea01000, fb, ARTIST_SRC_BM_ACCESS);
1098 	NGLE_QUICK_SET_DST_BM_ACCESS(fb, 0x2ea01000);
1099 	NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, rect->color);
1100 	WRITE_WORD(0, fb, ARTIST_BGCOLOR);
1101 
1102 	NGLE_SET_DSTXY(fb, (rect->dx << 16) | (rect->dy));
1103 	SET_LENXY_START_RECFILL(fb, (rect->width << 16) | (rect->height));
1104 
1105 	SETUP_FB(fb);
1106 }
1107 
1108 static void __init
1109 stifb_init_display(struct stifb_info *fb)
1110 {
1111 	int id = fb->id;
1112 
1113 	SETUP_FB(fb);
1114 
1115 	/* HCRX specific initialization */
1116 	SETUP_HCRX(fb);
1117 
1118 	/*
1119 	if (id == S9000_ID_HCRX)
1120 		hyperInitSprite(fb);
1121 	else
1122 		ngleInitSprite(fb);
1123 	*/
1124 
1125 	/* Initialize the image planes. */
1126         switch (id) {
1127 	 case S9000_ID_HCRX:
1128 	    hyperResetPlanes(fb, ENABLE);
1129 	    break;
1130 	 case S9000_ID_A1439A:
1131 	    rattlerSetupPlanes(fb);
1132 	    break;
1133 	 case S9000_ID_A1659A:
1134 	 case S9000_ID_ARTIST:
1135 	 case CRT_ID_VISUALIZE_EG:
1136 	    elkSetupPlanes(fb);
1137 	    break;
1138 	}
1139 
1140 	/* Clear attribute planes on non HCRX devices. */
1141         switch (id) {
1142 	 case S9000_ID_A1659A:
1143 	 case S9000_ID_A1439A:
1144 	    if (fb->info.var.bits_per_pixel == 32)
1145 		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1146 	    else {
1147 		ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1148 	    }
1149 	    if (id == S9000_ID_A1439A)
1150 		ngleClearOverlayPlanes(fb, 0xff, 0);
1151 	    break;
1152 	 case S9000_ID_ARTIST:
1153 	 case CRT_ID_VISUALIZE_EG:
1154 	    if (fb->info.var.bits_per_pixel == 32)
1155 		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1156 	    else {
1157 		ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1158 	    }
1159 	    break;
1160 	}
1161 	stifb_blank(0, (struct fb_info *)fb);	/* 0=enable screen */
1162 
1163 	SETUP_FB(fb);
1164 }
1165 
1166 /* ------------ Interfaces to hardware functions ------------ */
1167 
1168 static const struct fb_ops stifb_ops = {
1169 	.owner		= THIS_MODULE,
1170 	__FB_DEFAULT_IOMEM_OPS_RDWR,
1171 	.fb_check_var	= stifb_check_var,
1172 	.fb_setcolreg	= stifb_setcolreg,
1173 	.fb_blank	= stifb_blank,
1174 	.fb_fillrect	= stifb_fillrect,
1175 	.fb_copyarea	= stifb_copyarea,
1176 	.fb_imageblit	= cfb_imageblit,
1177 	__FB_DEFAULT_IOMEM_OPS_MMAP,
1178 };
1179 
1180 
1181 /*
1182  *  Initialization
1183  */
1184 
1185 static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1186 {
1187 	struct fb_fix_screeninfo *fix;
1188 	struct fb_var_screeninfo *var;
1189 	struct stifb_info *fb;
1190 	struct fb_info *info;
1191 	unsigned long sti_rom_address;
1192 	char modestr[32];
1193 	char *dev_name;
1194 	int bpp, xres, yres;
1195 
1196 	fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
1197 	if (!fb)
1198 		return -ENOMEM;
1199 
1200 	info = &fb->info;
1201 
1202 	/* set struct to a known state */
1203 	fix = &info->fix;
1204 	var = &info->var;
1205 
1206 	fb->sti = sti;
1207 	dev_name = sti->sti_data->inq_outptr.dev_name;
1208 	/* store upper 32bits of the graphics id */
1209 	fb->id = fb->sti->graphics_id[0];
1210 
1211 	/* only supported cards are allowed */
1212 	switch (fb->id) {
1213 	case CRT_ID_VISUALIZE_EG:
1214 		/* Visualize cards can run either in "double buffer" or
1215  		  "standard" mode. Depending on the mode, the card reports
1216 		  a different device name, e.g. "INTERNAL_EG_DX1024" in double
1217 		  buffer mode and "INTERNAL_EG_X1024" in standard mode.
1218 		  Since this driver only supports standard mode, we check
1219 		  if the device name contains the string "DX" and tell the
1220 		  user how to reconfigure the card. */
1221 		if (strstr(dev_name, "DX")) {
1222 		   printk(KERN_WARNING
1223 "WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
1224 "WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
1225 			dev_name);
1226 		   goto out_err0;
1227 		}
1228 		fallthrough;
1229 	case S9000_ID_ARTIST:
1230 	case S9000_ID_HCRX:
1231 	case S9000_ID_TIMBER:
1232 	case S9000_ID_A1659A:
1233 	case S9000_ID_A1439A:
1234 		break;
1235 	default:
1236 		printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1237 			dev_name, fb->id);
1238 		goto out_err0;
1239 	}
1240 
1241 	/* default to 8 bpp on most graphic chips */
1242 	bpp = 8;
1243 	xres = sti_onscreen_x(fb->sti);
1244 	yres = sti_onscreen_y(fb->sti);
1245 
1246 	ngleGetDeviceRomData(fb);
1247 
1248 	/* get (virtual) io region base addr */
1249 	fix->mmio_start = REGION_BASE(fb,2);
1250 	fix->mmio_len   = 0x400000;
1251 
1252        	/* Reject any device not in the NGLE family */
1253 	switch (fb->id) {
1254 	case S9000_ID_A1659A:	/* CRX/A1659A */
1255 		break;
1256 	case S9000_ID_ELM:	/* GRX, grayscale but else same as A1659A */
1257 		var->grayscale = 1;
1258 		fb->id = S9000_ID_A1659A;
1259 		break;
1260 	case S9000_ID_TIMBER:	/* HP9000/710 Any (may be a grayscale device) */
1261 		if (strstr(dev_name, "GRAYSCALE") ||
1262 		    strstr(dev_name, "Grayscale") ||
1263 		    strstr(dev_name, "grayscale"))
1264 			var->grayscale = 1;
1265 		break;
1266 	case S9000_ID_TOMCAT:	/* Dual CRX, behaves else like a CRX */
1267 		/* FIXME: TomCat supports two heads:
1268 		 * fb.iobase = REGION_BASE(fb_info,3);
1269 		 * fb.screen_base = ioremap(REGION_BASE(fb_info,2),xxx);
1270 		 * for now we only support the left one ! */
1271 		xres = fb->ngle_rom.x_size_visible;
1272 		yres = fb->ngle_rom.y_size_visible;
1273 		fb->id = S9000_ID_A1659A;
1274 		break;
1275 	case S9000_ID_A1439A:	/* CRX24/A1439A */
1276 		bpp = 32;
1277 		break;
1278 	case S9000_ID_HCRX:	/* Hyperdrive/HCRX */
1279 		memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1280 		if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1281 		    (fb->sti->regions_phys[2] & 0xfc000000))
1282 			sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1283 		else
1284 			sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1285 
1286 		fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1287 		if (IS_24_DEVICE(fb)) {
1288 			if (bpp_pref == 8 || bpp_pref == 32)
1289 				bpp = bpp_pref;
1290 			else
1291 				bpp = 32;
1292 		} else
1293 			bpp = 8;
1294 		READ_WORD(fb, REG_15);
1295 		SETUP_HW(fb);
1296 		break;
1297 	case CRT_ID_VISUALIZE_EG:
1298 	case S9000_ID_ARTIST:	/* Artist */
1299 		break;
1300 	default:
1301 #ifdef FALLBACK_TO_1BPP
1302 		printk(KERN_WARNING
1303 			"stifb: Unsupported graphics card (id=0x%08x) "
1304 				"- now trying 1bpp mode instead\n",
1305 			fb->id);
1306 		bpp = 1;	/* default to 1 bpp */
1307 		break;
1308 #else
1309 		printk(KERN_WARNING
1310 			"stifb: Unsupported graphics card (id=0x%08x) "
1311 				"- skipping.\n",
1312 			fb->id);
1313 		goto out_err0;
1314 #endif
1315 	}
1316 
1317 
1318 	/* get framebuffer physical and virtual base addr & len (64bit ready) */
1319 	fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1320 	fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1321 
1322 	fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1323 	if (!fix->line_length)
1324 		fix->line_length = 2048; /* default */
1325 
1326 	/* limit fbsize to max visible screen size */
1327 	if (fix->smem_len > yres*fix->line_length)
1328 		fix->smem_len = ALIGN(yres*fix->line_length, 4*1024*1024);
1329 
1330 	fix->accel = FB_ACCEL_NONE;
1331 
1332 	switch (bpp) {
1333 	    case 1:
1334 		fix->type = FB_TYPE_PLANES;	/* well, sort of */
1335 		fix->visual = FB_VISUAL_MONO10;
1336 		var->red.length = var->green.length = var->blue.length = 1;
1337 		break;
1338 	    case 8:
1339 		fix->type = FB_TYPE_PACKED_PIXELS;
1340 		fix->visual = FB_VISUAL_PSEUDOCOLOR;
1341 		var->red.length = var->green.length = var->blue.length = 8;
1342 		break;
1343 	    case 32:
1344 		fix->type = FB_TYPE_PACKED_PIXELS;
1345 		fix->visual = FB_VISUAL_DIRECTCOLOR;
1346 		var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1347 		var->blue.offset = 0;
1348 		var->green.offset = 8;
1349 		var->red.offset = 16;
1350 		var->transp.offset = 24;
1351 		break;
1352 	    default:
1353 		break;
1354 	}
1355 
1356 	var->xres = var->xres_virtual = xres;
1357 	var->yres = var->yres_virtual = yres;
1358 	var->bits_per_pixel = bpp;
1359 
1360 	strcpy(fix->id, "stifb");
1361 	info->fbops = &stifb_ops;
1362 	info->screen_base = ioremap(REGION_BASE(fb,1), fix->smem_len);
1363 	if (!info->screen_base) {
1364 		printk(KERN_ERR "stifb: failed to map memory\n");
1365 		goto out_err0;
1366 	}
1367 	info->screen_size = fix->smem_len;
1368 	info->flags = FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1369 	info->pseudo_palette = &fb->pseudo_palette;
1370 
1371 	scnprintf(modestr, sizeof(modestr), "%dx%d-%d", xres, yres, bpp);
1372 	fb_find_mode(&info->var, info, modestr, NULL, 0, NULL, bpp);
1373 
1374 	/* This has to be done !!! */
1375 	if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
1376 		goto out_err1;
1377 	stifb_init_display(fb);
1378 
1379 	if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1380 		printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1381 				fix->smem_start, fix->smem_start+fix->smem_len);
1382 		goto out_err2;
1383 	}
1384 
1385 	if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1386 		printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1387 				fix->mmio_start, fix->mmio_start+fix->mmio_len);
1388 		goto out_err3;
1389 	}
1390 
1391 	/* save for primary gfx device detection & unregister_framebuffer() */
1392 	sti->info = info;
1393 	if (register_framebuffer(&fb->info) < 0)
1394 		goto out_err4;
1395 
1396 	fb_info(&fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1397 		fix->id,
1398 		var->xres,
1399 		var->yres,
1400 		var->bits_per_pixel,
1401 		dev_name,
1402 		fb->id,
1403 		fix->mmio_start);
1404 
1405 	return 0;
1406 
1407 
1408 out_err4:
1409 	release_mem_region(fix->mmio_start, fix->mmio_len);
1410 out_err3:
1411 	release_mem_region(fix->smem_start, fix->smem_len);
1412 out_err2:
1413 	fb_dealloc_cmap(&info->cmap);
1414 out_err1:
1415 	iounmap(info->screen_base);
1416 out_err0:
1417 	kfree(fb);
1418 	sti->info = NULL;
1419 	return -ENXIO;
1420 }
1421 
1422 static int stifb_disabled __initdata;
1423 
1424 int __init
1425 stifb_setup(char *options);
1426 
1427 static int __init stifb_init(void)
1428 {
1429 	struct sti_struct *sti;
1430 	struct sti_struct *def_sti;
1431 	int i;
1432 
1433 #ifndef MODULE
1434 	char *option = NULL;
1435 
1436 	if (fb_get_options("stifb", &option))
1437 		return -ENODEV;
1438 	stifb_setup(option);
1439 #endif
1440 	if (stifb_disabled) {
1441 		printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1442 		return -ENXIO;
1443 	}
1444 
1445 	def_sti = sti_get_rom(0);
1446 	if (def_sti) {
1447 		for (i = 1; i <= MAX_STI_ROMS; i++) {
1448 			sti = sti_get_rom(i);
1449 			if (!sti)
1450 				break;
1451 			if (sti == def_sti) {
1452 				stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1453 				break;
1454 			}
1455 		}
1456 	}
1457 
1458 	for (i = 1; i <= MAX_STI_ROMS; i++) {
1459 		sti = sti_get_rom(i);
1460 		if (!sti)
1461 			break;
1462 		if (sti == def_sti)
1463 			continue;
1464 		stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1465 	}
1466 	return 0;
1467 }
1468 
1469 /*
1470  *  Cleanup
1471  */
1472 
1473 static void __exit
1474 stifb_cleanup(void)
1475 {
1476 	struct sti_struct *sti;
1477 	int i;
1478 
1479 	for (i = 1; i <= MAX_STI_ROMS; i++) {
1480 		sti = sti_get_rom(i);
1481 		if (!sti)
1482 			break;
1483 		if (sti->info) {
1484 			struct fb_info *info = sti->info;
1485 			unregister_framebuffer(sti->info);
1486 			release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1487 		        release_mem_region(info->fix.smem_start, info->fix.smem_len);
1488 				if (info->screen_base)
1489 					iounmap(info->screen_base);
1490 		        fb_dealloc_cmap(&info->cmap);
1491 		        framebuffer_release(info);
1492 		}
1493 		sti->info = NULL;
1494 	}
1495 }
1496 
1497 int __init
1498 stifb_setup(char *options)
1499 {
1500 	int i;
1501 
1502 	if (!options || !*options)
1503 		return 1;
1504 
1505 	if (strncmp(options, "off", 3) == 0) {
1506 		stifb_disabled = 1;
1507 		options += 3;
1508 	}
1509 
1510 	if (strncmp(options, "bpp", 3) == 0) {
1511 		options += 3;
1512 		for (i = 0; i < MAX_STI_ROMS; i++) {
1513 			if (*options++ != ':')
1514 				break;
1515 			stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1516 		}
1517 	}
1518 	return 1;
1519 }
1520 
1521 __setup("stifb=", stifb_setup);
1522 
1523 module_init(stifb_init);
1524 module_exit(stifb_cleanup);
1525 
1526 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1527 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1528 MODULE_LICENSE("GPL v2");
1529