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