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