[go: nahoru, domu]

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