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