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