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