Merge branch 'agp-patches' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[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                                                         __FUNCTION__, 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                                                         __FUNCTION__, 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         CRX24_SETUP_RAMDAC(fb);
509     
510         /* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */
511         WRITE_WORD(0x83000300, fb, REG_14);
512         SETUP_HW(fb);
513         WRITE_BYTE(1, fb, REG_16b1);
514
515         fb_memset((void*)fb->info.fix.smem_start, 0xff,
516                 fb->info.var.yres*fb->info.fix.line_length);
517     
518         CRX24_SET_OVLY_MASK(fb);
519         SETUP_FB(fb);
520 }
521
522
523 #define HYPER_CMAP_TYPE                         0
524 #define NGLE_CMAP_INDEXED0_TYPE                 0
525 #define NGLE_CMAP_OVERLAY_TYPE                  3
526
527 /* typedef of LUT (Colormap) BLT Control Register */
528 typedef union   /* Note assumption that fields are packed left-to-right */
529 {       u32 all;
530         struct
531         {
532                 unsigned enable              :  1;
533                 unsigned waitBlank           :  1;
534                 unsigned reserved1           :  4;
535                 unsigned lutOffset           : 10;   /* Within destination LUT */
536                 unsigned lutType             :  2;   /* Cursor, image, overlay */
537                 unsigned reserved2           :  4;
538                 unsigned length              : 10;
539         } fields;
540 } NgleLutBltCtl;
541
542
543 #if 0
544 static NgleLutBltCtl
545 setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
546 {
547         NgleLutBltCtl lutBltCtl;
548
549         /* set enable, zero reserved fields */
550         lutBltCtl.all           = 0x80000000;
551         lutBltCtl.fields.length = length;
552
553         switch (fb->id) 
554         {
555         case S9000_ID_A1439A:           /* CRX24 */
556                 if (fb->var.bits_per_pixel == 8) {
557                         lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
558                         lutBltCtl.fields.lutOffset = 0;
559                 } else {
560                         lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
561                         lutBltCtl.fields.lutOffset = 0 * 256;
562                 }
563                 break;
564                 
565         case S9000_ID_ARTIST:
566                 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
567                 lutBltCtl.fields.lutOffset = 0 * 256;
568                 break;
569                 
570         default:
571                 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
572                 lutBltCtl.fields.lutOffset = 0;
573                 break;
574         }
575
576         /* Offset points to start of LUT.  Adjust for within LUT */
577         lutBltCtl.fields.lutOffset += offsetWithinLut;
578
579         return lutBltCtl;
580 }
581 #endif
582
583 static NgleLutBltCtl
584 setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) 
585 {
586         NgleLutBltCtl lutBltCtl;
587
588         /* set enable, zero reserved fields */
589         lutBltCtl.all = 0x80000000;
590
591         lutBltCtl.fields.length = length;
592         lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
593
594         /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
595         if (fb->info.var.bits_per_pixel == 8)
596                 lutBltCtl.fields.lutOffset = 2 * 256;
597         else
598                 lutBltCtl.fields.lutOffset = 0 * 256;
599
600         /* Offset points to start of LUT.  Adjust for within LUT */
601         lutBltCtl.fields.lutOffset += offsetWithinLut;
602
603         return lutBltCtl;
604 }
605
606
607 static void hyperUndoITE(struct stifb_info *fb)
608 {
609         int nFreeFifoSlots = 0;
610         u32 fbAddr;
611
612         NGLE_LOCK(fb);
613
614         GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
615         WRITE_WORD(0xffffffff, fb, REG_32);
616
617         /* Write overlay transparency mask so only entry 255 is transparent */
618
619         /* Hardware setup for full-depth write to "magic" location */
620         GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
621         NGLE_QUICK_SET_DST_BM_ACCESS(fb, 
622                 BA(IndexedDcd, Otc04, Ots08, AddrLong,
623                 BAJustPoint(0), BINovly, BAIndexBase(0)));
624         NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
625                 IBOvals(RopSrc, MaskAddrOffset(0),
626                 BitmapExtent08, StaticReg(0),
627                 DataDynamic, MaskOtc, BGx(0), FGx(0)));
628
629         /* Now prepare to write to the "magic" location */
630         fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
631         NGLE_BINC_SET_DSTADDR(fb, fbAddr);
632         NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
633         NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
634
635         /* Finally, write a zero to clear the mask */
636         NGLE_BINC_WRITE32(fb, 0);
637
638         NGLE_UNLOCK(fb);
639 }
640
641 static void 
642 ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
643 {
644         /* FIXME! */
645 }
646
647 static void 
648 ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
649 {
650         /* FIXME! */
651 }
652
653 static void
654 ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
655 {
656         int nFreeFifoSlots = 0;
657         u32 packed_dst;
658         u32 packed_len;
659
660         NGLE_LOCK(fb);
661
662         GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
663         NGLE_QUICK_SET_DST_BM_ACCESS(fb, 
664                                      BA(IndexedDcd, Otc32, OtsIndirect,
665                                         AddrLong, BAJustPoint(0),
666                                         BINattr, BAIndexBase(0)));
667         NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
668         NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
669
670         NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
671                                        IBOvals(RopSrc, MaskAddrOffset(0),
672                                                BitmapExtent08, StaticReg(1),
673                                                DataDynamic, MaskOtc,
674                                                BGx(0), FGx(0)));
675         packed_dst = 0;
676         packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
677         GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
678         NGLE_SET_DSTXY(fb, packed_dst);
679         SET_LENXY_START_RECFILL(fb, packed_len);
680
681         /*
682          * In order to work around an ELK hardware problem (Buffy doesn't
683          * always flush it's buffers when writing to the attribute
684          * planes), at least 4 pixels must be written to the attribute
685          * planes starting at (X == 1280) and (Y != to the last Y written
686          * by BIF):
687          */
688
689         if (fb->id == S9000_ID_A1659A) {   /* ELK_DEVICE_ID */
690                 /* It's safe to use scanline zero: */
691                 packed_dst = (1280 << 16);
692                 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
693                 NGLE_SET_DSTXY(fb, packed_dst);
694                 packed_len = (4 << 16) | 1;
695                 SET_LENXY_START_RECFILL(fb, packed_len);
696         }   /* ELK Hardware Kludge */
697
698         /**** Finally, set the Control Plane Register back to zero: ****/
699         GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
700         NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
701         
702         NGLE_UNLOCK(fb);
703 }
704     
705 static void
706 ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
707 {
708         int nFreeFifoSlots = 0;
709         u32 packed_dst;
710         u32 packed_len;
711     
712         NGLE_LOCK(fb);
713
714         /* Hardware setup */
715         GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
716         NGLE_QUICK_SET_DST_BM_ACCESS(fb, 
717                                      BA(IndexedDcd, Otc04, Ots08, AddrLong,
718                                         BAJustPoint(0), BINovly, BAIndexBase(0)));
719
720         NGLE_SET_TRANSFERDATA(fb, 0xffffffff);  /* Write foreground color */
721
722         NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
723         NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
724     
725         packed_dst = 0;
726         packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
727         NGLE_SET_DSTXY(fb, packed_dst);
728     
729         /* Write zeroes to overlay planes */                   
730         NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
731                                        IBOvals(RopSrc, MaskAddrOffset(0),
732                                                BitmapExtent08, StaticReg(0),
733                                                DataDynamic, MaskOtc, BGx(0), FGx(0)));
734                        
735         SET_LENXY_START_RECFILL(fb, packed_len);
736
737         NGLE_UNLOCK(fb);
738 }
739
740 static void 
741 hyperResetPlanes(struct stifb_info *fb, int enable)
742 {
743         unsigned int controlPlaneReg;
744
745         NGLE_LOCK(fb);
746
747         if (IS_24_DEVICE(fb))
748                 if (fb->info.var.bits_per_pixel == 32)
749                         controlPlaneReg = 0x04000F00;
750                 else
751                         controlPlaneReg = 0x00000F00;   /* 0x00000800 should be enought, but lets clear all 4 bits */
752         else
753                 controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
754
755         switch (enable) {
756         case ENABLE:
757                 /* clear screen */
758                 if (IS_24_DEVICE(fb))
759                         ngleDepth24_ClearImagePlanes(fb);
760                 else
761                         ngleDepth8_ClearImagePlanes(fb);
762
763                 /* Paint attribute planes for default case.
764                  * On Hyperdrive, this means all windows using overlay cmap 0. */
765                 ngleResetAttrPlanes(fb, controlPlaneReg);
766
767                 /* clear overlay planes */
768                 ngleClearOverlayPlanes(fb, 0xff, 255);
769
770                 /**************************************************
771                  ** Also need to counteract ITE settings 
772                  **************************************************/
773                 hyperUndoITE(fb);
774                 break;
775
776         case DISABLE:
777                 /* clear screen */
778                 if (IS_24_DEVICE(fb))
779                         ngleDepth24_ClearImagePlanes(fb);
780                 else
781                         ngleDepth8_ClearImagePlanes(fb);
782                 ngleResetAttrPlanes(fb, controlPlaneReg);
783                 ngleClearOverlayPlanes(fb, 0xff, 0);
784                 break;
785
786         case -1:        /* RESET */
787                 hyperUndoITE(fb);
788                 ngleResetAttrPlanes(fb, controlPlaneReg);
789                 break;
790         }
791         
792         NGLE_UNLOCK(fb);
793 }
794
795 /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
796
797 static void 
798 ngleGetDeviceRomData(struct stifb_info *fb)
799 {
800 #if 0
801 XXX: FIXME: !!!
802         int     *pBytePerLongDevDepData;/* data byte == LSB */
803         int     *pRomTable;
804         NgleDevRomData  *pPackedDevRomData;
805         int     sizePackedDevRomData = sizeof(*pPackedDevRomData);
806         char    *pCard8;
807         int     i;
808         char    *mapOrigin = NULL;
809     
810         int romTableIdx;
811
812         pPackedDevRomData = fb->ngle_rom;
813
814         SETUP_HW(fb);
815         if (fb->id == S9000_ID_ARTIST) {
816                 pPackedDevRomData->cursor_pipeline_delay = 4;
817                 pPackedDevRomData->video_interleaves     = 4;
818         } else {
819                 /* Get pointer to unpacked byte/long data in ROM */
820                 pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
821
822                 /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
823                 if (fb->id == S9000_ID_TOMCAT)
824         {
825             /*  jump to the correct ROM table  */
826             GET_ROMTABLE_INDEX(romTableIdx);
827             while  (romTableIdx > 0)
828             {
829                 pCard8 = (Card8 *) pPackedDevRomData;
830                 pRomTable = pBytePerLongDevDepData;
831                 /* Pack every fourth byte from ROM into structure */
832                 for (i = 0; i < sizePackedDevRomData; i++)
833                 {
834                     *pCard8++ = (Card8) (*pRomTable++);
835                 }
836
837                 pBytePerLongDevDepData = (Card32 *)
838                         ((Card8 *) pBytePerLongDevDepData +
839                                pPackedDevRomData->sizeof_ngle_data);
840
841                 romTableIdx--;
842             }
843         }
844
845         pCard8 = (Card8 *) pPackedDevRomData;
846
847         /* Pack every fourth byte from ROM into structure */
848         for (i = 0; i < sizePackedDevRomData; i++)
849         {
850             *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
851         }
852     }
853
854     SETUP_FB(fb);
855 #endif
856 }
857
858
859 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES     4
860 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE      8
861 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE           10
862 #define HYPERBOWL_MODE2_8_24                                    15
863
864 /* HCRX specific boot-time initialization */
865 static void __init
866 SETUP_HCRX(struct stifb_info *fb)
867 {
868         int     hyperbowl;
869         int     nFreeFifoSlots = 0;
870
871         if (fb->id != S9000_ID_HCRX)
872                 return;
873
874         /* Initialize Hyperbowl registers */
875         GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
876         
877         if (IS_24_DEVICE(fb)) {
878                 hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
879                         HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
880                         HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
881
882                 /* First write to Hyperbowl must happen twice (bug) */
883                 WRITE_WORD(hyperbowl, fb, REG_40);
884                 WRITE_WORD(hyperbowl, fb, REG_40);
885                 
886                 WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
887                 
888                 WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
889                 WRITE_WORD(0x404c4048, fb, REG_43);
890                 WRITE_WORD(0x034c0348, fb, REG_44);
891                 WRITE_WORD(0x444c4448, fb, REG_45);
892         } else {
893                 hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
894
895                 /* First write to Hyperbowl must happen twice (bug) */
896                 WRITE_WORD(hyperbowl, fb, REG_40);
897                 WRITE_WORD(hyperbowl, fb, REG_40);
898
899                 WRITE_WORD(0x00000000, fb, REG_42);
900                 WRITE_WORD(0x00000000, fb, REG_43);
901                 WRITE_WORD(0x00000000, fb, REG_44);
902                 WRITE_WORD(0x444c4048, fb, REG_45);
903         }
904 }
905
906
907 /* ------------------- driver specific functions --------------------------- */
908
909 static int
910 stifb_setcolreg(u_int regno, u_int red, u_int green,
911               u_int blue, u_int transp, struct fb_info *info)
912 {
913         struct stifb_info *fb = (struct stifb_info *) info;
914         u32 color;
915
916         if (regno >= NR_PALETTE)
917                 return 1;
918
919         red   >>= 8;
920         green >>= 8;
921         blue  >>= 8;
922
923         DEBUG_OFF();
924
925         START_IMAGE_COLORMAP_ACCESS(fb);
926
927         if (unlikely(fb->info.var.grayscale)) {
928                 /* gray = 0.30*R + 0.59*G + 0.11*B */
929                 color = ((red * 77) +
930                          (green * 151) +
931                          (blue * 28)) >> 8;
932         } else {
933                 color = ((red << 16) |
934                          (green << 8) |
935                          (blue));
936         }
937
938         if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
939                 struct fb_var_screeninfo *var = &fb->info.var;
940                 if (regno < 16)
941                         ((u32 *)fb->info.pseudo_palette)[regno] =
942                                 regno << var->red.offset |
943                                 regno << var->green.offset |
944                                 regno << var->blue.offset;
945         }
946
947         WRITE_IMAGE_COLOR(fb, regno, color);
948
949         if (fb->id == S9000_ID_HCRX) {
950                 NgleLutBltCtl lutBltCtl;
951
952                 lutBltCtl = setHyperLutBltCtl(fb,
953                                 0,      /* Offset w/i LUT */
954                                 256);   /* Load entire LUT */
955                 NGLE_BINC_SET_SRCADDR(fb,
956                                 NGLE_LONG_FB_ADDRESS(0, 0x100, 0)); 
957                                 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
958                 START_COLORMAPLOAD(fb, lutBltCtl.all);
959                 SETUP_FB(fb);
960         } else {
961                 /* cleanup colormap hardware */
962                 FINISH_IMAGE_COLORMAP_ACCESS(fb);
963         }
964
965         DEBUG_ON();
966
967         return 0;
968 }
969
970 static int
971 stifb_blank(int blank_mode, struct fb_info *info)
972 {
973         struct stifb_info *fb = (struct stifb_info *) info;
974         int enable = (blank_mode == 0) ? ENABLE : DISABLE;
975
976         switch (fb->id) {
977         case S9000_ID_A1439A:
978                 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
979                 break;
980         case CRT_ID_VISUALIZE_EG:
981         case S9000_ID_ARTIST:
982                 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
983                 break;
984         case S9000_ID_HCRX:
985                 HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
986                 break;
987         case S9000_ID_A1659A:   /* fall through */
988         case S9000_ID_TIMBER:
989         case CRX24_OVERLAY_PLANES:
990         default:
991                 ENABLE_DISABLE_DISPLAY(fb, enable);
992                 break;
993         }
994         
995         SETUP_FB(fb);
996         return 0;
997 }
998
999 static void __init
1000 stifb_init_display(struct stifb_info *fb)
1001 {
1002         int id = fb->id;
1003
1004         SETUP_FB(fb);
1005
1006         /* HCRX specific initialization */
1007         SETUP_HCRX(fb);
1008         
1009         /*
1010         if (id == S9000_ID_HCRX)
1011                 hyperInitSprite(fb);
1012         else
1013                 ngleInitSprite(fb);
1014         */
1015         
1016         /* Initialize the image planes. */ 
1017         switch (id) {
1018          case S9000_ID_HCRX:
1019             hyperResetPlanes(fb, ENABLE);
1020             break;
1021          case S9000_ID_A1439A:
1022             rattlerSetupPlanes(fb);
1023             break;
1024          case S9000_ID_A1659A:
1025          case S9000_ID_ARTIST:
1026          case CRT_ID_VISUALIZE_EG:
1027             elkSetupPlanes(fb);
1028             break;
1029         }
1030
1031         /* Clear attribute planes on non HCRX devices. */
1032         switch (id) {
1033          case S9000_ID_A1659A:
1034          case S9000_ID_A1439A:
1035             if (fb->info.var.bits_per_pixel == 32)
1036                 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1037             else {
1038                 ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1039             }
1040             if (id == S9000_ID_A1439A)
1041                 ngleClearOverlayPlanes(fb, 0xff, 0);
1042             break;
1043          case S9000_ID_ARTIST:
1044          case CRT_ID_VISUALIZE_EG:
1045             if (fb->info.var.bits_per_pixel == 32)
1046                 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1047             else {
1048                 ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1049             }
1050             break;
1051         }
1052         stifb_blank(0, (struct fb_info *)fb);   /* 0=enable screen */
1053
1054         SETUP_FB(fb);
1055 }
1056
1057 /* ------------ Interfaces to hardware functions ------------ */
1058
1059 static struct fb_ops stifb_ops = {
1060         .owner          = THIS_MODULE,
1061         .fb_setcolreg   = stifb_setcolreg,
1062         .fb_blank       = stifb_blank,
1063         .fb_fillrect    = cfb_fillrect,
1064         .fb_copyarea    = cfb_copyarea,
1065         .fb_imageblit   = cfb_imageblit,
1066 };
1067
1068
1069 /*
1070  *  Initialization
1071  */
1072
1073 int __init
1074 stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1075 {
1076         struct fb_fix_screeninfo *fix;
1077         struct fb_var_screeninfo *var;
1078         struct stifb_info *fb;
1079         struct fb_info *info;
1080         unsigned long sti_rom_address;
1081         char *dev_name;
1082         int bpp, xres, yres;
1083
1084         fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
1085         if (!fb) {
1086                 printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
1087                 return -ENODEV;
1088         }
1089         
1090         info = &fb->info;
1091
1092         /* set struct to a known state */
1093         fix = &info->fix;
1094         var = &info->var;
1095
1096         fb->sti = sti;
1097         /* store upper 32bits of the graphics id */
1098         fb->id = fb->sti->graphics_id[0];
1099
1100         /* only supported cards are allowed */
1101         switch (fb->id) {
1102         case CRT_ID_VISUALIZE_EG:
1103                 /* Visualize cards can run either in "double buffer" or
1104                   "standard" mode. Depending on the mode, the card reports
1105                   a different device name, e.g. "INTERNAL_EG_DX1024" in double
1106                   buffer mode and "INTERNAL_EG_X1024" in standard mode.
1107                   Since this driver only supports standard mode, we check
1108                   if the device name contains the string "DX" and tell the
1109                   user how to reconfigure the card. */
1110                 if (strstr(sti->outptr.dev_name, "DX")) {
1111                    printk(KERN_WARNING "WARNING: stifb framebuffer driver does not "
1112                         "support '%s' in double-buffer mode.\n"
1113                         KERN_WARNING "WARNING: Please disable the double-buffer mode "
1114                         "in IPL menu (the PARISC-BIOS).\n",
1115                         sti->outptr.dev_name);
1116                    goto out_err0;
1117                 }
1118                 /* fall though */
1119         case S9000_ID_ARTIST:
1120         case S9000_ID_HCRX:
1121         case S9000_ID_TIMBER:
1122         case S9000_ID_A1659A:
1123         case S9000_ID_A1439A:
1124                 break;
1125         default:
1126                 printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1127                         sti->outptr.dev_name, fb->id);
1128                 goto out_err0;
1129         }
1130         
1131         /* default to 8 bpp on most graphic chips */
1132         bpp = 8;
1133         xres = sti_onscreen_x(fb->sti);
1134         yres = sti_onscreen_y(fb->sti);
1135
1136         ngleGetDeviceRomData(fb);
1137
1138         /* get (virtual) io region base addr */
1139         fix->mmio_start = REGION_BASE(fb,2);
1140         fix->mmio_len   = 0x400000;
1141
1142         /* Reject any device not in the NGLE family */
1143         switch (fb->id) {
1144         case S9000_ID_A1659A:   /* CRX/A1659A */
1145                 break;
1146         case S9000_ID_ELM:      /* GRX, grayscale but else same as A1659A */
1147                 var->grayscale = 1;
1148                 fb->id = S9000_ID_A1659A;
1149                 break;
1150         case S9000_ID_TIMBER:   /* HP9000/710 Any (may be a grayscale device) */
1151                 dev_name = fb->sti->outptr.dev_name;
1152                 if (strstr(dev_name, "GRAYSCALE") || 
1153                     strstr(dev_name, "Grayscale") ||
1154                     strstr(dev_name, "grayscale"))
1155                         var->grayscale = 1;
1156                 break;
1157         case S9000_ID_TOMCAT:   /* Dual CRX, behaves else like a CRX */
1158                 /* FIXME: TomCat supports two heads:
1159                  * fb.iobase = REGION_BASE(fb_info,3);
1160                  * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx);
1161                  * for now we only support the left one ! */
1162                 xres = fb->ngle_rom.x_size_visible;
1163                 yres = fb->ngle_rom.y_size_visible;
1164                 fb->id = S9000_ID_A1659A;
1165                 break;
1166         case S9000_ID_A1439A:   /* CRX24/A1439A */
1167                 bpp = 32;
1168                 break;
1169         case S9000_ID_HCRX:     /* Hyperdrive/HCRX */
1170                 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1171                 if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1172                     (fb->sti->regions_phys[2] & 0xfc000000))
1173                         sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1174                 else
1175                         sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1176
1177                 fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1178                 if (IS_24_DEVICE(fb)) {
1179                         if (bpp_pref == 8 || bpp_pref == 32)
1180                                 bpp = bpp_pref;
1181                         else
1182                                 bpp = 32;
1183                 } else
1184                         bpp = 8;
1185                 READ_WORD(fb, REG_15);
1186                 SETUP_HW(fb);
1187                 break;
1188         case CRT_ID_VISUALIZE_EG:
1189         case S9000_ID_ARTIST:   /* Artist */
1190                 break;
1191         default: 
1192 #ifdef FALLBACK_TO_1BPP
1193                 printk(KERN_WARNING 
1194                         "stifb: Unsupported graphics card (id=0x%08x) "
1195                                 "- now trying 1bpp mode instead\n",
1196                         fb->id);
1197                 bpp = 1;        /* default to 1 bpp */
1198                 break;
1199 #else
1200                 printk(KERN_WARNING 
1201                         "stifb: Unsupported graphics card (id=0x%08x) "
1202                                 "- skipping.\n",
1203                         fb->id);
1204                 goto out_err0;
1205 #endif
1206         }
1207
1208
1209         /* get framebuffer physical and virtual base addr & len (64bit ready) */
1210         fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1211         fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1212
1213         fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1214         if (!fix->line_length)
1215                 fix->line_length = 2048; /* default */
1216         
1217         /* limit fbsize to max visible screen size */
1218         if (fix->smem_len > yres*fix->line_length)
1219                 fix->smem_len = yres*fix->line_length;
1220         
1221         fix->accel = FB_ACCEL_NONE;
1222
1223         switch (bpp) {
1224             case 1:
1225                 fix->type = FB_TYPE_PLANES;     /* well, sort of */
1226                 fix->visual = FB_VISUAL_MONO10;
1227                 var->red.length = var->green.length = var->blue.length = 1;
1228                 break;
1229             case 8:
1230                 fix->type = FB_TYPE_PACKED_PIXELS;
1231                 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1232                 var->red.length = var->green.length = var->blue.length = 8;
1233                 break;
1234             case 32:
1235                 fix->type = FB_TYPE_PACKED_PIXELS;
1236                 fix->visual = FB_VISUAL_DIRECTCOLOR;
1237                 var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1238                 var->blue.offset = 0;
1239                 var->green.offset = 8;
1240                 var->red.offset = 16;
1241                 var->transp.offset = 24;
1242                 break;
1243             default:
1244                 break;
1245         }
1246         
1247         var->xres = var->xres_virtual = xres;
1248         var->yres = var->yres_virtual = yres;
1249         var->bits_per_pixel = bpp;
1250
1251         strcpy(fix->id, "stifb");
1252         info->fbops = &stifb_ops;
1253         info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
1254         info->screen_size = fix->smem_len;
1255         info->flags = FBINFO_DEFAULT;
1256         info->pseudo_palette = &fb->pseudo_palette;
1257
1258         /* This has to been done !!! */
1259         fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
1260         stifb_init_display(fb);
1261
1262         if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1263                 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1264                                 fix->smem_start, fix->smem_start+fix->smem_len);
1265                 goto out_err1;
1266         }
1267                 
1268         if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1269                 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1270                                 fix->mmio_start, fix->mmio_start+fix->mmio_len);
1271                 goto out_err2;
1272         }
1273
1274         if (register_framebuffer(&fb->info) < 0)
1275                 goto out_err3;
1276
1277         sti->info = info; /* save for unregister_framebuffer() */
1278
1279         printk(KERN_INFO 
1280             "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1281                 fb->info.node, 
1282                 fix->id,
1283                 var->xres, 
1284                 var->yres,
1285                 var->bits_per_pixel,
1286                 sti->outptr.dev_name,
1287                 fb->id, 
1288                 fix->mmio_start);
1289
1290         return 0;
1291
1292
1293 out_err3:
1294         release_mem_region(fix->mmio_start, fix->mmio_len);
1295 out_err2:
1296         release_mem_region(fix->smem_start, fix->smem_len);
1297 out_err1:
1298         iounmap(info->screen_base);
1299         fb_dealloc_cmap(&info->cmap);
1300 out_err0:
1301         kfree(fb);
1302         return -ENXIO;
1303 }
1304
1305 static int stifb_disabled __initdata;
1306
1307 int __init
1308 stifb_setup(char *options);
1309
1310 int __init
1311 stifb_init(void)
1312 {
1313         struct sti_struct *sti;
1314         struct sti_struct *def_sti;
1315         int i;
1316         
1317 #ifndef MODULE
1318         char *option = NULL;
1319
1320         if (fb_get_options("stifb", &option))
1321                 return -ENODEV;
1322         stifb_setup(option);
1323 #endif
1324         if (stifb_disabled) {
1325                 printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1326                 return -ENXIO;
1327         }
1328         
1329         def_sti = sti_get_rom(0);
1330         if (def_sti) {
1331                 for (i = 1; i <= MAX_STI_ROMS; i++) {
1332                         sti = sti_get_rom(i);
1333                         if (!sti)
1334                                 break;
1335                         if (sti == def_sti) {
1336                                 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1337                                 break;
1338                         }
1339                 }
1340         }
1341
1342         for (i = 1; i <= MAX_STI_ROMS; i++) {
1343                 sti = sti_get_rom(i);
1344                 if (!sti)
1345                         break;
1346                 if (sti == def_sti)
1347                         continue;
1348                 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1349         }
1350         return 0;
1351 }
1352
1353 /*
1354  *  Cleanup
1355  */
1356
1357 static void __exit
1358 stifb_cleanup(void)
1359 {
1360         struct sti_struct *sti;
1361         int i;
1362         
1363         for (i = 1; i <= MAX_STI_ROMS; i++) {
1364                 sti = sti_get_rom(i);
1365                 if (!sti)
1366                         break;
1367                 if (sti->info) {
1368                         struct fb_info *info = sti->info;
1369                         unregister_framebuffer(sti->info);
1370                         release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1371                         release_mem_region(info->fix.smem_start, info->fix.smem_len);
1372                                 if (info->screen_base)
1373                                         iounmap(info->screen_base);
1374                         fb_dealloc_cmap(&info->cmap);
1375                         kfree(info); 
1376                 }
1377                 sti->info = NULL;
1378         }
1379 }
1380
1381 int __init
1382 stifb_setup(char *options)
1383 {
1384         int i;
1385         
1386         if (!options || !*options)
1387                 return 1;
1388         
1389         if (strncmp(options, "off", 3) == 0) {
1390                 stifb_disabled = 1;
1391                 options += 3;
1392         }
1393
1394         if (strncmp(options, "bpp", 3) == 0) {
1395                 options += 3;
1396                 for (i = 0; i < MAX_STI_ROMS; i++) {
1397                         if (*options++ != ':')
1398                                 break;
1399                         stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1400                 }
1401         }
1402         return 1;
1403 }
1404
1405 __setup("stifb=", stifb_setup);
1406
1407 module_init(stifb_init);
1408 module_exit(stifb_cleanup);
1409
1410 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1411 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1412 MODULE_LICENSE("GPL v2");