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