1 /*
2  * linux/drivers/video/sti/stifb.c -
3  * Frame buffer driver for HP workstations with STI (standard text interface)
4  * video firmware.
5  *
6  * Copyright (C) 2001 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  *	- Artist gfx is the only supported chip atm,
43  *	- remove the static fb_info to support multiple cards
44  *	- remove the completely untested 1bpp mode
45  *	- add support for h/w acceleration
46  *	- add hardware cursor
47  *	-
48  */
49 
50 
51 /* on supported graphic devices you may:
52  * #define FALLBACK_TO_1BPP to fall back to 1 bpp, or
53  * #undef  FALLBACK_TO_1BPP to reject support for unsupported cards */
54 #undef FALLBACK_TO_1BPP
55 
56 
57 #include <linux/config.h>
58 #include <linux/module.h>
59 #include <linux/kernel.h>
60 #include <linux/errno.h>
61 #include <linux/string.h>
62 #include <linux/mm.h>
63 #include <linux/tty.h>
64 #include <linux/slab.h>
65 #include <linux/delay.h>
66 #include <linux/fb.h>
67 #include <linux/init.h>
68 #include <linux/selection.h>
69 #include <linux/ioport.h>
70 #include <linux/pci.h>
71 
72 #include <video/fbcon.h>
73 #include <video/fbcon-cfb8.h>
74 #include <video/fbcon-cfb32.h>
75 
76 #include <asm/grfioctl.h>	/* for HP-UX compatibility */
77 
78 #include "sticore.h"
79 
80 extern struct display_switch fbcon_sti; /* fbcon-sti.c */
81 
82 #ifdef __LP64__
83 /* return virtual address */
84 #define REGION_BASE(fb_info, index) \
85 	(fb_info->sti->glob_cfg->region_ptrs[index] | 0xffffffff00000000)
86 #else
87 /* return virtual address */
88 #define REGION_BASE(fb_info, index) \
89 	fb_info->sti->glob_cfg->region_ptrs[index]
90 #endif
91 
92 #define NGLEDEVDEPROM_CRT_REGION 1
93 
94 typedef struct {
95 	__s32	video_config_reg;
96 	__s32	misc_video_start;
97 	__s32	horiz_timing_fmt;
98 	__s32	serr_timing_fmt;
99 	__s32	vert_timing_fmt;
100 	__s32	horiz_state;
101 	__s32	vert_state;
102 	__s32	vtg_state_elements;
103 	__s32	pipeline_delay;
104 	__s32	misc_video_end;
105 } video_setup_t;
106 
107 typedef struct {
108 	__s16	sizeof_ngle_data;
109 	__s16	x_size_visible;	    /* visible screen dim in pixels  */
110 	__s16	y_size_visible;
111 	__s16	pad2[15];
112 	__s16	cursor_pipeline_delay;
113 	__s16	video_interleaves;
114 	__s32	pad3[11];
115 } ngle_rom_t;
116 
117 struct stifb_info {
118 	struct fb_info info;
119         struct fb_var_screeninfo var;
120         struct fb_fix_screeninfo fix;
121 	struct display disp;
122 	struct sti_struct *sti;
123 	unsigned int id, real_id;
124 	int currcon;
125 	int cmap_reload:1;
126 	int deviceSpecificConfig;
127 	ngle_rom_t ngle_rom;
128 	struct { u8 red, green, blue; } palette[256];
129 #ifdef FBCON_HAS_CFB32
130 	union {
131 		u32 cfb32[16];
132 	} fbcon_cmap;
133 #endif
134 };
135 
136 static int stifb_force_bpp[MAX_STI_ROMS];
137 
138 /* ------------------- chipset specific functions -------------------------- */
139 
140 /* offsets to graphic-chip internal registers */
141 
142 #define REG_1		0x000118
143 #define REG_2		0x000480
144 #define REG_3		0x0004a0
145 #define REG_4		0x000600
146 #define REG_6		0x000800
147 #define REG_8		0x000820
148 #define REG_9		0x000a04
149 #define REG_10		0x018000
150 #define REG_11		0x018004
151 #define REG_12		0x01800c
152 #define REG_13		0x018018
153 #define REG_14  	0x01801c
154 #define REG_15		0x200000
155 #define REG_15b0	0x200000
156 #define REG_16b1	0x200005
157 #define REG_16b3	0x200007
158 #define REG_21		0x200218
159 #define REG_22		0x0005a0
160 #define REG_23		0x0005c0
161 #define REG_26		0x200118
162 #define REG_27		0x200308
163 #define REG_32		0x21003c
164 #define REG_33		0x210040
165 #define REG_34		0x200008
166 #define REG_35		0x018010
167 #define REG_38		0x210020
168 #define REG_39		0x210120
169 #define REG_40		0x210130
170 #define REG_42		0x210028
171 #define REG_43		0x21002c
172 #define REG_44		0x210030
173 #define REG_45		0x210034
174 
175 #define READ_BYTE(fb,reg)		__raw_readb((fb)->fix.mmio_start + (reg))
176 #define READ_WORD(fb,reg)		__raw_readl((fb)->fix.mmio_start + (reg))
177 #define WRITE_BYTE(value,fb,reg)	__raw_writeb((value),(fb)->fix.mmio_start + (reg))
178 #define WRITE_WORD(value,fb,reg)	__raw_writel((value),(fb)->fix.mmio_start + (reg))
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
SETUP_HW(struct stifb_info * fb)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
SETUP_FB(struct stifb_info * fb)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->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->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
START_IMAGE_COLORMAP_ACCESS(struct stifb_info * fb)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
WRITE_IMAGE_COLOR(struct stifb_info * fb,int index,int color)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
FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info * fb)254 FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
255 {
256 	WRITE_WORD(0x400, fb, REG_2);
257 	if (fb->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
SETUP_RAMDAC(struct stifb_info * fb)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
CRX24_SETUP_RAMDAC(struct stifb_info * fb)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
CRX24_SET_OVLY_MASK(struct stifb_info * fb)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
ENABLE_DISABLE_DISPLAY(struct stifb_info * fb,int enable)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
CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info * fb,int enable)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
ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info * fb,int enable)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 static void
HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info * fb,int enable)437 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
438 {
439 	u32 DregsHypMiscVideo = REG_33;
440 	unsigned int value;
441 	SETUP_HW(fb);
442 	value = READ_WORD(fb, DregsHypMiscVideo);
443 	if (enable)
444 		value |= 0x0A000000;
445 	else
446 		value &= ~0x0A000000;
447 	WRITE_WORD(value, fb, DregsHypMiscVideo);
448 }
449 
450 
451 /* BufferNumbers used by SETUP_ATTR_ACCESS() */
452 #define BUFF0_CMAP0	0x00001e02
453 #define BUFF1_CMAP0	0x02001e02
454 #define BUFF1_CMAP3	0x0c001e02
455 #define ARTIST_CMAP0	0x00000102
456 #define HYPER_CMAP8	0x00000100
457 #define HYPER_CMAP24	0x00000800
458 
459 static void
SETUP_ATTR_ACCESS(struct stifb_info * fb,unsigned BufferNumber)460 SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
461 {
462 	SETUP_HW(fb);
463 	WRITE_WORD(0x2EA0D000, fb, REG_11);
464 	WRITE_WORD(0x23000302, fb, REG_14);
465 	WRITE_WORD(BufferNumber, fb, REG_12);
466 	WRITE_WORD(0xffffffff, fb, REG_8);
467 }
468 
469 static void
SET_ATTR_SIZE(struct stifb_info * fb,int width,int height)470 SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
471 {
472 	WRITE_WORD(0x00000000, fb, REG_6);
473 	WRITE_WORD((width<<16) | height, fb, REG_9);
474 	WRITE_WORD(0x05000000, fb, REG_6);
475 	WRITE_WORD(0x00040001, fb, REG_9);
476 }
477 
478 static void
FINISH_ATTR_ACCESS(struct stifb_info * fb)479 FINISH_ATTR_ACCESS(struct stifb_info *fb)
480 {
481 	SETUP_HW(fb);
482 	WRITE_WORD(0x00000000, fb, REG_12);
483 }
484 
485 static void
elkSetupPlanes(struct stifb_info * fb)486 elkSetupPlanes(struct stifb_info *fb)
487 {
488 	SETUP_RAMDAC(fb);
489 	SETUP_FB(fb);
490 }
491 
492 static void
ngleSetupAttrPlanes(struct stifb_info * fb,int BufferNumber)493 ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
494 {
495 	SETUP_ATTR_ACCESS(fb, BufferNumber);
496 	SET_ATTR_SIZE(fb, fb->var.xres, fb->var.yres);
497 	FINISH_ATTR_ACCESS(fb);
498 	SETUP_FB(fb);
499 }
500 
501 
502 static void
rattlerSetupPlanes(struct stifb_info * fb)503 rattlerSetupPlanes(struct stifb_info *fb)
504 {
505 	CRX24_SETUP_RAMDAC(fb);
506 
507 	/* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */
508 	WRITE_WORD(0x83000300, fb, REG_14);
509 	SETUP_HW(fb);
510 	WRITE_BYTE(1, fb, REG_16b1);
511 
512 	/* XXX: replace by fb_setmem(), smem_start or screen_base ? */
513 	memset_io(fb->fix.smem_start, 0xff,
514 		fb->var.yres*fb->fix.line_length);
515 
516 	CRX24_SET_OVLY_MASK(fb);
517 	SETUP_FB(fb);
518 }
519 
520 
521 #define HYPER_CMAP_TYPE				0
522 #define NGLE_CMAP_INDEXED0_TYPE			0
523 #define NGLE_CMAP_OVERLAY_TYPE			3
524 
525 /* typedef of LUT (Colormap) BLT Control Register */
526 typedef union	/* Note assumption that fields are packed left-to-right */
527 {	u32 all;
528 	struct
529 	{
530 		unsigned enable              :  1;
531 		unsigned waitBlank           :  1;
532 		unsigned reserved1           :  4;
533 		unsigned lutOffset           : 10;   /* Within destination LUT */
534 		unsigned lutType             :  2;   /* Cursor, image, overlay */
535 		unsigned reserved2           :  4;
536 		unsigned length              : 10;
537 	} fields;
538 } NgleLutBltCtl;
539 
540 
541 #if 0
542 static NgleLutBltCtl
543 setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
544 {
545 	NgleLutBltCtl lutBltCtl;
546 
547 	/* set enable, zero reserved fields */
548 	lutBltCtl.all           = 0x80000000;
549 	lutBltCtl.fields.length = length;
550 
551 	switch (fb->id)
552 	{
553 	case S9000_ID_A1439A:		/* CRX24 */
554 		if (fb->var.bits_per_pixel == 8) {
555 			lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
556 			lutBltCtl.fields.lutOffset = 0;
557 		} else {
558 			lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
559 			lutBltCtl.fields.lutOffset = 0 * 256;
560 		}
561 		break;
562 
563 	case S9000_ID_ARTIST:
564 		lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
565 		lutBltCtl.fields.lutOffset = 0 * 256;
566 		break;
567 
568 	default:
569 		lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
570 		lutBltCtl.fields.lutOffset = 0;
571 		break;
572 	}
573 
574 	/* Offset points to start of LUT.  Adjust for within LUT */
575 	lutBltCtl.fields.lutOffset += offsetWithinLut;
576 
577 	return lutBltCtl;
578 }
579 #endif
580 
581 static NgleLutBltCtl
setHyperLutBltCtl(struct stifb_info * fb,int offsetWithinLut,int length)582 setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
583 {
584 	NgleLutBltCtl lutBltCtl;
585 
586 	/* set enable, zero reserved fields */
587 	lutBltCtl.all = 0x80000000;
588 
589 	lutBltCtl.fields.length = length;
590 	lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
591 
592 	/* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
593 	if (fb->var.bits_per_pixel == 8)
594 		lutBltCtl.fields.lutOffset = 2 * 256;
595 	else
596 		lutBltCtl.fields.lutOffset = 0 * 256;
597 
598 	/* Offset points to start of LUT.  Adjust for within LUT */
599 	lutBltCtl.fields.lutOffset += offsetWithinLut;
600 
601 	return lutBltCtl;
602 }
603 
604 
hyperUndoITE(struct stifb_info * fb)605 static void hyperUndoITE(struct stifb_info *fb)
606 {
607 	int nFreeFifoSlots = 0;
608 	u32 fbAddr;
609 
610 	NGLE_LOCK(fb);
611 
612 	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
613 	WRITE_WORD(0xffffffff, fb, REG_32);
614 
615 	/* Write overlay transparency mask so only entry 255 is transparent */
616 
617 	/* Hardware setup for full-depth write to "magic" location */
618 	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
619 	NGLE_QUICK_SET_DST_BM_ACCESS(fb,
620 		BA(IndexedDcd, Otc04, Ots08, AddrLong,
621 		BAJustPoint(0), BINovly, BAIndexBase(0)));
622 	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
623 		IBOvals(RopSrc, MaskAddrOffset(0),
624 		BitmapExtent08, StaticReg(0),
625 		DataDynamic, MaskOtc, BGx(0), FGx(0)));
626 
627 	/* Now prepare to write to the "magic" location */
628 	fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
629 	NGLE_BINC_SET_DSTADDR(fb, fbAddr);
630 	NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
631 	NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
632 
633 	/* Finally, write a zero to clear the mask */
634 	NGLE_BINC_WRITE32(fb, 0);
635 
636 	NGLE_UNLOCK(fb);
637 }
638 
639 static void
ngleDepth8_ClearImagePlanes(struct stifb_info * fb)640 ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
641 {
642 	/* FIXME! */
643 }
644 
645 static void
ngleDepth24_ClearImagePlanes(struct stifb_info * fb)646 ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
647 {
648 	/* FIXME! */
649 }
650 
651 static void
ngleResetAttrPlanes(struct stifb_info * fb,unsigned int ctlPlaneReg)652 ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
653 {
654 	int nFreeFifoSlots = 0;
655 	u32 packed_dst;
656 	u32 packed_len;
657 
658 	NGLE_LOCK(fb);
659 
660 	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
661 	NGLE_QUICK_SET_DST_BM_ACCESS(fb,
662 				     BA(IndexedDcd, Otc32, OtsIndirect,
663 					AddrLong, BAJustPoint(0),
664 					BINattr, BAIndexBase(0)));
665 	NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
666 	NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
667 
668 	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
669 				       IBOvals(RopSrc, MaskAddrOffset(0),
670 					       BitmapExtent08, StaticReg(1),
671 					       DataDynamic, MaskOtc,
672 					       BGx(0), FGx(0)));
673 	packed_dst = 0;
674 	packed_len = (fb->var.xres << 16) | fb->var.yres;
675 	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
676 	NGLE_SET_DSTXY(fb, packed_dst);
677 	SET_LENXY_START_RECFILL(fb, packed_len);
678 
679 	/*
680 	 * In order to work around an ELK hardware problem (Buffy doesn't
681 	 * always flush it's buffers when writing to the attribute
682 	 * planes), at least 4 pixels must be written to the attribute
683 	 * planes starting at (X == 1280) and (Y != to the last Y written
684 	 * by BIF):
685 	 */
686 
687 	if (fb->id == S9000_ID_A1659A) {   /* ELK_DEVICE_ID */
688 		/* It's safe to use scanline zero: */
689 		packed_dst = (1280 << 16);
690 		GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
691 		NGLE_SET_DSTXY(fb, packed_dst);
692 		packed_len = (4 << 16) | 1;
693 		SET_LENXY_START_RECFILL(fb, packed_len);
694 	}   /* ELK Hardware Kludge */
695 
696 	/**** Finally, set the Control Plane Register back to zero: ****/
697 	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
698 	NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
699 
700 	NGLE_UNLOCK(fb);
701 }
702 
703 static void
ngleClearOverlayPlanes(struct stifb_info * fb,int mask,int data)704 ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
705 {
706 	int nFreeFifoSlots = 0;
707 	u32 packed_dst;
708 	u32 packed_len;
709 
710 	NGLE_LOCK(fb);
711 
712 	/* Hardware setup */
713 	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
714 	NGLE_QUICK_SET_DST_BM_ACCESS(fb,
715 				     BA(IndexedDcd, Otc04, Ots08, AddrLong,
716 					BAJustPoint(0), BINovly, BAIndexBase(0)));
717 
718         NGLE_SET_TRANSFERDATA(fb, 0xffffffff);  /* Write foreground color */
719 
720         NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
721         NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
722 
723         packed_dst = 0;
724         packed_len = (fb->var.xres << 16) | fb->var.yres;
725         NGLE_SET_DSTXY(fb, packed_dst);
726 
727         /* Write zeroes to overlay planes */
728 	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
729 				       IBOvals(RopSrc, MaskAddrOffset(0),
730 					       BitmapExtent08, StaticReg(0),
731 					       DataDynamic, MaskOtc, BGx(0), FGx(0)));
732 
733         SET_LENXY_START_RECFILL(fb, packed_len);
734 
735 	NGLE_UNLOCK(fb);
736 }
737 
738 static void
hyperResetPlanes(struct stifb_info * fb,int enable)739 hyperResetPlanes(struct stifb_info *fb, int enable)
740 {
741 	unsigned int controlPlaneReg;
742 
743 	NGLE_LOCK(fb);
744 
745 	if (IS_24_DEVICE(fb))
746 		if (fb->var.bits_per_pixel == 32)
747 			controlPlaneReg = 0x04000F00;
748 		else
749 			controlPlaneReg = 0x00000F00;   /* 0x00000800 should be enought, but lets clear all 4 bits */
750 	else
751 		controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
752 
753 	switch (enable) {
754 	case 1:		/* ENABLE */
755 		/* clear screen */
756 		if (IS_24_DEVICE(fb))
757 			ngleDepth24_ClearImagePlanes(fb);
758 		else
759 			ngleDepth8_ClearImagePlanes(fb);
760 
761 		/* Paint attribute planes for default case.
762 		 * On Hyperdrive, this means all windows using overlay cmap 0. */
763 		ngleResetAttrPlanes(fb, controlPlaneReg);
764 
765 		/* clear overlay planes */
766 	        ngleClearOverlayPlanes(fb, 0xff, 255);
767 
768 		/**************************************************
769 		 ** Also need to counteract ITE settings
770 		 **************************************************/
771 		hyperUndoITE(fb);
772 		break;
773 
774 	case 0:		/* DISABLE */
775 		/* clear screen */
776 		if (IS_24_DEVICE(fb))
777 			ngleDepth24_ClearImagePlanes(fb);
778 		else
779 			ngleDepth8_ClearImagePlanes(fb);
780 		ngleResetAttrPlanes(fb, controlPlaneReg);
781 		ngleClearOverlayPlanes(fb, 0xff, 0);
782 		break;
783 
784 	case -1:	/* RESET */
785 		hyperUndoITE(fb);
786 		ngleResetAttrPlanes(fb, controlPlaneReg);
787 		break;
788     	}
789 
790 	NGLE_UNLOCK(fb);
791 }
792 
793 /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
794 
795 static void
ngleGetDeviceRomData(struct stifb_info * fb)796 ngleGetDeviceRomData(struct stifb_info *fb)
797 {
798 #if 0
799 XXX: FIXME: !!!
800 	int	*pBytePerLongDevDepData;/* data byte == LSB */
801 	int 	*pRomTable;
802 	NgleDevRomData	*pPackedDevRomData;
803 	int	sizePackedDevRomData = sizeof(*pPackedDevRomData);
804 	char	*pCard8;
805 	int	i;
806 	char	*mapOrigin = NULL;
807 
808 	int romTableIdx;
809 
810 	pPackedDevRomData = fb->ngle_rom;
811 
812 	SETUP_HW(fb);
813 	if (fb->id == S9000_ID_ARTIST) {
814 		pPackedDevRomData->cursor_pipeline_delay = 4;
815 		pPackedDevRomData->video_interleaves     = 4;
816 	} else {
817 		/* Get pointer to unpacked byte/long data in ROM */
818 		pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
819 
820 		/* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
821 		if (fb->id == S9000_ID_TOMCAT)
822 	{
823 	    /*  jump to the correct ROM table  */
824 	    GET_ROMTABLE_INDEX(romTableIdx);
825 	    while  (romTableIdx > 0)
826 	    {
827 		pCard8 = (Card8 *) pPackedDevRomData;
828 		pRomTable = pBytePerLongDevDepData;
829 		/* Pack every fourth byte from ROM into structure */
830 		for (i = 0; i < sizePackedDevRomData; i++)
831 		{
832 		    *pCard8++ = (Card8) (*pRomTable++);
833 		}
834 
835 		pBytePerLongDevDepData = (Card32 *)
836 			((Card8 *) pBytePerLongDevDepData +
837 			       pPackedDevRomData->sizeof_ngle_data);
838 
839 		romTableIdx--;
840 	    }
841 	}
842 
843 	pCard8 = (Card8 *) pPackedDevRomData;
844 
845 	/* Pack every fourth byte from ROM into structure */
846 	for (i = 0; i < sizePackedDevRomData; i++)
847 	{
848 	    *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
849 	}
850     }
851 
852     SETUP_FB(fb);
853 #endif
854 }
855 
856 
857 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES	4
858 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE	8
859 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE		10
860 #define HYPERBOWL_MODE2_8_24					15
861 
862 /* HCRX specific boot-time initialization */
863 static void __init
SETUP_HCRX(struct stifb_info * fb)864 SETUP_HCRX(struct stifb_info *fb)
865 {
866 	int	hyperbowl;
867         int	nFreeFifoSlots = 0;
868 
869 	if (fb->id != S9000_ID_HCRX)
870 		return;
871 
872 	/* Initialize Hyperbowl registers */
873 	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
874 
875 	if (IS_24_DEVICE(fb)) {
876 		hyperbowl = (fb->var.bits_per_pixel == 32) ?
877 			HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
878 			HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
879 
880 		/* First write to Hyperbowl must happen twice (bug) */
881 		WRITE_WORD(hyperbowl, fb, REG_40);
882 		WRITE_WORD(hyperbowl, fb, REG_40);
883 
884 		WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
885 
886 		WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
887 		WRITE_WORD(0x404c4048, fb, REG_43);
888 		WRITE_WORD(0x034c0348, fb, REG_44);
889 		WRITE_WORD(0x444c4448, fb, REG_45);
890 	} else {
891 		hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
892 
893 		/* First write to Hyperbowl must happen twice (bug) */
894 		WRITE_WORD(hyperbowl, fb, REG_40);
895 		WRITE_WORD(hyperbowl, fb, REG_40);
896 
897 		WRITE_WORD(0x00000000, fb, REG_42);
898 		WRITE_WORD(0x00000000, fb, REG_43);
899 		WRITE_WORD(0x00000000, fb, REG_44);
900 		WRITE_WORD(0x444c4048, fb, REG_45);
901 	}
902 }
903 
904 
905 /* ------------------- driver specific functions --------------------------- */
906 
907 static int
stifb_getcolreg(u_int regno,u_int * red,u_int * green,u_int * blue,u_int * transp,struct fb_info * info)908 stifb_getcolreg(u_int regno, u_int *red, u_int *green,
909 	      u_int *blue, u_int *transp, struct fb_info *info)
910 {
911 	struct stifb_info *fb = (struct stifb_info *) info;
912 
913 	if (regno > 255)
914 		return 1;
915 	*red = (fb->palette[regno].red<<8) | fb->palette[regno].red;
916 	*green = (fb->palette[regno].green<<8) | fb->palette[regno].green;
917 	*blue = (fb->palette[regno].blue<<8) | fb->palette[regno].blue;
918 	*transp = 0;
919 
920 	return 0;
921 }
922 
923 static int
stifb_setcolreg(u_int regno,u_int red,u_int green,u_int blue,u_int transp,struct fb_info * info)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 = (struct stifb_info *) info;
928 
929 	if (regno > 255)
930 		return 1;
931 
932 	red >>= 8;
933 	green >>= 8;
934 	blue >>= 8;
935 
936 	if ((fb->palette[regno].red != red) ||
937 	    (fb->palette[regno].green != green) ||
938 	    (fb->palette[regno].blue != blue))
939 		fb->cmap_reload = 1;
940 
941 	fb->palette[regno].red = red;
942 	fb->palette[regno].green = green;
943 	fb->palette[regno].blue = blue;
944 
945 #ifdef FBCON_HAS_CFB32
946 	if (regno < 16 && fb->var.bits_per_pixel == 32) {
947 		fb->fbcon_cmap.cfb32[regno] = ((red << 16) |
948 					       (green << 8) |
949 					       (blue << 0) |
950 					       (transp << 24));
951 	}
952 #endif
953 	return 0;
954 }
955 
956 static void
stifb_loadcmap(struct stifb_info * fb)957 stifb_loadcmap(struct stifb_info *fb)
958 {
959 	u32 color;
960 	int i;
961 
962 	if (!fb->cmap_reload)
963 		return;
964 
965 	START_IMAGE_COLORMAP_ACCESS(fb);
966 	for (i = 0; i < 256; i++) {
967 		if (fb->var.bits_per_pixel > 8) {
968 			color = (i << 16) | (i << 8) | i;
969 		} else {
970 			if (fb->var.grayscale) {
971 				/* gray = 0.30*R + 0.59*G + 0.11*B */
972 				color = ((fb->palette[i].red * 77) +
973 					 (fb->palette[i].green * 151) +
974 					 (fb->palette[i].blue * 28)) >> 8;
975 			} else {
976 				color = ((fb->palette[i].red << 16) |
977 					 (fb->palette[i].green << 8) |
978 					 (fb->palette[i].blue));
979 			}
980 		}
981 		WRITE_IMAGE_COLOR(fb, i, color);
982 	}
983 	if (fb->id == S9000_ID_HCRX) {
984 		NgleLutBltCtl lutBltCtl;
985 
986 		lutBltCtl = setHyperLutBltCtl(fb,
987 				0,	/* Offset w/i LUT */
988 				256);	/* Load entire LUT */
989 		NGLE_BINC_SET_SRCADDR(fb,
990 				NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
991 				/* 0x100 is same as used in WRITE_IMAGE_COLOR() */
992 		START_COLORMAPLOAD(fb, lutBltCtl.all);
993 		SETUP_FB(fb);
994 	} else {
995 		/* cleanup colormap hardware */
996 		FINISH_IMAGE_COLORMAP_ACCESS(fb);
997 	}
998 	fb->cmap_reload = 0;
999 }
1000 
1001 static int
stifb_get_fix(struct fb_fix_screeninfo * fix,int con,struct fb_info * info)1002 stifb_get_fix(struct fb_fix_screeninfo *fix, int con,
1003 	      struct fb_info *info)
1004 {
1005 	memcpy (fix, &((struct stifb_info *)info)->fix, sizeof (*fix));
1006 	return 0;
1007 }
1008 
1009 static int
stifb_get_var(struct fb_var_screeninfo * var,int con,struct fb_info * info)1010 stifb_get_var(struct fb_var_screeninfo *var, int con,
1011 	      struct fb_info *info)
1012 {
1013 	memcpy (var, &((struct stifb_info *)info)->var, sizeof (*var));
1014 	return 0;
1015 }
1016 
1017 static int
stifb_set_var(struct fb_var_screeninfo * var,int con,struct fb_info * info)1018 stifb_set_var(struct fb_var_screeninfo *var, int con,
1019 	      struct fb_info *info)
1020 {
1021 	struct display *disp;
1022 
1023 	if (con >= 0)
1024 		disp = &fb_display[con];
1025 	else
1026 		disp = info->disp;
1027 
1028 	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1029 		if (disp->var.xres != var->xres ||
1030 		    disp->var.yres != var->yres ||
1031 		    disp->var.xres_virtual != var->xres_virtual ||
1032 		    disp->var.yres_virtual != var->yres_virtual ||
1033 		    disp->var.bits_per_pixel != var->bits_per_pixel ||
1034 		    disp->var.accel_flags != var->accel_flags)
1035 			return -EINVAL;
1036 	}
1037 	return 0;
1038 }
1039 
1040 static int
stifb_get_cmap(struct fb_cmap * cmap,int kspc,int con,struct fb_info * info)1041 stifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
1042 	       struct fb_info *info)
1043 {
1044 	struct stifb_info *fb = (struct stifb_info *)info;
1045 
1046 	if (con == fb->currcon) /* current console ? */
1047 		return fb_get_cmap(cmap, kspc, stifb_getcolreg, info);
1048 	else if (fb_display[con].cmap.len) /* non default colormap ? */
1049 		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
1050 	else
1051 		fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel > 8 ? 16 : 256), cmap, kspc ? 0: 2);
1052 	return 0;
1053 }
1054 
1055 static int
stifb_set_cmap(struct fb_cmap * cmap,int kspc,int con,struct fb_info * info)1056 stifb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
1057 	       struct fb_info *info)
1058 {
1059 	struct stifb_info *fb = (struct stifb_info *)info;
1060 	struct display *disp;
1061 	int err;
1062 
1063 	if (con >= 0)
1064 		disp = &fb_display[con];
1065 	else
1066 		disp = info->disp;
1067 
1068 	if (!disp->cmap.len) { /* no colormap allocated ? */
1069 		if ((err = fb_alloc_cmap(&disp->cmap, disp->var.bits_per_pixel > 8 ? 16 : 256, 0)))
1070 			return err;
1071 	}
1072 	if (con == fb->currcon || con == -1) {
1073 		err = fb_set_cmap(cmap, kspc, stifb_setcolreg, info);
1074 		if (!err)
1075 			stifb_loadcmap ((struct stifb_info *)info);
1076 		return err;
1077 	} else
1078 		fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
1079 	return 0;
1080 }
1081 
1082 static void
stifb_blank(int blank_mode,struct fb_info * info)1083 stifb_blank(int blank_mode, struct fb_info *info)
1084 {
1085 	struct stifb_info *fb = (struct stifb_info *) info;
1086 	int enable = (blank_mode == 0) ? ENABLE : DISABLE;
1087 
1088 	switch (fb->id) {
1089 	case S9000_ID_A1439A:
1090 		CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
1091 		break;
1092 	case CRT_ID_VISUALIZE_EG:
1093 	case S9000_ID_ARTIST:
1094 		ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
1095 		break;
1096 	case S9000_ID_HCRX:
1097 		HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
1098 		break;
1099 	case S9000_ID_A1659A:;	/* fall through */
1100 	case S9000_ID_TIMBER:;
1101 	case CRX24_OVERLAY_PLANES:;
1102 	default:
1103 		ENABLE_DISABLE_DISPLAY(fb, enable);
1104 		break;
1105 	}
1106 
1107 	SETUP_FB(fb);
1108 }
1109 
1110 static void
stifb_set_disp(struct stifb_info * fb)1111 stifb_set_disp(struct stifb_info *fb)
1112 {
1113 	int id = fb->id;
1114 
1115 	SETUP_FB(fb);
1116 
1117 	/* HCRX specific initialization */
1118 	SETUP_HCRX(fb);
1119 
1120 	/*
1121 	if (id == S9000_ID_HCRX)
1122 		hyperInitSprite(fb);
1123 	else
1124 		ngleInitSprite(fb);
1125 	*/
1126 
1127 	/* Initialize the image planes. */
1128         switch (id) {
1129 	 case S9000_ID_HCRX:
1130 	    hyperResetPlanes(fb, ENABLE);
1131 	    break;
1132 	 case S9000_ID_A1439A:
1133 	    rattlerSetupPlanes(fb);
1134 	    break;
1135 	 case S9000_ID_A1659A:
1136 	 case S9000_ID_ARTIST:
1137 	 case CRT_ID_VISUALIZE_EG:
1138 	    elkSetupPlanes(fb);
1139 	    break;
1140 	}
1141 
1142 	/* Clear attribute planes on non HCRX devices. */
1143         switch (id) {
1144 	 case S9000_ID_A1659A:
1145 	 case S9000_ID_A1439A:
1146 	    if (fb->var.bits_per_pixel == 32)
1147 		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1148 	    else {
1149 		ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1150 	    }
1151 	    if (id == S9000_ID_A1439A)
1152 		ngleClearOverlayPlanes(fb, 0xff, 0);
1153 	    break;
1154 	 case S9000_ID_ARTIST:
1155 	 case CRT_ID_VISUALIZE_EG:
1156 	    if (fb->var.bits_per_pixel == 32)
1157 		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1158 	    else {
1159 		ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1160 	    }
1161 	    break;
1162 	}
1163 	stifb_blank(0, (struct fb_info *)fb);	/* 0=enable screen */
1164 
1165 	SETUP_FB(fb);
1166 }
1167 
1168 static int
stifb_switch(int con,struct fb_info * info)1169 stifb_switch(int con, struct fb_info *info)
1170 {
1171 	struct stifb_info *fb = (struct stifb_info *)info;
1172 
1173 	/* Do we have to save the colormap ? */
1174 	if (fb->currcon != -1 && fb_display[fb->currcon].cmap.len)
1175 		fb_get_cmap(&fb_display[fb->currcon].cmap, 1, stifb_getcolreg, info);
1176 
1177 	fb->currcon = con;
1178 	/* Install new colormap */
1179 	if (fb_display[con].cmap.len)
1180 		fb_set_cmap(&fb_display[con].cmap, 1, stifb_setcolreg, info);
1181 	else
1182 		fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel > 8 ? 16 : 256),
1183 			    1, stifb_setcolreg, info);
1184 	stifb_loadcmap ((struct stifb_info *)info);
1185 	return 0;
1186 }
1187 
1188 static int
stifb_update_var(int con,struct fb_info * info)1189 stifb_update_var(int con, struct fb_info *info)
1190 {
1191 	return 0;
1192 }
1193 
1194 /* ------------ Interfaces to hardware functions ------------ */
1195 
1196 static struct fb_ops stifb_ops = {
1197 	owner:		THIS_MODULE,
1198 	fb_get_fix:	stifb_get_fix,
1199 	fb_get_var:	stifb_get_var,
1200 	fb_set_var:	stifb_set_var,
1201 	fb_get_cmap:	stifb_get_cmap,
1202 	fb_set_cmap:	stifb_set_cmap,
1203 //	fb_pan_display:	fbgen_pan_display,
1204 //	fb_ioctl:       xxxfb_ioctl,   /* optional */
1205 };
1206 
1207 
1208     /*
1209      *  Initialization
1210      */
1211 
1212 int __init
stifb_init_fb(struct sti_struct * sti,int force_bpp)1213 stifb_init_fb(struct sti_struct *sti, int force_bpp)
1214 {
1215 	struct fb_fix_screeninfo *fix;
1216 	struct fb_var_screeninfo *var;
1217 	struct display *disp;
1218 	struct stifb_info *fb;
1219 	unsigned long sti_rom_address;
1220 	char *dev_name;
1221 	int bpp, xres, yres;
1222 
1223 	fb = kmalloc(sizeof(struct stifb_info), GFP_ATOMIC);
1224 	if (!fb) {
1225 		printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
1226 		return -ENODEV;
1227 	}
1228 
1229 	/* set struct to a known state */
1230 	memset(fb, 0, sizeof(struct stifb_info));
1231 	fix = &fb->fix;
1232 	var = &fb->var;
1233 	disp = &fb->disp;
1234 
1235 	fb->currcon = -1;
1236 	fb->cmap_reload = 1;
1237 	fb->sti = sti;
1238 	/* store upper 32bits of the graphics id */
1239 	fb->id = fb->sti->graphics_id[0];
1240 	fb->real_id = fb->id;	/* save the real id */
1241 
1242 	/* only supported cards are allowed */
1243 	switch (fb->id) {
1244 	case S9000_ID_ARTIST:
1245 	case S9000_ID_HCRX:
1246 	case S9000_ID_TIMBER:
1247 	case S9000_ID_A1659A:
1248 	case S9000_ID_A1439A:
1249 	case CRT_ID_VISUALIZE_EG:
1250 		break;
1251 	default:
1252 		printk(KERN_WARNING "stifb: Unsupported gfx card id 0x%08x\n",
1253 			fb->id);
1254 		goto out_err1;
1255 	}
1256 
1257 	/* default to 8 bpp on most graphic chips */
1258 	bpp = 8;
1259 	xres = sti_onscreen_x(fb->sti);
1260 	yres = sti_onscreen_y(fb->sti);
1261 
1262 	ngleGetDeviceRomData(fb);
1263 
1264 	/* get (virtual) io region base addr */
1265 	fix->mmio_start = REGION_BASE(fb,2);
1266 	fix->mmio_len   = 0x400000;
1267 
1268        	/* Reject any device not in the NGLE family */
1269 	switch (fb->id) {
1270 	case S9000_ID_A1659A:	/* CRX/A1659A */
1271 		break;
1272 	case S9000_ID_ELM:	/* GRX, grayscale but else same as A1659A */
1273 		var->grayscale = 1;
1274 		fb->id = S9000_ID_A1659A;
1275 		break;
1276 	case S9000_ID_TIMBER:	/* HP9000/710 Any (may be a grayscale device) */
1277 		dev_name = fb->sti->outptr.dev_name;
1278 		if (strstr(dev_name, "GRAYSCALE") ||
1279 		    strstr(dev_name, "Grayscale") ||
1280 		    strstr(dev_name, "grayscale"))
1281 			var->grayscale = 1;
1282 		break;
1283 	case S9000_ID_TOMCAT:	/* Dual CRX, behaves else like a CRX */
1284 		/* FIXME: TomCat supports two heads:
1285 		 * fb.iobase = REGION_BASE(fb_info,3);
1286 		 * fb.screen_base = (void*) REGION_BASE(fb_info,2);
1287 		 * for now we only support the left one ! */
1288 		xres = fb->ngle_rom.x_size_visible;
1289 		yres = fb->ngle_rom.y_size_visible;
1290 		fb->id = S9000_ID_A1659A;
1291 		break;
1292 	case S9000_ID_A1439A:	/* CRX24/A1439A */
1293 		if (force_bpp == 8 || force_bpp == 32)
1294 		  bpp = force_bpp;
1295 		else
1296 		  bpp = 32;
1297 		break;
1298 	case S9000_ID_HCRX:	/* Hyperdrive/HCRX */
1299 		memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1300 		if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1301 		    (fb->sti->regions_phys[2] & 0xfc000000))
1302 			sti_rom_address = fb->sti->regions_phys[0];
1303 		else
1304 			sti_rom_address = fb->sti->regions_phys[1];
1305 #ifdef __LP64__
1306 	        sti_rom_address |= 0xffffffff00000000;
1307 #endif
1308 		fb->deviceSpecificConfig = __raw_readl(sti_rom_address);
1309 		if (IS_24_DEVICE(fb)) {
1310 			if (force_bpp == 8 || force_bpp == 32)
1311 				bpp = force_bpp;
1312 			else
1313 				bpp = 32;
1314 		} else
1315 			bpp = 8;
1316 		READ_WORD(fb, REG_15);
1317 		SETUP_HW(fb);
1318 		break;
1319 	case CRT_ID_VISUALIZE_EG:
1320 	case S9000_ID_ARTIST:	/* Artist */
1321 		break;
1322 	default:
1323 #ifdef FALLBACK_TO_1BPP
1324 	       	printk(KERN_WARNING
1325 			"stifb: Unsupported graphics card (id=0x%08x) "
1326 				"- now trying 1bpp mode instead\n",
1327 			fb->id);
1328 		bpp = 1;	/* default to 1 bpp */
1329 		break;
1330 #else
1331 	       	printk(KERN_WARNING
1332 			"stifb: Unsupported graphics card (id=0x%08x) "
1333 				"- skipping.\n",
1334 			fb->id);
1335 		goto out_err1;
1336 #endif
1337 	}
1338 
1339 
1340 	/* get framebuffer pysical and virtual base addr & len (64bit ready) */
1341 	fix->smem_start = fb->sti->regions_phys[1] | 0xffffffff00000000;
1342 	fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1343 
1344 	fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1345 	if (!fix->line_length)
1346 		fix->line_length = 2048; /* default */
1347 	fix->accel = FB_ACCEL_NONE;
1348 
1349 	switch (bpp) {
1350 	    case 1:
1351 		fix->type = FB_TYPE_PLANES;	/* well, sort of */
1352 		fix->visual = FB_VISUAL_MONO10;
1353 		disp->dispsw = &fbcon_sti;
1354 		break;
1355 #ifdef FBCON_HAS_CFB8
1356 	    case 8:
1357 		fix->type = FB_TYPE_PACKED_PIXELS;
1358 		fix->visual = FB_VISUAL_PSEUDOCOLOR;
1359 	 	disp->dispsw = &fbcon_cfb8;
1360 		var->red.length = var->green.length = var->blue.length = 8;
1361 		break;
1362 #endif
1363 #ifdef FBCON_HAS_CFB32
1364 	    case 32:
1365 		fix->type = FB_TYPE_PACKED_PIXELS;
1366 		fix->visual = FB_VISUAL_TRUECOLOR;
1367 		disp->dispsw = &fbcon_cfb32;
1368 		disp->dispsw_data = fb->fbcon_cmap.cfb32;
1369 		var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1370 		var->blue.offset = 0;
1371 		var->green.offset = 8;
1372 		var->red.offset = 16;
1373 		var->transp.offset = 24;
1374 		break;
1375 #endif
1376 	    default:
1377 		disp->dispsw = &fbcon_dummy;
1378 		break;
1379 	}
1380 
1381 	var->xres = var->xres_virtual = xres;
1382 	var->yres = var->yres_virtual = yres;
1383 	var->bits_per_pixel = bpp;
1384 
1385 	disp->var = *var;
1386 	disp->visual = fix->visual;
1387 	disp->type = fix->type;
1388 	disp->type_aux = fix->type_aux;
1389 	disp->line_length = fix->line_length;
1390 	disp->var.activate = FB_ACTIVATE_NOW;
1391 	disp->screen_base = (void*) REGION_BASE(fb,1);
1392 	disp->can_soft_blank = 1;
1393 	disp->scrollmode = SCROLL_YREDRAW;
1394 
1395 	strcpy(fb->info.modename, "stifb");
1396 	fb->info.node = -1;
1397 	fb->info.flags = FBINFO_FLAG_DEFAULT;
1398 	fb->info.fbops = &stifb_ops;
1399 	fb->info.disp = disp;
1400 	fb->info.changevar = NULL;
1401 	fb->info.switch_con = &stifb_switch;
1402 	fb->info.updatevar = &stifb_update_var;
1403 	fb->info.blank = &stifb_blank;
1404 	fb->info.flags = FBINFO_FLAG_DEFAULT;
1405 
1406 	stifb_set_var(&disp->var, 1, &fb->info);
1407 
1408 	stifb_set_disp(fb);
1409 
1410 	if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb")) {
1411 		printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1412 				fix->smem_start, fix->smem_start+fix->smem_len);
1413 		goto out_err1;
1414 	}
1415 
1416 	if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1417 		printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1418 				fix->mmio_start, fix->mmio_start+fix->mmio_len);
1419 		goto out_err2;
1420 	}
1421 
1422 	if (register_framebuffer(&fb->info) < 0)
1423 		goto out_err3;
1424 
1425 	printk(KERN_INFO
1426 	    "fb%d: %s %dx%d-%d frame buffer device, id: %04x, mmio: 0x%04lx\n",
1427 		GET_FB_IDX(fb->info.node),
1428 		fb->info.modename,
1429 		disp->var.xres,
1430 		disp->var.yres,
1431 		disp->var.bits_per_pixel,
1432 		fb->id,
1433 		fix->mmio_start);
1434 
1435 	return 0;
1436 
1437 
1438 out_err3:
1439 	release_mem_region(fix->mmio_start, fix->mmio_len);
1440 out_err2:
1441 	release_mem_region(fix->smem_start, fix->smem_len);
1442 out_err1:
1443 	kfree(fb);
1444 	return -ENXIO;
1445 }
1446 
1447 int __init
stifb_init(void)1448 stifb_init(void)
1449 {
1450 	struct sti_struct *sti;
1451 	int i;
1452 
1453 
1454 	if (sti_init_roms() == NULL)
1455 		return -ENXIO; /* no STI cards available */
1456 
1457 	for (i = 0; i < MAX_STI_ROMS; i++) {
1458 		sti = sti_get_rom(i);
1459 		if (sti)
1460 			stifb_init_fb (sti, stifb_force_bpp[i]);
1461 		else
1462 			break;
1463 	}
1464 	return 0;
1465 }
1466 
1467 /*
1468  *  Cleanup
1469  */
1470 
1471 void __exit
stifb_cleanup(struct fb_info * info)1472 stifb_cleanup(struct fb_info *info)
1473 {
1474 	// unregister_framebuffer(info);
1475 }
1476 
1477 int __init
stifb_setup(char * options)1478 stifb_setup(char *options)
1479 {
1480 	int i;
1481 
1482 	if (!options || !*options)
1483 		return 0;
1484 
1485 	if (strncmp(options, "bpp", 3) == 0) {
1486 		options += 3;
1487 		for (i = 0; i < MAX_STI_ROMS; i++) {
1488 			if (*options++ == ':')
1489 				stifb_force_bpp[i] = simple_strtoul(options, &options, 10);
1490 			else
1491 				break;
1492 		}
1493 	}
1494 	return 0;
1495 }
1496 
1497 __setup("stifb=", stifb_setup);
1498 
1499 #ifdef MODULE
1500 module_init(stifb_init);
1501 #endif
1502 module_exit(stifb_cleanup);
1503 
1504 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1505 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1506 MODULE_LICENSE("GPL");
1507 
1508 MODULE_PARM(bpp, "i");
1509 MODULE_PARM_DESC(mem, "Bits per pixel (default: 8)");
1510 
1511