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
80extern 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
94typedef 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
107typedef 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
117struct 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
136static int stifb_force_bpp[MAX_STI_ROMS] = {0, };
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
186static void
187SETUP_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
199static void
200SETUP_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
236static void
237START_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
245static void
246WRITE_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
253static void
254FINISH_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
268static void
269SETUP_RAMDAC(struct stifb_info *fb)
270{
271	SETUP_HW(fb);
272	WRITE_WORD(0x04000000, fb, 0x1020);
273	WRITE_WORD(0xff000000, fb, 0x1028);
274}
275
276static void
277CRX24_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
289static void
290CRX24_SET_OVLY_MASK(struct stifb_info *fb)
291{
292	SETUP_HW(fb);
293	WRITE_WORD(0x13a02000, fb, REG_11);
294	WRITE_WORD(0x03000300, fb, REG_14);
295	WRITE_WORD(0x000017f0, fb, REG_3);
296	WRITE_WORD(0xffffffff, fb, REG_13);
297	WRITE_WORD(0xffffffff, fb, REG_22);
298	WRITE_WORD(0x00000000, fb, REG_23);
299}
300
301static void
302ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
303{
304	unsigned int value = enable ? 0x43000000 : 0x03000000;
305        SETUP_HW(fb);
306        WRITE_WORD(0x06000000,	fb, 0x1030);
307        WRITE_WORD(value, 	fb, 0x1038);
308}
309
310static void
311CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
312{
313	unsigned int value = enable ? 0x10000000 : 0x30000000;
314	SETUP_HW(fb);
315	WRITE_WORD(0x01000000,	fb, 0x1000);
316	WRITE_WORD(0x02000000,	fb, 0x1004);
317	WRITE_WORD(value,	fb, 0x1008);
318}
319
320static void
321ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
322{
323	u32 DregsMiscVideo = REG_21;
324	u32 DregsMiscCtl = REG_27;
325
326	SETUP_HW(fb);
327	if (enable) {
328	  WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
329	  WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   | 0x00800000, fb, DregsMiscCtl);
330	} else {
331	  WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
332	  WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   & ~0x00800000, fb, DregsMiscCtl);
333	}
334}
335
336#define GET_ROMTABLE_INDEX(fb) \
337	(READ_BYTE(fb, REG_16b3) - 1)
338
339#define HYPER_CONFIG_PLANES_24 0x00000100
340
341#define IS_24_DEVICE(fb) \
342	(fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
343
344#define IS_888_DEVICE(fb) \
345	(!(IS_24_DEVICE(fb)))
346
347#define GET_FIFO_SLOTS(fb, cnt, numslots)			\
348{	while (cnt < numslots) 					\
349		cnt = READ_WORD(fb, REG_34);	\
350	cnt -= numslots;					\
351}
352
353#define	    IndexedDcd	0	/* Pixel data is indexed (pseudo) color */
354#define	    Otc04	2	/* Pixels in each longword transfer (4) */
355#define	    Otc32	5	/* Pixels in each longword transfer (32) */
356#define	    Ots08	3	/* Each pixel is size (8)d transfer (1) */
357#define	    OtsIndirect	6	/* Each bit goes through FG/BG color(8) */
358#define	    AddrLong	5	/* FB address is Long aligned (pixel) */
359#define	    BINovly	0x2	/* 8 bit overlay */
360#define	    BINapp0I	0x0	/* Application Buffer 0, Indexed */
361#define	    BINapp1I	0x1	/* Application Buffer 1, Indexed */
362#define	    BINapp0F8	0xa	/* Application Buffer 0, Fractional 8-8-8 */
363#define	    BINattr	0xd	/* Attribute Bitmap */
364#define	    RopSrc 	0x3
365#define	    BitmapExtent08  3	/* Each write hits ( 8) bits in depth */
366#define	    BitmapExtent32  5	/* Each write hits (32) bits in depth */
367#define	    DataDynamic	    0	/* Data register reloaded by direct access */
368#define	    MaskDynamic	    1	/* Mask register reloaded by direct access */
369#define	    MaskOtc	    0	/* Mask contains Object Count valid bits */
370
371#define MaskAddrOffset(offset) (offset)
372#define StaticReg(en) (en)
373#define BGx(en) (en)
374#define FGx(en) (en)
375
376#define BAJustPoint(offset) (offset)
377#define BAIndexBase(base) (base)
378#define BA(F,C,S,A,J,B,I) \
379	(((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
380
381#define IBOvals(R,M,X,S,D,L,B,F) \
382	(((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
383
384#define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
385	WRITE_WORD(val, fb, REG_14)
386
387#define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
388	WRITE_WORD(val, fb, REG_11)
389
390#define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
391	WRITE_WORD(val, fb, REG_12)
392
393#define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
394	WRITE_WORD(plnmsk32, fb, REG_13)
395
396#define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
397	WRITE_WORD(fg32, fb, REG_35)
398
399#define NGLE_SET_TRANSFERDATA(fb, val) \
400	WRITE_WORD(val, fb, REG_8)
401
402#define NGLE_SET_DSTXY(fb, val) \
403	WRITE_WORD(val, fb, REG_6)
404
405#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) (		\
406	(u32) (fbaddrbase) +				\
407	    (	(unsigned int)  ( (y) << 13      ) |		\
408		(unsigned int)  ( (x) << 2       )	)	\
409	)
410
411#define NGLE_BINC_SET_DSTADDR(fb, addr) \
412	WRITE_WORD(addr, fb, REG_3)
413
414#define NGLE_BINC_SET_SRCADDR(fb, addr) \
415	WRITE_WORD(addr, fb, REG_2)
416
417#define NGLE_BINC_SET_DSTMASK(fb, mask) \
418	WRITE_WORD(mask, fb, REG_22)
419
420#define NGLE_BINC_WRITE32(fb, data32) \
421	WRITE_WORD(data32, fb, REG_23)
422
423#define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
424	WRITE_WORD((cmapBltCtlData32), fb, REG_38)
425
426#define SET_LENXY_START_RECFILL(fb, lenxy) \
427	WRITE_WORD(lenxy, fb, REG_9)
428
429static void
430HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
431{
432	u32 DregsHypMiscVideo = REG_33;
433	unsigned int value;
434	SETUP_HW(fb);
435	value = READ_WORD(fb, DregsHypMiscVideo);
436	if (enable)
437		value |= 0x0A000000;
438	else
439		value &= ~0x0A000000;
440	WRITE_WORD(value, fb, DregsHypMiscVideo);
441}
442
443
444/* BufferNumbers used by SETUP_ATTR_ACCESS() */
445#define BUFF0_CMAP0	0x00001e02
446#define BUFF1_CMAP0	0x02001e02
447#define BUFF1_CMAP3	0x0c001e02
448#define ARTIST_CMAP0	0x00000102
449#define HYPER_CMAP8	0x00000100
450#define HYPER_CMAP24	0x00000800
451
452static void
453SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
454{
455	SETUP_HW(fb);
456	WRITE_WORD(0x2EA0D000, fb, REG_11);
457	WRITE_WORD(0x23000302, fb, REG_14);
458	WRITE_WORD(BufferNumber, fb, REG_12);
459	WRITE_WORD(0xffffffff, fb, REG_8);
460}
461
462static void
463SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
464{
465	WRITE_WORD(0x00000000, fb, REG_6);
466	WRITE_WORD((width<<16) | height, fb, REG_9);
467	WRITE_WORD(0x05000000, fb, REG_6);
468	WRITE_WORD(0x00040001, fb, REG_9);
469}
470
471static void
472FINISH_ATTR_ACCESS(struct stifb_info *fb)
473{
474	SETUP_HW(fb);
475	WRITE_WORD(0x00000000, fb, REG_12);
476}
477
478static void
479elkSetupPlanes(struct stifb_info *fb)
480{
481	SETUP_RAMDAC(fb);
482	SETUP_FB(fb);
483}
484
485static void
486ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
487{
488	SETUP_ATTR_ACCESS(fb, BufferNumber);
489	SET_ATTR_SIZE(fb, fb->var.xres, fb->var.yres);
490	FINISH_ATTR_ACCESS(fb);
491	SETUP_FB(fb);
492}
493
494
495static void
496rattlerSetupPlanes(struct stifb_info *fb)
497{
498	CRX24_SETUP_RAMDAC(fb);
499
500	/* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */
501	WRITE_WORD(0x83000300, fb, REG_14);
502	SETUP_HW(fb);
503	WRITE_BYTE(1, fb, REG_16b1);
504
505	memset_io(fb->fix.smem_start, 0xff,
506		fb->var.yres*fb->fix.line_length);
507
508	CRX24_SET_OVLY_MASK(fb);
509	SETUP_FB(fb);
510}
511
512
513#define HYPER_CMAP_TYPE				0
514#define NGLE_CMAP_INDEXED0_TYPE			0
515#define NGLE_CMAP_OVERLAY_TYPE			3
516
517/* typedef of LUT (Colormap) BLT Control Register */
518typedef union	/* Note assumption that fields are packed left-to-right */
519{	u32 all;
520	struct
521	{
522		unsigned enable              :  1;
523		unsigned waitBlank           :  1;
524		unsigned reserved1           :  4;
525		unsigned lutOffset           : 10;   /* Within destination LUT */
526		unsigned lutType             :  2;   /* Cursor, image, overlay */
527		unsigned reserved2           :  4;
528		unsigned length              : 10;
529	} fields;
530} NgleLutBltCtl;
531
532
533
534static NgleLutBltCtl
535setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
536{
537	NgleLutBltCtl lutBltCtl;
538
539	/* set enable, zero reserved fields */
540	lutBltCtl.all = 0x80000000;
541
542	lutBltCtl.fields.length = length;
543	lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
544
545	/* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
546	if (fb->var.bits_per_pixel == 8)
547		lutBltCtl.fields.lutOffset = 2 * 256;
548	else
549		lutBltCtl.fields.lutOffset = 0 * 256;
550
551	/* Offset points to start of LUT.  Adjust for within LUT */
552	lutBltCtl.fields.lutOffset += offsetWithinLut;
553
554	return lutBltCtl;
555}
556
557
558static void hyperUndoITE(struct stifb_info *fb)
559{
560	int nFreeFifoSlots = 0;
561	u32 fbAddr;
562
563	NGLE_LOCK(fb);
564
565	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
566	WRITE_WORD(0xffffffff, fb, REG_32);
567
568	/* Write overlay transparency mask so only entry 255 is transparent */
569
570	/* Hardware setup for full-depth write to "magic" location */
571	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
572	NGLE_QUICK_SET_DST_BM_ACCESS(fb,
573		BA(IndexedDcd, Otc04, Ots08, AddrLong,
574		BAJustPoint(0), BINovly, BAIndexBase(0)));
575	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
576		IBOvals(RopSrc, MaskAddrOffset(0),
577		BitmapExtent08, StaticReg(0),
578		DataDynamic, MaskOtc, BGx(0), FGx(0)));
579
580	/* Now prepare to write to the "magic" location */
581	fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
582	NGLE_BINC_SET_DSTADDR(fb, fbAddr);
583	NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
584	NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
585
586	/* Finally, write a zero to clear the mask */
587	NGLE_BINC_WRITE32(fb, 0);
588
589	NGLE_UNLOCK(fb);
590}
591
592static void
593ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
594{
595}
596
597static void
598ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
599{
600}
601
602static void
603ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
604{
605	int nFreeFifoSlots = 0;
606	u32 packed_dst;
607	u32 packed_len;
608
609	NGLE_LOCK(fb);
610
611	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
612	NGLE_QUICK_SET_DST_BM_ACCESS(fb,
613				     BA(IndexedDcd, Otc32, OtsIndirect,
614					AddrLong, BAJustPoint(0),
615					BINattr, BAIndexBase(0)));
616	NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
617	NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
618
619	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
620				       IBOvals(RopSrc, MaskAddrOffset(0),
621					       BitmapExtent08, StaticReg(1),
622					       DataDynamic, MaskOtc,
623					       BGx(0), FGx(0)));
624	packed_dst = 0;
625	packed_len = (fb->var.xres << 16) | fb->var.yres;
626	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
627	NGLE_SET_DSTXY(fb, packed_dst);
628	SET_LENXY_START_RECFILL(fb, packed_len);
629
630	/*
631	 * In order to work around an ELK hardware problem (Buffy doesn't
632	 * always flush it's buffers when writing to the attribute
633	 * planes), at least 4 pixels must be written to the attribute
634	 * planes starting at (X == 1280) and (Y != to the last Y written
635	 * by BIF):
636	 */
637
638	if (fb->id == S9000_ID_A1659A) {   /* ELK_DEVICE_ID */
639		/* It's safe to use scanline zero: */
640		packed_dst = (1280 << 16);
641		GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
642		NGLE_SET_DSTXY(fb, packed_dst);
643		packed_len = (4 << 16) | 1;
644		SET_LENXY_START_RECFILL(fb, packed_len);
645	}   /* ELK Hardware Kludge */
646
647	/**** Finally, set the Control Plane Register back to zero: ****/
648	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
649	NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
650
651	NGLE_UNLOCK(fb);
652}
653
654static void
655ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
656{
657	int nFreeFifoSlots = 0;
658	u32 packed_dst;
659	u32 packed_len;
660
661	NGLE_LOCK(fb);
662
663	/* Hardware setup */
664	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
665	NGLE_QUICK_SET_DST_BM_ACCESS(fb,
666				     BA(IndexedDcd, Otc04, Ots08, AddrLong,
667					BAJustPoint(0), BINovly, BAIndexBase(0)));
668
669        NGLE_SET_TRANSFERDATA(fb, 0xffffffff);  /* Write foreground color */
670
671        NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
672        NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
673
674        packed_dst = 0;
675        packed_len = (fb->var.xres << 16) | fb->var.yres;
676        NGLE_SET_DSTXY(fb, packed_dst);
677
678        /* Write zeroes to overlay planes */
679	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
680				       IBOvals(RopSrc, MaskAddrOffset(0),
681					       BitmapExtent08, StaticReg(0),
682					       DataDynamic, MaskOtc, BGx(0), FGx(0)));
683
684        SET_LENXY_START_RECFILL(fb, packed_len);
685
686	NGLE_UNLOCK(fb);
687}
688
689static void
690hyperResetPlanes(struct stifb_info *fb, int enable)
691{
692	unsigned int controlPlaneReg;
693
694	NGLE_LOCK(fb);
695
696	if (IS_24_DEVICE(fb))
697		if (fb->var.bits_per_pixel == 32)
698			controlPlaneReg = 0x04000F00;
699		else
700			controlPlaneReg = 0x00000F00;   /* 0x00000800 should be enought, but lets clear all 4 bits */
701	else
702		controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
703
704	switch (enable) {
705	case 1:		/* ENABLE */
706		/* clear screen */
707		if (IS_24_DEVICE(fb))
708			ngleDepth24_ClearImagePlanes(fb);
709		else
710			ngleDepth8_ClearImagePlanes(fb);
711
712		/* Paint attribute planes for default case.
713		 * On Hyperdrive, this means all windows using overlay cmap 0. */
714		ngleResetAttrPlanes(fb, controlPlaneReg);
715
716		/* clear overlay planes */
717	        ngleClearOverlayPlanes(fb, 0xff, 255);
718
719		/**************************************************
720		 ** Also need to counteract ITE settings
721		 **************************************************/
722		hyperUndoITE(fb);
723		break;
724
725	case 0:		/* DISABLE */
726		/* clear screen */
727		if (IS_24_DEVICE(fb))
728			ngleDepth24_ClearImagePlanes(fb);
729		else
730			ngleDepth8_ClearImagePlanes(fb);
731		ngleResetAttrPlanes(fb, controlPlaneReg);
732		ngleClearOverlayPlanes(fb, 0xff, 0);
733		break;
734
735	case -1:	/* RESET */
736		hyperUndoITE(fb);
737		ngleResetAttrPlanes(fb, controlPlaneReg);
738		break;
739    	}
740
741	NGLE_UNLOCK(fb);
742}
743
744/* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
745
746static void
747ngleGetDeviceRomData(struct stifb_info *fb)
748{
749}
750
751
752#define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES	4
753#define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE	8
754#define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE		10
755#define HYPERBOWL_MODE2_8_24					15
756
757/* HCRX specific boot-time initialization */
758static void __init
759SETUP_HCRX(struct stifb_info *fb)
760{
761	int	hyperbowl;
762        int	nFreeFifoSlots = 0;
763
764	if (fb->id != S9000_ID_HCRX)
765		return;
766
767	/* Initialize Hyperbowl registers */
768	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
769
770	if (IS_24_DEVICE(fb)) {
771		hyperbowl = (fb->var.bits_per_pixel == 32) ?
772			HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
773			HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
774
775		/* First write to Hyperbowl must happen twice (bug) */
776		WRITE_WORD(hyperbowl, fb, REG_40);
777		WRITE_WORD(hyperbowl, fb, REG_40);
778
779		WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
780
781		WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
782		WRITE_WORD(0x404c4048, fb, REG_43);
783		WRITE_WORD(0x034c0348, fb, REG_44);
784		WRITE_WORD(0x444c4448, fb, REG_45);
785	} else {
786		hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
787
788		/* First write to Hyperbowl must happen twice (bug) */
789		WRITE_WORD(hyperbowl, fb, REG_40);
790		WRITE_WORD(hyperbowl, fb, REG_40);
791
792		WRITE_WORD(0x00000000, fb, REG_42);
793		WRITE_WORD(0x00000000, fb, REG_43);
794		WRITE_WORD(0x00000000, fb, REG_44);
795		WRITE_WORD(0x444c4048, fb, REG_45);
796	}
797}
798
799
800/* ------------------- driver specific functions --------------------------- */
801
802static int
803stifb_getcolreg(u_int regno, u_int *red, u_int *green,
804	      u_int *blue, u_int *transp, struct fb_info *info)
805{
806	struct stifb_info *fb = (struct stifb_info *) info;
807
808	if (regno > 255)
809		return 1;
810	*red = (fb->palette[regno].red<<8) | fb->palette[regno].red;
811	*green = (fb->palette[regno].green<<8) | fb->palette[regno].green;
812	*blue = (fb->palette[regno].blue<<8) | fb->palette[regno].blue;
813	*transp = 0;
814
815	return 0;
816}
817
818static int
819stifb_setcolreg(u_int regno, u_int red, u_int green,
820	      u_int blue, u_int transp, struct fb_info *info)
821{
822	struct stifb_info *fb = (struct stifb_info *) info;
823
824	if (regno > 255)
825		return 1;
826
827	red >>= 8;
828	green >>= 8;
829	blue >>= 8;
830
831	if ((fb->palette[regno].red != red) ||
832	    (fb->palette[regno].green != green) ||
833	    (fb->palette[regno].blue != blue))
834		fb->cmap_reload = 1;
835
836	fb->palette[regno].red = red;
837	fb->palette[regno].green = green;
838	fb->palette[regno].blue = blue;
839
840#ifdef FBCON_HAS_CFB32
841	if (regno < 16 && fb->var.bits_per_pixel == 32) {
842		fb->fbcon_cmap.cfb32[regno] = ((red << 16) |
843					       (green << 8) |
844					       (blue << 0) |
845					       (transp << 24));
846	}
847#endif
848	return 0;
849}
850
851static void
852stifb_loadcmap(struct stifb_info *fb)
853{
854	u32 color;
855	int i;
856
857	if (!fb->cmap_reload)
858		return;
859
860	START_IMAGE_COLORMAP_ACCESS(fb);
861	for (i = 0; i < 256; i++) {
862		if (fb->var.bits_per_pixel > 8) {
863			color = (i << 16) | (i << 8) | i;
864		} else {
865			if (fb->var.grayscale) {
866				/* gray = 0.30*R + 0.59*G + 0.11*B */
867				color = ((fb->palette[i].red * 77) +
868					 (fb->palette[i].green * 151) +
869					 (fb->palette[i].blue * 28)) >> 8;
870			} else {
871				color = ((fb->palette[i].red << 16) |
872					 (fb->palette[i].green << 8) |
873					 (fb->palette[i].blue));
874			}
875		}
876		WRITE_IMAGE_COLOR(fb, i, color);
877	}
878	if (fb->id == S9000_ID_HCRX) {
879		NgleLutBltCtl lutBltCtl;
880
881		lutBltCtl = setHyperLutBltCtl(fb,
882				0,	/* Offset w/i LUT */
883				256);	/* Load entire LUT */
884		NGLE_BINC_SET_SRCADDR(fb,
885				NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
886				/* 0x100 is same as used in WRITE_IMAGE_COLOR() */
887		START_COLORMAPLOAD(fb, lutBltCtl.all);
888		SETUP_FB(fb);
889	} else {
890		/* cleanup colormap hardware */
891		FINISH_IMAGE_COLORMAP_ACCESS(fb);
892	}
893	fb->cmap_reload = 0;
894}
895
896static int
897stifb_get_fix(struct fb_fix_screeninfo *fix, int con,
898	      struct fb_info *info)
899{
900	memcpy (fix, &((struct stifb_info *)info)->fix, sizeof (*fix));
901	return 0;
902}
903
904static int
905stifb_get_var(struct fb_var_screeninfo *var, int con,
906	      struct fb_info *info)
907{
908	memcpy (var, &((struct stifb_info *)info)->var, sizeof (*var));
909	return 0;
910}
911
912static int
913stifb_set_var(struct fb_var_screeninfo *var, int con,
914	      struct fb_info *info)
915{
916	struct display *disp;
917
918	if (con >= 0)
919		disp = &fb_display[con];
920	else
921		disp = info->disp;
922
923	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
924		if (disp->var.xres != var->xres ||
925		    disp->var.yres != var->yres ||
926		    disp->var.xres_virtual != var->xres_virtual ||
927		    disp->var.yres_virtual != var->yres_virtual ||
928		    disp->var.bits_per_pixel != var->bits_per_pixel ||
929		    disp->var.accel_flags != var->accel_flags)
930			return -EINVAL;
931	}
932	return 0;
933}
934
935static int
936stifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
937	       struct fb_info *info)
938{
939	struct stifb_info *fb = (struct stifb_info *)info;
940
941	if (con == fb->currcon) /* current console ? */
942		return fb_get_cmap(cmap, kspc, stifb_getcolreg, info);
943	else if (fb_display[con].cmap.len) /* non default colormap ? */
944		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
945	else
946		fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel > 8 ? 16 : 256), cmap, kspc ? 0: 2);
947	return 0;
948}
949
950static int
951stifb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
952	       struct fb_info *info)
953{
954	struct stifb_info *fb = (struct stifb_info *)info;
955	struct display *disp;
956	int err;
957
958	if (con >= 0)
959		disp = &fb_display[con];
960	else
961		disp = info->disp;
962
963	if (!disp->cmap.len) { /* no colormap allocated ? */
964		if ((err = fb_alloc_cmap(&disp->cmap, disp->var.bits_per_pixel > 8 ? 16 : 256, 0)))
965			return err;
966	}
967	if (con == fb->currcon || con == -1) {
968		err = fb_set_cmap(cmap, kspc, stifb_setcolreg, info);
969		if (!err)
970			stifb_loadcmap ((struct stifb_info *)info);
971		return err;
972	} else
973		fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
974	return 0;
975}
976
977static void
978stifb_blank(int blank_mode, struct fb_info *info)
979{
980	struct stifb_info *fb = (struct stifb_info *) info;
981	int enable = (blank_mode == 0) ? ENABLE : DISABLE;
982
983	switch (fb->id) {
984	case S9000_ID_A1439A:
985		CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
986		break;
987	case CRT_ID_VISUALIZE_EG:
988	case S9000_ID_ARTIST:
989		ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
990		break;
991	case S9000_ID_HCRX:
992		HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
993		break;
994	case S9000_ID_A1659A:;	/* fall through */
995	case S9000_ID_TIMBER:;
996	case CRX24_OVERLAY_PLANES:;
997	default:
998		ENABLE_DISABLE_DISPLAY(fb, enable);
999		break;
1000	}
1001
1002	SETUP_FB(fb);
1003}
1004
1005static void
1006stifb_set_disp(struct stifb_info *fb)
1007{
1008	int id = fb->id;
1009
1010	SETUP_FB(fb);
1011
1012	/* HCRX specific initialization */
1013	SETUP_HCRX(fb);
1014
1015	/*
1016	if (id == S9000_ID_HCRX)
1017		hyperInitSprite(fb);
1018	else
1019		ngleInitSprite(fb);
1020	*/
1021
1022	/* Initialize the image planes. */
1023        switch (id) {
1024	 case S9000_ID_HCRX:
1025	    hyperResetPlanes(fb, ENABLE);
1026	    break;
1027	 case S9000_ID_A1439A:
1028	    rattlerSetupPlanes(fb);
1029	    break;
1030	 case S9000_ID_A1659A:
1031	 case S9000_ID_ARTIST:
1032	 case CRT_ID_VISUALIZE_EG:
1033	    elkSetupPlanes(fb);
1034	    break;
1035	}
1036
1037	/* Clear attribute planes on non HCRX devices. */
1038        switch (id) {
1039	 case S9000_ID_A1659A:
1040	 case S9000_ID_A1439A:
1041	    if (fb->var.bits_per_pixel == 32)
1042		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1043	    else {
1044		ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1045	    }
1046	    if (id == S9000_ID_A1439A)
1047		ngleClearOverlayPlanes(fb, 0xff, 0);
1048	    break;
1049	 case S9000_ID_ARTIST:
1050	 case CRT_ID_VISUALIZE_EG:
1051	    if (fb->var.bits_per_pixel == 32)
1052		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1053	    else {
1054		ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1055	    }
1056	    break;
1057	}
1058	stifb_blank(0, (struct fb_info *)fb);	/* 0=enable screen */
1059
1060	SETUP_FB(fb);
1061}
1062
1063static int
1064stifb_switch(int con, struct fb_info *info)
1065{
1066	struct stifb_info *fb = (struct stifb_info *)info;
1067
1068	/* Do we have to save the colormap ? */
1069	if (fb->currcon != -1 && fb_display[fb->currcon].cmap.len)
1070		fb_get_cmap(&fb_display[fb->currcon].cmap, 1, stifb_getcolreg, info);
1071
1072	fb->currcon = con;
1073	/* Install new colormap */
1074	if (fb_display[con].cmap.len)
1075		fb_set_cmap(&fb_display[con].cmap, 1, stifb_setcolreg, info);
1076	else
1077		fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel > 8 ? 16 : 256),
1078			    1, stifb_setcolreg, info);
1079	stifb_loadcmap ((struct stifb_info *)info);
1080	return 0;
1081}
1082
1083static int
1084stifb_update_var(int con, struct fb_info *info)
1085{
1086	return 0;
1087}
1088
1089/* ------------ Interfaces to hardware functions ------------ */
1090
1091static struct fb_ops stifb_ops = {
1092	owner:		THIS_MODULE,
1093	fb_get_fix:	stifb_get_fix,
1094	fb_get_var:	stifb_get_var,
1095	fb_set_var:	stifb_set_var,
1096	fb_get_cmap:	stifb_get_cmap,
1097	fb_set_cmap:	stifb_set_cmap,
1098//	fb_pan_display:	fbgen_pan_display,
1099//	fb_ioctl:       xxxfb_ioctl,   /* optional */
1100};
1101
1102
1103    /*
1104     *  Initialization
1105     */
1106
1107int __init
1108stifb_init_fb(struct sti_struct *sti, int force_bpp)
1109{
1110	struct fb_fix_screeninfo *fix;
1111	struct fb_var_screeninfo *var;
1112	struct display *disp;
1113	struct stifb_info *fb;
1114	unsigned long sti_rom_address;
1115	char *dev_name;
1116	int bpp, xres, yres;
1117
1118	fb = kmalloc(sizeof(struct stifb_info), GFP_ATOMIC);
1119	if (!fb) {
1120		printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
1121		return -ENODEV;
1122	}
1123
1124	/* set struct to a known state */
1125	memset(fb, 0, sizeof(struct stifb_info));
1126	fix = &fb->fix;
1127	var = &fb->var;
1128	disp = &fb->disp;
1129
1130	fb->currcon = -1;
1131	fb->cmap_reload = 1;
1132	fb->sti = sti;
1133	/* store upper 32bits of the graphics id */
1134	fb->id = fb->sti->graphics_id[0];
1135	fb->real_id = fb->id;	/* save the real id */
1136
1137	/* only supported cards are allowed */
1138	switch (fb->id) {
1139	case S9000_ID_ARTIST:
1140	case S9000_ID_HCRX:
1141	case S9000_ID_TIMBER:
1142	case S9000_ID_A1659A:
1143	case S9000_ID_A1439A:
1144	case CRT_ID_VISUALIZE_EG:
1145		break;
1146	default:
1147		printk(KERN_WARNING "stifb: Unsupported gfx card id 0x%08x\n",
1148			fb->id);
1149		goto out_err1;
1150	}
1151
1152	/* default to 8 bpp on most graphic chips */
1153	bpp = 8;
1154	xres = sti_onscreen_x(fb->sti);
1155	yres = sti_onscreen_y(fb->sti);
1156
1157	ngleGetDeviceRomData(fb);
1158
1159	/* get (virtual) io region base addr */
1160	fix->mmio_start = REGION_BASE(fb,2);
1161	fix->mmio_len   = 0x400000;
1162
1163       	/* Reject any device not in the NGLE family */
1164	switch (fb->id) {
1165	case S9000_ID_A1659A:	/* CRX/A1659A */
1166		break;
1167	case S9000_ID_ELM:	/* GRX, grayscale but else same as A1659A */
1168		var->grayscale = 1;
1169		fb->id = S9000_ID_A1659A;
1170		break;
1171	case S9000_ID_TIMBER:	/* HP9000/710 Any (may be a grayscale device) */
1172		dev_name = fb->sti->outptr.dev_name;
1173		if (strstr(dev_name, "GRAYSCALE") ||
1174		    strstr(dev_name, "Grayscale") ||
1175		    strstr(dev_name, "grayscale"))
1176			var->grayscale = 1;
1177		break;
1178	case S9000_ID_TOMCAT:	/* Dual CRX, behaves else like a CRX */
1179		xres = fb->ngle_rom.x_size_visible;
1180		yres = fb->ngle_rom.y_size_visible;
1181		fb->id = S9000_ID_A1659A;
1182		break;
1183	case S9000_ID_A1439A:	/* CRX24/A1439A */
1184		bpp = 32;
1185		break;
1186	case S9000_ID_HCRX:	/* Hyperdrive/HCRX */
1187		memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1188		if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1189		    (fb->sti->regions_phys[2] & 0xfc000000))
1190			sti_rom_address = fb->sti->regions_phys[0];
1191		else
1192			sti_rom_address = fb->sti->regions_phys[1];
1193#ifdef __LP64__
1194	        sti_rom_address |= 0xffffffff00000000;
1195#endif
1196		fb->deviceSpecificConfig = __raw_readl(sti_rom_address);
1197		if (IS_24_DEVICE(fb)) {
1198			if (force_bpp == 8 || force_bpp == 32)
1199				bpp = force_bpp;
1200			else
1201				bpp = 32;
1202		} else
1203			bpp = 8;
1204		READ_WORD(fb, REG_15);
1205		SETUP_HW(fb);
1206		break;
1207	case CRT_ID_VISUALIZE_EG:
1208	case S9000_ID_ARTIST:	/* Artist */
1209		break;
1210	default:
1211#ifdef FALLBACK_TO_1BPP
1212	       	printk(KERN_WARNING
1213			"stifb: Unsupported graphics card (id=0x%08x) "
1214				"- now trying 1bpp mode instead\n",
1215			fb->id);
1216		bpp = 1;	/* default to 1 bpp */
1217		break;
1218#else
1219	       	printk(KERN_WARNING
1220			"stifb: Unsupported graphics card (id=0x%08x) "
1221				"- skipping.\n",
1222			fb->id);
1223		goto out_err1;
1224#endif
1225	}
1226
1227
1228	/* get framebuffer pysical and virtual base addr & len (64bit ready) */
1229	fix->smem_start = fb->sti->regions_phys[1] | 0xffffffff00000000;
1230	fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1231
1232	fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1233	if (!fix->line_length)
1234		fix->line_length = 2048; /* default */
1235	fix->accel = FB_ACCEL_NONE;
1236
1237	switch (bpp) {
1238	    case 1:
1239		fix->type = FB_TYPE_PLANES;	/* well, sort of */
1240		fix->visual = FB_VISUAL_MONO10;
1241		disp->dispsw = &fbcon_sti;
1242		break;
1243#ifdef FBCON_HAS_CFB8
1244	    case 8:
1245		fix->type = FB_TYPE_PACKED_PIXELS;
1246		fix->visual = FB_VISUAL_PSEUDOCOLOR;
1247	 	disp->dispsw = &fbcon_cfb8;
1248		var->red.length = var->green.length = var->blue.length = 8;
1249		break;
1250#endif
1251#ifdef FBCON_HAS_CFB32
1252	    case 32:
1253		fix->type = FB_TYPE_PACKED_PIXELS;
1254		fix->visual = FB_VISUAL_TRUECOLOR;
1255		disp->dispsw = &fbcon_cfb32;
1256		disp->dispsw_data = fb->fbcon_cmap.cfb32;
1257		var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1258		var->blue.offset = 0;
1259		var->green.offset = 8;
1260		var->red.offset = 16;
1261		var->transp.offset = 24;
1262		break;
1263#endif
1264	    default:
1265		disp->dispsw = &fbcon_dummy;
1266		break;
1267	}
1268
1269	var->xres = var->xres_virtual = xres;
1270	var->yres = var->yres_virtual = yres;
1271	var->bits_per_pixel = bpp;
1272
1273	disp->var = *var;
1274	disp->visual = fix->visual;
1275	disp->type = fix->type;
1276	disp->type_aux = fix->type_aux;
1277	disp->line_length = fix->line_length;
1278	disp->var.activate = FB_ACTIVATE_NOW;
1279	disp->screen_base = (void*) REGION_BASE(fb,1);
1280	disp->can_soft_blank = 1;
1281	disp->scrollmode = SCROLL_YREDRAW;
1282
1283	strcpy(fb->info.modename, "stifb");
1284	fb->info.node = -1;
1285	fb->info.flags = FBINFO_FLAG_DEFAULT;
1286	fb->info.fbops = &stifb_ops;
1287	fb->info.disp = disp;
1288	fb->info.changevar = NULL;
1289	fb->info.switch_con = &stifb_switch;
1290	fb->info.updatevar = &stifb_update_var;
1291	fb->info.blank = &stifb_blank;
1292	fb->info.flags = FBINFO_FLAG_DEFAULT;
1293
1294	stifb_set_var(&disp->var, 1, &fb->info);
1295
1296	stifb_set_disp(fb);
1297
1298	if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb")) {
1299		printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1300				fix->smem_start, fix->smem_start+fix->smem_len);
1301		goto out_err1;
1302	}
1303
1304	if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1305		printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1306				fix->mmio_start, fix->mmio_start+fix->mmio_len);
1307		goto out_err2;
1308	}
1309
1310	if (register_framebuffer(&fb->info) < 0)
1311		goto out_err3;
1312
1313	printk(KERN_INFO
1314	    "fb%d: %s %dx%d-%d frame buffer device, id: %04x, mmio: 0x%04lx\n",
1315		GET_FB_IDX(fb->info.node),
1316		fb->info.modename,
1317		disp->var.xres,
1318		disp->var.yres,
1319		disp->var.bits_per_pixel,
1320		fb->id,
1321		fix->mmio_start);
1322
1323	return 0;
1324
1325
1326out_err3:
1327	release_mem_region(fix->mmio_start, fix->mmio_len);
1328out_err2:
1329	release_mem_region(fix->smem_start, fix->smem_len);
1330out_err1:
1331	kfree(fb);
1332	return -ENXIO;
1333}
1334
1335int __init
1336stifb_init(void)
1337{
1338	struct sti_struct *sti;
1339	int i;
1340
1341
1342	if (sti_init_roms() == NULL)
1343		return -ENXIO; /* no STI cards available */
1344
1345	for (i = 0; i < MAX_STI_ROMS; i++) {
1346		sti = sti_get_rom(i);
1347		if (sti)
1348			stifb_init_fb (sti, stifb_force_bpp[i]);
1349		else
1350			break;
1351	}
1352	return 0;
1353}
1354
1355/*
1356 *  Cleanup
1357 */
1358
1359void __exit
1360stifb_cleanup(struct fb_info *info)
1361{
1362	// unregister_framebuffer(info);
1363}
1364
1365int __init
1366stifb_setup(char *options)
1367{
1368	int i;
1369
1370	if (!options || !*options)
1371		return 0;
1372
1373	if (strncmp(options, "bpp", 3) == 0) {
1374		options += 3;
1375		for (i = 0; i < MAX_STI_ROMS; i++) {
1376			if (*options++ == ':')
1377				stifb_force_bpp[i] = simple_strtoul(options, &options, 10);
1378			else
1379				break;
1380		}
1381	}
1382	return 0;
1383}
1384
1385__setup("stifb=", stifb_setup);
1386
1387#ifdef MODULE
1388module_init(stifb_init);
1389#endif
1390module_exit(stifb_cleanup);
1391
1392MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1393MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1394MODULE_LICENSE("GPL");
1395
1396MODULE_PARM(bpp, "i");
1397MODULE_PARM_DESC(mem, "Bits per pixel (default: 8)");
1398
1399