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