import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / video / sti / stifb.c
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
187 SETUP_HW(struct stifb_info *fb)
188 {
189         char stat;
190
191         do {
192                 stat = READ_BYTE(fb, REG_15b0);
193                 if (!stat)
194                         stat = READ_BYTE(fb, REG_15b0);
195         } while (stat);
196 }
197
198
199 static void
200 SETUP_FB(struct stifb_info *fb)
201 {       
202         unsigned int reg10_value = 0;
203         
204         SETUP_HW(fb);
205         switch (fb->id)
206         {
207                 case CRT_ID_VISUALIZE_EG:
208                 case S9000_ID_ARTIST:
209                 case S9000_ID_A1659A:
210                         reg10_value = 0x13601000;
211                         break;
212                 case S9000_ID_A1439A:
213                         if (fb->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
237 START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
238 {
239         SETUP_HW(fb);
240         WRITE_WORD(0xBBE0F000, fb, REG_10);
241         WRITE_WORD(0x03000300, fb, REG_14);
242         WRITE_WORD(~0, fb, REG_13);
243 }
244
245 static void
246 WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color) 
247 {
248         SETUP_HW(fb);
249         WRITE_WORD(((0x100+index)<<2), fb, REG_3);
250         WRITE_WORD(color, fb, REG_4);
251 }
252
253 static void
254 FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) 
255 {               
256         WRITE_WORD(0x400, fb, REG_2);
257         if (fb->var.bits_per_pixel == 32) {
258                 WRITE_WORD(0x83000100, fb, REG_1);
259         } else {
260                 if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
261                         WRITE_WORD(0x80000100, fb, REG_26);
262                 else                                                    
263                         WRITE_WORD(0x80000100, fb, REG_1);
264         }
265         SETUP_FB(fb);
266 }
267
268 static void
269 SETUP_RAMDAC(struct stifb_info *fb) 
270 {
271         SETUP_HW(fb);
272         WRITE_WORD(0x04000000, fb, 0x1020);
273         WRITE_WORD(0xff000000, fb, 0x1028);
274 }
275
276 static void 
277 CRX24_SETUP_RAMDAC(struct stifb_info *fb) 
278 {
279         SETUP_HW(fb);
280         WRITE_WORD(0x04000000, fb, 0x1000);
281         WRITE_WORD(0x02000000, fb, 0x1004);
282         WRITE_WORD(0xff000000, fb, 0x1008);
283         WRITE_WORD(0x05000000, fb, 0x1000);
284         WRITE_WORD(0x02000000, fb, 0x1004);
285         WRITE_WORD(0x03000000, fb, 0x1008);
286 }
287
288 #if 0
289 static void 
290 HCRX_SETUP_RAMDAC(struct stifb_info *fb)
291 {
292         WRITE_WORD(0xffffffff, fb, REG_32);
293 }
294 #endif
295
296 static void 
297 CRX24_SET_OVLY_MASK(struct stifb_info *fb)
298 {
299         SETUP_HW(fb);
300         WRITE_WORD(0x13a02000, fb, REG_11);
301         WRITE_WORD(0x03000300, fb, REG_14);
302         WRITE_WORD(0x000017f0, fb, REG_3);
303         WRITE_WORD(0xffffffff, fb, REG_13);
304         WRITE_WORD(0xffffffff, fb, REG_22);
305         WRITE_WORD(0x00000000, fb, REG_23);
306 }
307
308 static void
309 ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
310 {
311         unsigned int value = enable ? 0x43000000 : 0x03000000;
312         SETUP_HW(fb);
313         WRITE_WORD(0x06000000,  fb, 0x1030);
314         WRITE_WORD(value,       fb, 0x1038);
315 }
316
317 static void 
318 CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
319 {
320         unsigned int value = enable ? 0x10000000 : 0x30000000;
321         SETUP_HW(fb);
322         WRITE_WORD(0x01000000,  fb, 0x1000);
323         WRITE_WORD(0x02000000,  fb, 0x1004);
324         WRITE_WORD(value,       fb, 0x1008);
325 }
326
327 static void
328 ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) 
329 {
330         u32 DregsMiscVideo = REG_21;
331         u32 DregsMiscCtl = REG_27;
332         
333         SETUP_HW(fb);
334         if (enable) {
335           WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
336           WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   | 0x00800000, fb, DregsMiscCtl);
337         } else {
338           WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
339           WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   & ~0x00800000, fb, DregsMiscCtl);
340         }
341 }
342
343 #define GET_ROMTABLE_INDEX(fb) \
344         (READ_BYTE(fb, REG_16b3) - 1)
345
346 #define HYPER_CONFIG_PLANES_24 0x00000100
347         
348 #define IS_24_DEVICE(fb) \
349         (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
350
351 #define IS_888_DEVICE(fb) \
352         (!(IS_24_DEVICE(fb)))
353
354 #define GET_FIFO_SLOTS(fb, cnt, numslots)                       \
355 {       while (cnt < numslots)                                  \
356                 cnt = READ_WORD(fb, REG_34);    \
357         cnt -= numslots;                                        \
358 }
359
360 #define     IndexedDcd  0       /* Pixel data is indexed (pseudo) color */
361 #define     Otc04       2       /* Pixels in each longword transfer (4) */
362 #define     Otc32       5       /* Pixels in each longword transfer (32) */
363 #define     Ots08       3       /* Each pixel is size (8)d transfer (1) */
364 #define     OtsIndirect 6       /* Each bit goes through FG/BG color(8) */
365 #define     AddrLong    5       /* FB address is Long aligned (pixel) */
366 #define     BINovly     0x2     /* 8 bit overlay */
367 #define     BINapp0I    0x0     /* Application Buffer 0, Indexed */
368 #define     BINapp1I    0x1     /* Application Buffer 1, Indexed */
369 #define     BINapp0F8   0xa     /* Application Buffer 0, Fractional 8-8-8 */
370 #define     BINattr     0xd     /* Attribute Bitmap */
371 #define     RopSrc      0x3
372 #define     BitmapExtent08  3   /* Each write hits ( 8) bits in depth */
373 #define     BitmapExtent32  5   /* Each write hits (32) bits in depth */
374 #define     DataDynamic     0   /* Data register reloaded by direct access */
375 #define     MaskDynamic     1   /* Mask register reloaded by direct access */
376 #define     MaskOtc         0   /* Mask contains Object Count valid bits */
377
378 #define MaskAddrOffset(offset) (offset)
379 #define StaticReg(en) (en)
380 #define BGx(en) (en)
381 #define FGx(en) (en)
382
383 #define BAJustPoint(offset) (offset)
384 #define BAIndexBase(base) (base)
385 #define BA(F,C,S,A,J,B,I) \
386         (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
387
388 #define IBOvals(R,M,X,S,D,L,B,F) \
389         (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
390
391 #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
392         WRITE_WORD(val, fb, REG_14)
393
394 #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
395         WRITE_WORD(val, fb, REG_11)
396
397 #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
398         WRITE_WORD(val, fb, REG_12)
399
400 #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
401         WRITE_WORD(plnmsk32, fb, REG_13)
402
403 #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
404         WRITE_WORD(fg32, fb, REG_35)
405
406 #define NGLE_SET_TRANSFERDATA(fb, val) \
407         WRITE_WORD(val, fb, REG_8)
408
409 #define NGLE_SET_DSTXY(fb, val) \
410         WRITE_WORD(val, fb, REG_6)
411
412 #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) (                \
413         (u32) (fbaddrbase) +                            \
414             (   (unsigned int)  ( (y) << 13      ) |            \
415                 (unsigned int)  ( (x) << 2       )      )       \
416         )
417
418 #define NGLE_BINC_SET_DSTADDR(fb, addr) \
419         WRITE_WORD(addr, fb, REG_3)
420
421 #define NGLE_BINC_SET_SRCADDR(fb, addr) \
422         WRITE_WORD(addr, fb, REG_2)
423
424 #define NGLE_BINC_SET_DSTMASK(fb, mask) \
425         WRITE_WORD(mask, fb, REG_22)
426
427 #define NGLE_BINC_WRITE32(fb, data32) \
428         WRITE_WORD(data32, fb, REG_23)
429
430 #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
431         WRITE_WORD((cmapBltCtlData32), fb, REG_38)
432
433 #define SET_LENXY_START_RECFILL(fb, lenxy) \
434         WRITE_WORD(lenxy, fb, REG_9)
435
436 static void
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
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
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
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
486 elkSetupPlanes(struct stifb_info *fb)
487 {
488         SETUP_RAMDAC(fb);
489         SETUP_FB(fb);
490 }
491
492 static void 
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
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
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
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 
640 ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
641 {
642         /* FIXME! */
643 }
644
645 static void 
646 ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
647 {
648         /* FIXME! */
649 }
650
651 static void
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
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 
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 
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1472 stifb_cleanup(struct fb_info *info)
1473 {
1474         // unregister_framebuffer(info); 
1475 }
1476
1477 int __init
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