ACPI: thinkpad-acpi: improve dock subdriver initialization
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / video / stifb.c
blob6074ae90b64c04cfab3aa5bb1541d95dd5939cba
1 /*
2 * linux/drivers/video/stifb.c -
3 * Low level Frame buffer driver for HP workstations with
4 * STI (standard text interface) video firmware.
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.
18 * The following graphics display devices (NGLE family) are supported by this driver:
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)
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.
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)
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
54 #undef DEBUG_STIFB_REGS /* debug sti register accesses */
57 #include <linux/module.h>
58 #include <linux/kernel.h>
59 #include <linux/errno.h>
60 #include <linux/string.h>
61 #include <linux/mm.h>
62 #include <linux/slab.h>
63 #include <linux/delay.h>
64 #include <linux/fb.h>
65 #include <linux/init.h>
66 #include <linux/ioport.h>
67 #include <linux/pci.h>
69 #include <asm/grfioctl.h> /* for HP-UX compatibility */
70 #include <asm/uaccess.h>
72 #include "sticore.h"
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])
78 #define NGLEDEVDEPROM_CRT_REGION 1
80 #define NR_PALETTE 256
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;
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;
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];
114 static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
116 /* ------------------- chipset specific functions -------------------------- */
118 /* offsets to graphic-chip internal registers */
120 #define REG_1 0x000118
121 #define REG_2 0x000480
122 #define REG_3 0x0004a0
123 #define REG_4 0x000600
124 #define REG_6 0x000800
125 #define REG_8 0x000820
126 #define REG_9 0x000a04
127 #define REG_10 0x018000
128 #define REG_11 0x018004
129 #define REG_12 0x01800c
130 #define REG_13 0x018018
131 #define REG_14 0x01801c
132 #define REG_15 0x200000
133 #define REG_15b0 0x200000
134 #define REG_16b1 0x200005
135 #define REG_16b3 0x200007
136 #define REG_21 0x200218
137 #define REG_22 0x0005a0
138 #define REG_23 0x0005c0
139 #define REG_26 0x200118
140 #define REG_27 0x200308
141 #define REG_32 0x21003c
142 #define REG_33 0x210040
143 #define REG_34 0x200008
144 #define REG_35 0x018010
145 #define REG_38 0x210020
146 #define REG_39 0x210120
147 #define REG_40 0x210130
148 #define REG_42 0x210028
149 #define REG_43 0x21002c
150 #define REG_44 0x210030
151 #define REG_45 0x210034
153 #define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg))
154 #define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg))
157 #ifndef DEBUG_STIFB_REGS
158 # define DEBUG_OFF()
159 # define DEBUG_ON()
160 # define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
161 # define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
162 #else
163 static int debug_on = 1;
164 # define DEBUG_OFF() debug_on=0
165 # define DEBUG_ON() debug_on=1
166 # define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
167 printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
168 __FUNCTION__, reg, value, READ_BYTE(fb,reg)); \
169 gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
170 # define WRITE_WORD(value,fb,reg) do { if (debug_on) \
171 printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
172 __FUNCTION__, reg, value, READ_WORD(fb,reg)); \
173 gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
174 #endif /* DEBUG_STIFB_REGS */
177 #define ENABLE 1 /* for enabling/disabling screen */
178 #define DISABLE 0
180 #define NGLE_LOCK(fb_info) do { } while (0)
181 #define NGLE_UNLOCK(fb_info) do { } while (0)
183 static void
184 SETUP_HW(struct stifb_info *fb)
186 char stat;
188 do {
189 stat = READ_BYTE(fb, REG_15b0);
190 if (!stat)
191 stat = READ_BYTE(fb, REG_15b0);
192 } while (stat);
196 static void
197 SETUP_FB(struct stifb_info *fb)
199 unsigned int reg10_value = 0;
201 SETUP_HW(fb);
202 switch (fb->id)
204 case CRT_ID_VISUALIZE_EG:
205 case S9000_ID_ARTIST:
206 case S9000_ID_A1659A:
207 reg10_value = 0x13601000;
208 break;
209 case S9000_ID_A1439A:
210 if (fb->info.var.bits_per_pixel == 32)
211 reg10_value = 0xBBA0A000;
212 else
213 reg10_value = 0x13601000;
214 break;
215 case S9000_ID_HCRX:
216 if (fb->info.var.bits_per_pixel == 32)
217 reg10_value = 0xBBA0A000;
218 else
219 reg10_value = 0x13602000;
220 break;
221 case S9000_ID_TIMBER:
222 case CRX24_OVERLAY_PLANES:
223 reg10_value = 0x13602000;
224 break;
226 if (reg10_value)
227 WRITE_WORD(reg10_value, fb, REG_10);
228 WRITE_WORD(0x83000300, fb, REG_14);
229 SETUP_HW(fb);
230 WRITE_BYTE(1, fb, REG_16b1);
233 static void
234 START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
236 SETUP_HW(fb);
237 WRITE_WORD(0xBBE0F000, fb, REG_10);
238 WRITE_WORD(0x03000300, fb, REG_14);
239 WRITE_WORD(~0, fb, REG_13);
242 static void
243 WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
245 SETUP_HW(fb);
246 WRITE_WORD(((0x100+index)<<2), fb, REG_3);
247 WRITE_WORD(color, fb, REG_4);
250 static void
251 FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
253 WRITE_WORD(0x400, fb, REG_2);
254 if (fb->info.var.bits_per_pixel == 32) {
255 WRITE_WORD(0x83000100, fb, REG_1);
256 } else {
257 if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
258 WRITE_WORD(0x80000100, fb, REG_26);
259 else
260 WRITE_WORD(0x80000100, fb, REG_1);
262 SETUP_FB(fb);
265 static void
266 SETUP_RAMDAC(struct stifb_info *fb)
268 SETUP_HW(fb);
269 WRITE_WORD(0x04000000, fb, 0x1020);
270 WRITE_WORD(0xff000000, fb, 0x1028);
273 static void
274 CRX24_SETUP_RAMDAC(struct stifb_info *fb)
276 SETUP_HW(fb);
277 WRITE_WORD(0x04000000, fb, 0x1000);
278 WRITE_WORD(0x02000000, fb, 0x1004);
279 WRITE_WORD(0xff000000, fb, 0x1008);
280 WRITE_WORD(0x05000000, fb, 0x1000);
281 WRITE_WORD(0x02000000, fb, 0x1004);
282 WRITE_WORD(0x03000000, fb, 0x1008);
285 #if 0
286 static void
287 HCRX_SETUP_RAMDAC(struct stifb_info *fb)
289 WRITE_WORD(0xffffffff, fb, REG_32);
291 #endif
293 static void
294 CRX24_SET_OVLY_MASK(struct stifb_info *fb)
296 SETUP_HW(fb);
297 WRITE_WORD(0x13a02000, fb, REG_11);
298 WRITE_WORD(0x03000300, fb, REG_14);
299 WRITE_WORD(0x000017f0, fb, REG_3);
300 WRITE_WORD(0xffffffff, fb, REG_13);
301 WRITE_WORD(0xffffffff, fb, REG_22);
302 WRITE_WORD(0x00000000, fb, REG_23);
305 static void
306 ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
308 unsigned int value = enable ? 0x43000000 : 0x03000000;
309 SETUP_HW(fb);
310 WRITE_WORD(0x06000000, fb, 0x1030);
311 WRITE_WORD(value, fb, 0x1038);
314 static void
315 CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
317 unsigned int value = enable ? 0x10000000 : 0x30000000;
318 SETUP_HW(fb);
319 WRITE_WORD(0x01000000, fb, 0x1000);
320 WRITE_WORD(0x02000000, fb, 0x1004);
321 WRITE_WORD(value, fb, 0x1008);
324 static void
325 ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
327 u32 DregsMiscVideo = REG_21;
328 u32 DregsMiscCtl = REG_27;
330 SETUP_HW(fb);
331 if (enable) {
332 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
333 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl);
334 } else {
335 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
336 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl);
340 #define GET_ROMTABLE_INDEX(fb) \
341 (READ_BYTE(fb, REG_16b3) - 1)
343 #define HYPER_CONFIG_PLANES_24 0x00000100
345 #define IS_24_DEVICE(fb) \
346 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
348 #define IS_888_DEVICE(fb) \
349 (!(IS_24_DEVICE(fb)))
351 #define GET_FIFO_SLOTS(fb, cnt, numslots) \
352 { while (cnt < numslots) \
353 cnt = READ_WORD(fb, REG_34); \
354 cnt -= numslots; \
357 #define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
358 #define Otc04 2 /* Pixels in each longword transfer (4) */
359 #define Otc32 5 /* Pixels in each longword transfer (32) */
360 #define Ots08 3 /* Each pixel is size (8)d transfer (1) */
361 #define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */
362 #define AddrLong 5 /* FB address is Long aligned (pixel) */
363 #define BINovly 0x2 /* 8 bit overlay */
364 #define BINapp0I 0x0 /* Application Buffer 0, Indexed */
365 #define BINapp1I 0x1 /* Application Buffer 1, Indexed */
366 #define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */
367 #define BINattr 0xd /* Attribute Bitmap */
368 #define RopSrc 0x3
369 #define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */
370 #define BitmapExtent32 5 /* Each write hits (32) bits in depth */
371 #define DataDynamic 0 /* Data register reloaded by direct access */
372 #define MaskDynamic 1 /* Mask register reloaded by direct access */
373 #define MaskOtc 0 /* Mask contains Object Count valid bits */
375 #define MaskAddrOffset(offset) (offset)
376 #define StaticReg(en) (en)
377 #define BGx(en) (en)
378 #define FGx(en) (en)
380 #define BAJustPoint(offset) (offset)
381 #define BAIndexBase(base) (base)
382 #define BA(F,C,S,A,J,B,I) \
383 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
385 #define IBOvals(R,M,X,S,D,L,B,F) \
386 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
388 #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
389 WRITE_WORD(val, fb, REG_14)
391 #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
392 WRITE_WORD(val, fb, REG_11)
394 #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
395 WRITE_WORD(val, fb, REG_12)
397 #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
398 WRITE_WORD(plnmsk32, fb, REG_13)
400 #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
401 WRITE_WORD(fg32, fb, REG_35)
403 #define NGLE_SET_TRANSFERDATA(fb, val) \
404 WRITE_WORD(val, fb, REG_8)
406 #define NGLE_SET_DSTXY(fb, val) \
407 WRITE_WORD(val, fb, REG_6)
409 #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
410 (u32) (fbaddrbase) + \
411 ( (unsigned int) ( (y) << 13 ) | \
412 (unsigned int) ( (x) << 2 ) ) \
415 #define NGLE_BINC_SET_DSTADDR(fb, addr) \
416 WRITE_WORD(addr, fb, REG_3)
418 #define NGLE_BINC_SET_SRCADDR(fb, addr) \
419 WRITE_WORD(addr, fb, REG_2)
421 #define NGLE_BINC_SET_DSTMASK(fb, mask) \
422 WRITE_WORD(mask, fb, REG_22)
424 #define NGLE_BINC_WRITE32(fb, data32) \
425 WRITE_WORD(data32, fb, REG_23)
427 #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
428 WRITE_WORD((cmapBltCtlData32), fb, REG_38)
430 #define SET_LENXY_START_RECFILL(fb, lenxy) \
431 WRITE_WORD(lenxy, fb, REG_9)
433 static void
434 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
436 u32 DregsHypMiscVideo = REG_33;
437 unsigned int value;
438 SETUP_HW(fb);
439 value = READ_WORD(fb, DregsHypMiscVideo);
440 if (enable)
441 value |= 0x0A000000;
442 else
443 value &= ~0x0A000000;
444 WRITE_WORD(value, fb, DregsHypMiscVideo);
448 /* BufferNumbers used by SETUP_ATTR_ACCESS() */
449 #define BUFF0_CMAP0 0x00001e02
450 #define BUFF1_CMAP0 0x02001e02
451 #define BUFF1_CMAP3 0x0c001e02
452 #define ARTIST_CMAP0 0x00000102
453 #define HYPER_CMAP8 0x00000100
454 #define HYPER_CMAP24 0x00000800
456 static void
457 SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
459 SETUP_HW(fb);
460 WRITE_WORD(0x2EA0D000, fb, REG_11);
461 WRITE_WORD(0x23000302, fb, REG_14);
462 WRITE_WORD(BufferNumber, fb, REG_12);
463 WRITE_WORD(0xffffffff, fb, REG_8);
466 static void
467 SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
469 /* REG_6 seems to have special values when run on a
470 RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
471 INTERNAL_EG_X1024). The values are:
472 0x2f0: internal (LCD) & external display enabled
473 0x2a0: external display only
474 0x000: zero on standard artist graphic cards
476 WRITE_WORD(0x00000000, fb, REG_6);
477 WRITE_WORD((width<<16) | height, fb, REG_9);
478 WRITE_WORD(0x05000000, fb, REG_6);
479 WRITE_WORD(0x00040001, fb, REG_9);
482 static void
483 FINISH_ATTR_ACCESS(struct stifb_info *fb)
485 SETUP_HW(fb);
486 WRITE_WORD(0x00000000, fb, REG_12);
489 static void
490 elkSetupPlanes(struct stifb_info *fb)
492 SETUP_RAMDAC(fb);
493 SETUP_FB(fb);
496 static void
497 ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
499 SETUP_ATTR_ACCESS(fb, BufferNumber);
500 SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
501 FINISH_ATTR_ACCESS(fb);
502 SETUP_FB(fb);
506 static void
507 rattlerSetupPlanes(struct stifb_info *fb)
509 CRX24_SETUP_RAMDAC(fb);
511 /* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */
512 WRITE_WORD(0x83000300, fb, REG_14);
513 SETUP_HW(fb);
514 WRITE_BYTE(1, fb, REG_16b1);
516 fb_memset((void*)fb->info.fix.smem_start, 0xff,
517 fb->info.var.yres*fb->info.fix.line_length);
519 CRX24_SET_OVLY_MASK(fb);
520 SETUP_FB(fb);
524 #define HYPER_CMAP_TYPE 0
525 #define NGLE_CMAP_INDEXED0_TYPE 0
526 #define NGLE_CMAP_OVERLAY_TYPE 3
528 /* typedef of LUT (Colormap) BLT Control Register */
529 typedef union /* Note assumption that fields are packed left-to-right */
530 { u32 all;
531 struct
533 unsigned enable : 1;
534 unsigned waitBlank : 1;
535 unsigned reserved1 : 4;
536 unsigned lutOffset : 10; /* Within destination LUT */
537 unsigned lutType : 2; /* Cursor, image, overlay */
538 unsigned reserved2 : 4;
539 unsigned length : 10;
540 } fields;
541 } NgleLutBltCtl;
544 #if 0
545 static NgleLutBltCtl
546 setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
548 NgleLutBltCtl lutBltCtl;
550 /* set enable, zero reserved fields */
551 lutBltCtl.all = 0x80000000;
552 lutBltCtl.fields.length = length;
554 switch (fb->id)
556 case S9000_ID_A1439A: /* CRX24 */
557 if (fb->var.bits_per_pixel == 8) {
558 lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
559 lutBltCtl.fields.lutOffset = 0;
560 } else {
561 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
562 lutBltCtl.fields.lutOffset = 0 * 256;
564 break;
566 case S9000_ID_ARTIST:
567 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
568 lutBltCtl.fields.lutOffset = 0 * 256;
569 break;
571 default:
572 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
573 lutBltCtl.fields.lutOffset = 0;
574 break;
577 /* Offset points to start of LUT. Adjust for within LUT */
578 lutBltCtl.fields.lutOffset += offsetWithinLut;
580 return lutBltCtl;
582 #endif
584 static NgleLutBltCtl
585 setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
587 NgleLutBltCtl lutBltCtl;
589 /* set enable, zero reserved fields */
590 lutBltCtl.all = 0x80000000;
592 lutBltCtl.fields.length = length;
593 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
595 /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
596 if (fb->info.var.bits_per_pixel == 8)
597 lutBltCtl.fields.lutOffset = 2 * 256;
598 else
599 lutBltCtl.fields.lutOffset = 0 * 256;
601 /* Offset points to start of LUT. Adjust for within LUT */
602 lutBltCtl.fields.lutOffset += offsetWithinLut;
604 return lutBltCtl;
608 static void hyperUndoITE(struct stifb_info *fb)
610 int nFreeFifoSlots = 0;
611 u32 fbAddr;
613 NGLE_LOCK(fb);
615 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
616 WRITE_WORD(0xffffffff, fb, REG_32);
618 /* Write overlay transparency mask so only entry 255 is transparent */
620 /* Hardware setup for full-depth write to "magic" location */
621 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
622 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
623 BA(IndexedDcd, Otc04, Ots08, AddrLong,
624 BAJustPoint(0), BINovly, BAIndexBase(0)));
625 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
626 IBOvals(RopSrc, MaskAddrOffset(0),
627 BitmapExtent08, StaticReg(0),
628 DataDynamic, MaskOtc, BGx(0), FGx(0)));
630 /* Now prepare to write to the "magic" location */
631 fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
632 NGLE_BINC_SET_DSTADDR(fb, fbAddr);
633 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
634 NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
636 /* Finally, write a zero to clear the mask */
637 NGLE_BINC_WRITE32(fb, 0);
639 NGLE_UNLOCK(fb);
642 static void
643 ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
645 /* FIXME! */
648 static void
649 ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
651 /* FIXME! */
654 static void
655 ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
657 int nFreeFifoSlots = 0;
658 u32 packed_dst;
659 u32 packed_len;
661 NGLE_LOCK(fb);
663 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
664 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
665 BA(IndexedDcd, Otc32, OtsIndirect,
666 AddrLong, BAJustPoint(0),
667 BINattr, BAIndexBase(0)));
668 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
669 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
671 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
672 IBOvals(RopSrc, MaskAddrOffset(0),
673 BitmapExtent08, StaticReg(1),
674 DataDynamic, MaskOtc,
675 BGx(0), FGx(0)));
676 packed_dst = 0;
677 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
678 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
679 NGLE_SET_DSTXY(fb, packed_dst);
680 SET_LENXY_START_RECFILL(fb, packed_len);
683 * In order to work around an ELK hardware problem (Buffy doesn't
684 * always flush it's buffers when writing to the attribute
685 * planes), at least 4 pixels must be written to the attribute
686 * planes starting at (X == 1280) and (Y != to the last Y written
687 * by BIF):
690 if (fb->id == S9000_ID_A1659A) { /* ELK_DEVICE_ID */
691 /* It's safe to use scanline zero: */
692 packed_dst = (1280 << 16);
693 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
694 NGLE_SET_DSTXY(fb, packed_dst);
695 packed_len = (4 << 16) | 1;
696 SET_LENXY_START_RECFILL(fb, packed_len);
697 } /* ELK Hardware Kludge */
699 /**** Finally, set the Control Plane Register back to zero: ****/
700 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
701 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
703 NGLE_UNLOCK(fb);
706 static void
707 ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
709 int nFreeFifoSlots = 0;
710 u32 packed_dst;
711 u32 packed_len;
713 NGLE_LOCK(fb);
715 /* Hardware setup */
716 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
717 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
718 BA(IndexedDcd, Otc04, Ots08, AddrLong,
719 BAJustPoint(0), BINovly, BAIndexBase(0)));
721 NGLE_SET_TRANSFERDATA(fb, 0xffffffff); /* Write foreground color */
723 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
724 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
726 packed_dst = 0;
727 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
728 NGLE_SET_DSTXY(fb, packed_dst);
730 /* Write zeroes to overlay planes */
731 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
732 IBOvals(RopSrc, MaskAddrOffset(0),
733 BitmapExtent08, StaticReg(0),
734 DataDynamic, MaskOtc, BGx(0), FGx(0)));
736 SET_LENXY_START_RECFILL(fb, packed_len);
738 NGLE_UNLOCK(fb);
741 static void
742 hyperResetPlanes(struct stifb_info *fb, int enable)
744 unsigned int controlPlaneReg;
746 NGLE_LOCK(fb);
748 if (IS_24_DEVICE(fb))
749 if (fb->info.var.bits_per_pixel == 32)
750 controlPlaneReg = 0x04000F00;
751 else
752 controlPlaneReg = 0x00000F00; /* 0x00000800 should be enought, but lets clear all 4 bits */
753 else
754 controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
756 switch (enable) {
757 case ENABLE:
758 /* clear screen */
759 if (IS_24_DEVICE(fb))
760 ngleDepth24_ClearImagePlanes(fb);
761 else
762 ngleDepth8_ClearImagePlanes(fb);
764 /* Paint attribute planes for default case.
765 * On Hyperdrive, this means all windows using overlay cmap 0. */
766 ngleResetAttrPlanes(fb, controlPlaneReg);
768 /* clear overlay planes */
769 ngleClearOverlayPlanes(fb, 0xff, 255);
771 /**************************************************
772 ** Also need to counteract ITE settings
773 **************************************************/
774 hyperUndoITE(fb);
775 break;
777 case DISABLE:
778 /* clear screen */
779 if (IS_24_DEVICE(fb))
780 ngleDepth24_ClearImagePlanes(fb);
781 else
782 ngleDepth8_ClearImagePlanes(fb);
783 ngleResetAttrPlanes(fb, controlPlaneReg);
784 ngleClearOverlayPlanes(fb, 0xff, 0);
785 break;
787 case -1: /* RESET */
788 hyperUndoITE(fb);
789 ngleResetAttrPlanes(fb, controlPlaneReg);
790 break;
793 NGLE_UNLOCK(fb);
796 /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
798 static void
799 ngleGetDeviceRomData(struct stifb_info *fb)
801 #if 0
802 XXX: FIXME: !!!
803 int *pBytePerLongDevDepData;/* data byte == LSB */
804 int *pRomTable;
805 NgleDevRomData *pPackedDevRomData;
806 int sizePackedDevRomData = sizeof(*pPackedDevRomData);
807 char *pCard8;
808 int i;
809 char *mapOrigin = NULL;
811 int romTableIdx;
813 pPackedDevRomData = fb->ngle_rom;
815 SETUP_HW(fb);
816 if (fb->id == S9000_ID_ARTIST) {
817 pPackedDevRomData->cursor_pipeline_delay = 4;
818 pPackedDevRomData->video_interleaves = 4;
819 } else {
820 /* Get pointer to unpacked byte/long data in ROM */
821 pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
823 /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
824 if (fb->id == S9000_ID_TOMCAT)
826 /* jump to the correct ROM table */
827 GET_ROMTABLE_INDEX(romTableIdx);
828 while (romTableIdx > 0)
830 pCard8 = (Card8 *) pPackedDevRomData;
831 pRomTable = pBytePerLongDevDepData;
832 /* Pack every fourth byte from ROM into structure */
833 for (i = 0; i < sizePackedDevRomData; i++)
835 *pCard8++ = (Card8) (*pRomTable++);
838 pBytePerLongDevDepData = (Card32 *)
839 ((Card8 *) pBytePerLongDevDepData +
840 pPackedDevRomData->sizeof_ngle_data);
842 romTableIdx--;
846 pCard8 = (Card8 *) pPackedDevRomData;
848 /* Pack every fourth byte from ROM into structure */
849 for (i = 0; i < sizePackedDevRomData; i++)
851 *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
855 SETUP_FB(fb);
856 #endif
860 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
861 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8
862 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10
863 #define HYPERBOWL_MODE2_8_24 15
865 /* HCRX specific boot-time initialization */
866 static void __init
867 SETUP_HCRX(struct stifb_info *fb)
869 int hyperbowl;
870 int nFreeFifoSlots = 0;
872 if (fb->id != S9000_ID_HCRX)
873 return;
875 /* Initialize Hyperbowl registers */
876 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
878 if (IS_24_DEVICE(fb)) {
879 hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
880 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
881 HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
883 /* First write to Hyperbowl must happen twice (bug) */
884 WRITE_WORD(hyperbowl, fb, REG_40);
885 WRITE_WORD(hyperbowl, fb, REG_40);
887 WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
889 WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
890 WRITE_WORD(0x404c4048, fb, REG_43);
891 WRITE_WORD(0x034c0348, fb, REG_44);
892 WRITE_WORD(0x444c4448, fb, REG_45);
893 } else {
894 hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
896 /* First write to Hyperbowl must happen twice (bug) */
897 WRITE_WORD(hyperbowl, fb, REG_40);
898 WRITE_WORD(hyperbowl, fb, REG_40);
900 WRITE_WORD(0x00000000, fb, REG_42);
901 WRITE_WORD(0x00000000, fb, REG_43);
902 WRITE_WORD(0x00000000, fb, REG_44);
903 WRITE_WORD(0x444c4048, fb, REG_45);
908 /* ------------------- driver specific functions --------------------------- */
910 static int
911 stifb_setcolreg(u_int regno, u_int red, u_int green,
912 u_int blue, u_int transp, struct fb_info *info)
914 struct stifb_info *fb = (struct stifb_info *) info;
915 u32 color;
917 if (regno >= NR_PALETTE)
918 return 1;
920 red >>= 8;
921 green >>= 8;
922 blue >>= 8;
924 DEBUG_OFF();
926 START_IMAGE_COLORMAP_ACCESS(fb);
928 if (unlikely(fb->info.var.grayscale)) {
929 /* gray = 0.30*R + 0.59*G + 0.11*B */
930 color = ((red * 77) +
931 (green * 151) +
932 (blue * 28)) >> 8;
933 } else {
934 color = ((red << 16) |
935 (green << 8) |
936 (blue));
939 if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
940 struct fb_var_screeninfo *var = &fb->info.var;
941 if (regno < 16)
942 ((u32 *)fb->info.pseudo_palette)[regno] =
943 regno << var->red.offset |
944 regno << var->green.offset |
945 regno << var->blue.offset;
948 WRITE_IMAGE_COLOR(fb, regno, color);
950 if (fb->id == S9000_ID_HCRX) {
951 NgleLutBltCtl lutBltCtl;
953 lutBltCtl = setHyperLutBltCtl(fb,
954 0, /* Offset w/i LUT */
955 256); /* Load entire LUT */
956 NGLE_BINC_SET_SRCADDR(fb,
957 NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
958 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
959 START_COLORMAPLOAD(fb, lutBltCtl.all);
960 SETUP_FB(fb);
961 } else {
962 /* cleanup colormap hardware */
963 FINISH_IMAGE_COLORMAP_ACCESS(fb);
966 DEBUG_ON();
968 return 0;
971 static int
972 stifb_blank(int blank_mode, struct fb_info *info)
974 struct stifb_info *fb = (struct stifb_info *) info;
975 int enable = (blank_mode == 0) ? ENABLE : DISABLE;
977 switch (fb->id) {
978 case S9000_ID_A1439A:
979 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
980 break;
981 case CRT_ID_VISUALIZE_EG:
982 case S9000_ID_ARTIST:
983 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
984 break;
985 case S9000_ID_HCRX:
986 HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
987 break;
988 case S9000_ID_A1659A: /* fall through */
989 case S9000_ID_TIMBER:
990 case CRX24_OVERLAY_PLANES:
991 default:
992 ENABLE_DISABLE_DISPLAY(fb, enable);
993 break;
996 SETUP_FB(fb);
997 return 0;
1000 static void __init
1001 stifb_init_display(struct stifb_info *fb)
1003 int id = fb->id;
1005 SETUP_FB(fb);
1007 /* HCRX specific initialization */
1008 SETUP_HCRX(fb);
1011 if (id == S9000_ID_HCRX)
1012 hyperInitSprite(fb);
1013 else
1014 ngleInitSprite(fb);
1017 /* Initialize the image planes. */
1018 switch (id) {
1019 case S9000_ID_HCRX:
1020 hyperResetPlanes(fb, ENABLE);
1021 break;
1022 case S9000_ID_A1439A:
1023 rattlerSetupPlanes(fb);
1024 break;
1025 case S9000_ID_A1659A:
1026 case S9000_ID_ARTIST:
1027 case CRT_ID_VISUALIZE_EG:
1028 elkSetupPlanes(fb);
1029 break;
1032 /* Clear attribute planes on non HCRX devices. */
1033 switch (id) {
1034 case S9000_ID_A1659A:
1035 case S9000_ID_A1439A:
1036 if (fb->info.var.bits_per_pixel == 32)
1037 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1038 else {
1039 ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1041 if (id == S9000_ID_A1439A)
1042 ngleClearOverlayPlanes(fb, 0xff, 0);
1043 break;
1044 case S9000_ID_ARTIST:
1045 case CRT_ID_VISUALIZE_EG:
1046 if (fb->info.var.bits_per_pixel == 32)
1047 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1048 else {
1049 ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1051 break;
1053 stifb_blank(0, (struct fb_info *)fb); /* 0=enable screen */
1055 SETUP_FB(fb);
1058 /* ------------ Interfaces to hardware functions ------------ */
1060 static struct fb_ops stifb_ops = {
1061 .owner = THIS_MODULE,
1062 .fb_setcolreg = stifb_setcolreg,
1063 .fb_blank = stifb_blank,
1064 .fb_fillrect = cfb_fillrect,
1065 .fb_copyarea = cfb_copyarea,
1066 .fb_imageblit = cfb_imageblit,
1071 * Initialization
1074 int __init
1075 stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1077 struct fb_fix_screeninfo *fix;
1078 struct fb_var_screeninfo *var;
1079 struct stifb_info *fb;
1080 struct fb_info *info;
1081 unsigned long sti_rom_address;
1082 char *dev_name;
1083 int bpp, xres, yres;
1085 fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
1086 if (!fb) {
1087 printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
1088 return -ENODEV;
1091 info = &fb->info;
1093 /* set struct to a known state */
1094 fix = &info->fix;
1095 var = &info->var;
1097 fb->sti = sti;
1098 /* store upper 32bits of the graphics id */
1099 fb->id = fb->sti->graphics_id[0];
1101 /* only supported cards are allowed */
1102 switch (fb->id) {
1103 case CRT_ID_VISUALIZE_EG:
1104 /* Visualize cards can run either in "double buffer" or
1105 "standard" mode. Depending on the mode, the card reports
1106 a different device name, e.g. "INTERNAL_EG_DX1024" in double
1107 buffer mode and "INTERNAL_EG_X1024" in standard mode.
1108 Since this driver only supports standard mode, we check
1109 if the device name contains the string "DX" and tell the
1110 user how to reconfigure the card. */
1111 if (strstr(sti->outptr.dev_name, "DX")) {
1112 printk(KERN_WARNING "WARNING: stifb framebuffer driver does not "
1113 "support '%s' in double-buffer mode.\n"
1114 KERN_WARNING "WARNING: Please disable the double-buffer mode "
1115 "in IPL menu (the PARISC-BIOS).\n",
1116 sti->outptr.dev_name);
1117 goto out_err0;
1119 /* fall though */
1120 case S9000_ID_ARTIST:
1121 case S9000_ID_HCRX:
1122 case S9000_ID_TIMBER:
1123 case S9000_ID_A1659A:
1124 case S9000_ID_A1439A:
1125 break;
1126 default:
1127 printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1128 sti->outptr.dev_name, fb->id);
1129 goto out_err0;
1132 /* default to 8 bpp on most graphic chips */
1133 bpp = 8;
1134 xres = sti_onscreen_x(fb->sti);
1135 yres = sti_onscreen_y(fb->sti);
1137 ngleGetDeviceRomData(fb);
1139 /* get (virtual) io region base addr */
1140 fix->mmio_start = REGION_BASE(fb,2);
1141 fix->mmio_len = 0x400000;
1143 /* Reject any device not in the NGLE family */
1144 switch (fb->id) {
1145 case S9000_ID_A1659A: /* CRX/A1659A */
1146 break;
1147 case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */
1148 var->grayscale = 1;
1149 fb->id = S9000_ID_A1659A;
1150 break;
1151 case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */
1152 dev_name = fb->sti->outptr.dev_name;
1153 if (strstr(dev_name, "GRAYSCALE") ||
1154 strstr(dev_name, "Grayscale") ||
1155 strstr(dev_name, "grayscale"))
1156 var->grayscale = 1;
1157 break;
1158 case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */
1159 /* FIXME: TomCat supports two heads:
1160 * fb.iobase = REGION_BASE(fb_info,3);
1161 * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx);
1162 * for now we only support the left one ! */
1163 xres = fb->ngle_rom.x_size_visible;
1164 yres = fb->ngle_rom.y_size_visible;
1165 fb->id = S9000_ID_A1659A;
1166 break;
1167 case S9000_ID_A1439A: /* CRX24/A1439A */
1168 bpp = 32;
1169 break;
1170 case S9000_ID_HCRX: /* Hyperdrive/HCRX */
1171 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1172 if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1173 (fb->sti->regions_phys[2] & 0xfc000000))
1174 sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1175 else
1176 sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1178 fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1179 if (IS_24_DEVICE(fb)) {
1180 if (bpp_pref == 8 || bpp_pref == 32)
1181 bpp = bpp_pref;
1182 else
1183 bpp = 32;
1184 } else
1185 bpp = 8;
1186 READ_WORD(fb, REG_15);
1187 SETUP_HW(fb);
1188 break;
1189 case CRT_ID_VISUALIZE_EG:
1190 case S9000_ID_ARTIST: /* Artist */
1191 break;
1192 default:
1193 #ifdef FALLBACK_TO_1BPP
1194 printk(KERN_WARNING
1195 "stifb: Unsupported graphics card (id=0x%08x) "
1196 "- now trying 1bpp mode instead\n",
1197 fb->id);
1198 bpp = 1; /* default to 1 bpp */
1199 break;
1200 #else
1201 printk(KERN_WARNING
1202 "stifb: Unsupported graphics card (id=0x%08x) "
1203 "- skipping.\n",
1204 fb->id);
1205 goto out_err0;
1206 #endif
1210 /* get framebuffer physical and virtual base addr & len (64bit ready) */
1211 fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1212 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1214 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1215 if (!fix->line_length)
1216 fix->line_length = 2048; /* default */
1218 /* limit fbsize to max visible screen size */
1219 if (fix->smem_len > yres*fix->line_length)
1220 fix->smem_len = yres*fix->line_length;
1222 fix->accel = FB_ACCEL_NONE;
1224 switch (bpp) {
1225 case 1:
1226 fix->type = FB_TYPE_PLANES; /* well, sort of */
1227 fix->visual = FB_VISUAL_MONO10;
1228 var->red.length = var->green.length = var->blue.length = 1;
1229 break;
1230 case 8:
1231 fix->type = FB_TYPE_PACKED_PIXELS;
1232 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1233 var->red.length = var->green.length = var->blue.length = 8;
1234 break;
1235 case 32:
1236 fix->type = FB_TYPE_PACKED_PIXELS;
1237 fix->visual = FB_VISUAL_DIRECTCOLOR;
1238 var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1239 var->blue.offset = 0;
1240 var->green.offset = 8;
1241 var->red.offset = 16;
1242 var->transp.offset = 24;
1243 break;
1244 default:
1245 break;
1248 var->xres = var->xres_virtual = xres;
1249 var->yres = var->yres_virtual = yres;
1250 var->bits_per_pixel = bpp;
1252 strcpy(fix->id, "stifb");
1253 info->fbops = &stifb_ops;
1254 info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
1255 info->screen_size = fix->smem_len;
1256 info->flags = FBINFO_DEFAULT;
1257 info->pseudo_palette = &fb->pseudo_palette;
1259 /* This has to been done !!! */
1260 fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
1261 stifb_init_display(fb);
1263 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1264 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1265 fix->smem_start, fix->smem_start+fix->smem_len);
1266 goto out_err1;
1269 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1270 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1271 fix->mmio_start, fix->mmio_start+fix->mmio_len);
1272 goto out_err2;
1275 if (register_framebuffer(&fb->info) < 0)
1276 goto out_err3;
1278 sti->info = info; /* save for unregister_framebuffer() */
1280 printk(KERN_INFO
1281 "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1282 fb->info.node,
1283 fix->id,
1284 var->xres,
1285 var->yres,
1286 var->bits_per_pixel,
1287 sti->outptr.dev_name,
1288 fb->id,
1289 fix->mmio_start);
1291 return 0;
1294 out_err3:
1295 release_mem_region(fix->mmio_start, fix->mmio_len);
1296 out_err2:
1297 release_mem_region(fix->smem_start, fix->smem_len);
1298 out_err1:
1299 iounmap(info->screen_base);
1300 fb_dealloc_cmap(&info->cmap);
1301 out_err0:
1302 kfree(fb);
1303 return -ENXIO;
1306 static int stifb_disabled __initdata;
1308 int __init
1309 stifb_setup(char *options);
1311 int __init
1312 stifb_init(void)
1314 struct sti_struct *sti;
1315 struct sti_struct *def_sti;
1316 int i;
1318 #ifndef MODULE
1319 char *option = NULL;
1321 if (fb_get_options("stifb", &option))
1322 return -ENODEV;
1323 stifb_setup(option);
1324 #endif
1325 if (stifb_disabled) {
1326 printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1327 return -ENXIO;
1330 def_sti = sti_get_rom(0);
1331 if (def_sti) {
1332 for (i = 1; i <= MAX_STI_ROMS; i++) {
1333 sti = sti_get_rom(i);
1334 if (!sti)
1335 break;
1336 if (sti == def_sti) {
1337 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1338 break;
1343 for (i = 1; i <= MAX_STI_ROMS; i++) {
1344 sti = sti_get_rom(i);
1345 if (!sti)
1346 break;
1347 if (sti == def_sti)
1348 continue;
1349 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1351 return 0;
1355 * Cleanup
1358 static void __exit
1359 stifb_cleanup(void)
1361 struct sti_struct *sti;
1362 int i;
1364 for (i = 1; i <= MAX_STI_ROMS; i++) {
1365 sti = sti_get_rom(i);
1366 if (!sti)
1367 break;
1368 if (sti->info) {
1369 struct fb_info *info = sti->info;
1370 unregister_framebuffer(sti->info);
1371 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1372 release_mem_region(info->fix.smem_start, info->fix.smem_len);
1373 if (info->screen_base)
1374 iounmap(info->screen_base);
1375 fb_dealloc_cmap(&info->cmap);
1376 kfree(info);
1378 sti->info = NULL;
1382 int __init
1383 stifb_setup(char *options)
1385 int i;
1387 if (!options || !*options)
1388 return 1;
1390 if (strncmp(options, "off", 3) == 0) {
1391 stifb_disabled = 1;
1392 options += 3;
1395 if (strncmp(options, "bpp", 3) == 0) {
1396 options += 3;
1397 for (i = 0; i < MAX_STI_ROMS; i++) {
1398 if (*options++ != ':')
1399 break;
1400 stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1403 return 1;
1406 __setup("stifb=", stifb_setup);
1408 module_init(stifb_init);
1409 module_exit(stifb_cleanup);
1411 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1412 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1413 MODULE_LICENSE("GPL v2");