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>
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
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>
62 #include <linux/slab.h>
63 #include <linux/delay.h>
65 #include <linux/init.h>
66 #include <linux/ioport.h>
69 #include <asm/grfioctl.h> /* for HP-UX compatibility */
70 #include <linux/uaccess.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
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
;
90 __s32 vtg_state_elements
;
96 __s16 sizeof_ngle_data
;
97 __s16 x_size_visible
; /* visible screen dim in pixels */
100 __s16 cursor_pipeline_delay
;
101 __s16 video_interleaves
;
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_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
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))
160 #ifndef DEBUG_STIFB_REGS
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))
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 */
180 #define ENABLE 1 /* for enabling/disabling screen */
183 #define NGLE_LOCK(fb_info) do { } while (0)
184 #define NGLE_UNLOCK(fb_info) do { } while (0)
187 SETUP_HW(struct stifb_info
*fb
)
192 stat
= READ_BYTE(fb
, REG_15b0
);
194 stat
= READ_BYTE(fb
, REG_15b0
);
200 SETUP_FB(struct stifb_info
*fb
)
202 unsigned int reg10_value
= 0;
207 case CRT_ID_VISUALIZE_EG
:
208 case S9000_ID_ARTIST
:
209 case S9000_ID_A1659A
:
210 reg10_value
= 0x13601000;
212 case S9000_ID_A1439A
:
213 if (fb
->info
.var
.bits_per_pixel
== 32)
214 reg10_value
= 0xBBA0A000;
216 reg10_value
= 0x13601000;
219 if (fb
->info
.var
.bits_per_pixel
== 32)
220 reg10_value
= 0xBBA0A000;
222 reg10_value
= 0x13602000;
224 case S9000_ID_TIMBER
:
225 case CRX24_OVERLAY_PLANES
:
226 reg10_value
= 0x13602000;
230 WRITE_WORD(reg10_value
, fb
, REG_10
);
231 WRITE_WORD(0x83000300, fb
, REG_14
);
233 WRITE_BYTE(1, fb
, REG_16b1
);
237 START_IMAGE_COLORMAP_ACCESS(struct stifb_info
*fb
)
240 WRITE_WORD(0xBBE0F000, fb
, REG_10
);
241 WRITE_WORD(0x03000300, fb
, REG_14
);
242 WRITE_WORD(~0, fb
, REG_13
);
246 WRITE_IMAGE_COLOR(struct stifb_info
*fb
, int index
, int color
)
249 WRITE_WORD(((0x100+index
)<<2), fb
, REG_3
);
250 WRITE_WORD(color
, fb
, REG_4
);
254 FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info
*fb
)
256 WRITE_WORD(0x400, fb
, REG_2
);
257 if (fb
->info
.var
.bits_per_pixel
== 32) {
258 WRITE_WORD(0x83000100, fb
, REG_1
);
260 if (fb
->id
== S9000_ID_ARTIST
|| fb
->id
== CRT_ID_VISUALIZE_EG
)
261 WRITE_WORD(0x80000100, fb
, REG_26
);
263 WRITE_WORD(0x80000100, fb
, REG_1
);
269 SETUP_RAMDAC(struct stifb_info
*fb
)
272 WRITE_WORD(0x04000000, fb
, 0x1020);
273 WRITE_WORD(0xff000000, fb
, 0x1028);
277 CRX24_SETUP_RAMDAC(struct stifb_info
*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);
290 HCRX_SETUP_RAMDAC(struct stifb_info
*fb
)
292 WRITE_WORD(0xffffffff, fb
, REG_32
);
297 CRX24_SET_OVLY_MASK(struct stifb_info
*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
);
309 ENABLE_DISABLE_DISPLAY(struct stifb_info
*fb
, int enable
)
311 unsigned int value
= enable
? 0x43000000 : 0x03000000;
313 WRITE_WORD(0x06000000, fb
, 0x1030);
314 WRITE_WORD(value
, fb
, 0x1038);
318 CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info
*fb
, int enable
)
320 unsigned int value
= enable
? 0x10000000 : 0x30000000;
322 WRITE_WORD(0x01000000, fb
, 0x1000);
323 WRITE_WORD(0x02000000, fb
, 0x1004);
324 WRITE_WORD(value
, fb
, 0x1008);
328 ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info
*fb
, int enable
)
330 u32 DregsMiscVideo
= REG_21
;
331 u32 DregsMiscCtl
= REG_27
;
335 WRITE_WORD(READ_WORD(fb
, DregsMiscVideo
) | 0x0A000000, fb
, DregsMiscVideo
);
336 WRITE_WORD(READ_WORD(fb
, DregsMiscCtl
) | 0x00800000, fb
, DregsMiscCtl
);
338 WRITE_WORD(READ_WORD(fb
, DregsMiscVideo
) & ~0x0A000000, fb
, DregsMiscVideo
);
339 WRITE_WORD(READ_WORD(fb
, DregsMiscCtl
) & ~0x00800000, fb
, DregsMiscCtl
);
343 #define GET_ROMTABLE_INDEX(fb) \
344 (READ_BYTE(fb, REG_16b3) - 1)
346 #define HYPER_CONFIG_PLANES_24 0x00000100
348 #define IS_24_DEVICE(fb) \
349 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
351 #define IS_888_DEVICE(fb) \
352 (!(IS_24_DEVICE(fb)))
354 #define GET_FIFO_SLOTS(fb, cnt, numslots) \
355 { while (cnt < numslots) \
356 cnt = READ_WORD(fb, REG_34); \
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 */
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 */
378 #define MaskAddrOffset(offset) (offset)
379 #define StaticReg(en) (en)
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))
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))
391 #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
392 WRITE_WORD(val, fb, REG_14)
394 #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
395 WRITE_WORD(val, fb, REG_11)
397 #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
398 WRITE_WORD(val, fb, REG_12)
400 #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
401 WRITE_WORD(plnmsk32, fb, REG_13)
403 #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
404 WRITE_WORD(fg32, fb, REG_35)
406 #define NGLE_SET_TRANSFERDATA(fb, val) \
407 WRITE_WORD(val, fb, REG_8)
409 #define NGLE_SET_DSTXY(fb, val) \
410 WRITE_WORD(val, fb, REG_6)
412 #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
413 (u32) (fbaddrbase) + \
414 ( (unsigned int) ( (y) << 13 ) | \
415 (unsigned int) ( (x) << 2 ) ) \
418 #define NGLE_BINC_SET_DSTADDR(fb, addr) \
419 WRITE_WORD(addr, fb, REG_3)
421 #define NGLE_BINC_SET_SRCADDR(fb, addr) \
422 WRITE_WORD(addr, fb, REG_2)
424 #define NGLE_BINC_SET_DSTMASK(fb, mask) \
425 WRITE_WORD(mask, fb, REG_22)
427 #define NGLE_BINC_WRITE32(fb, data32) \
428 WRITE_WORD(data32, fb, REG_23)
430 #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
431 WRITE_WORD((cmapBltCtlData32), fb, REG_38)
433 #define SET_LENXY_START_RECFILL(fb, lenxy) \
434 WRITE_WORD(lenxy, fb, REG_9)
436 #define SETUP_COPYAREA(fb) \
437 WRITE_BYTE(0, fb, REG_16b1)
440 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info
*fb
, int enable
)
442 u32 DregsHypMiscVideo
= REG_33
;
445 value
= READ_WORD(fb
, DregsHypMiscVideo
);
449 value
&= ~0x0A000000;
450 WRITE_WORD(value
, fb
, DregsHypMiscVideo
);
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
463 SETUP_ATTR_ACCESS(struct stifb_info
*fb
, unsigned BufferNumber
)
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
);
473 SET_ATTR_SIZE(struct stifb_info
*fb
, int width
, int height
)
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
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
);
489 FINISH_ATTR_ACCESS(struct stifb_info
*fb
)
492 WRITE_WORD(0x00000000, fb
, REG_12
);
496 elkSetupPlanes(struct stifb_info
*fb
)
503 ngleSetupAttrPlanes(struct stifb_info
*fb
, int BufferNumber
)
505 SETUP_ATTR_ACCESS(fb
, BufferNumber
);
506 SET_ATTR_SIZE(fb
, fb
->info
.var
.xres
, fb
->info
.var
.yres
);
507 FINISH_ATTR_ACCESS(fb
);
513 rattlerSetupPlanes(struct stifb_info
*fb
)
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).
521 CRX24_SETUP_RAMDAC(fb
);
523 /* change fb->id temporarily to fool SETUP_FB() */
525 fb
->id
= CRX24_OVERLAY_PLANES
;
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);
533 CRX24_SET_OVLY_MASK(fb
);
538 #define HYPER_CMAP_TYPE 0
539 #define NGLE_CMAP_INDEXED0_TYPE 0
540 #define NGLE_CMAP_OVERLAY_TYPE 3
542 /* typedef of LUT (Colormap) BLT Control Register */
543 typedef union /* Note assumption that fields are packed left-to-right */
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;
560 setNgleLutBltCtl(struct stifb_info
*fb
, int offsetWithinLut
, int length
)
562 NgleLutBltCtl lutBltCtl
;
564 /* set enable, zero reserved fields */
565 lutBltCtl
.all
= 0x80000000;
566 lutBltCtl
.fields
.length
= length
;
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;
575 lutBltCtl
.fields
.lutType
= NGLE_CMAP_INDEXED0_TYPE
;
576 lutBltCtl
.fields
.lutOffset
= 0 * 256;
580 case S9000_ID_ARTIST
:
581 lutBltCtl
.fields
.lutType
= NGLE_CMAP_INDEXED0_TYPE
;
582 lutBltCtl
.fields
.lutOffset
= 0 * 256;
586 lutBltCtl
.fields
.lutType
= NGLE_CMAP_INDEXED0_TYPE
;
587 lutBltCtl
.fields
.lutOffset
= 0;
591 /* Offset points to start of LUT. Adjust for within LUT */
592 lutBltCtl
.fields
.lutOffset
+= offsetWithinLut
;
599 setHyperLutBltCtl(struct stifb_info
*fb
, int offsetWithinLut
, int length
)
601 NgleLutBltCtl lutBltCtl
;
603 /* set enable, zero reserved fields */
604 lutBltCtl
.all
= 0x80000000;
606 lutBltCtl
.fields
.length
= length
;
607 lutBltCtl
.fields
.lutType
= HYPER_CMAP_TYPE
;
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;
613 lutBltCtl
.fields
.lutOffset
= 0 * 256;
615 /* Offset points to start of LUT. Adjust for within LUT */
616 lutBltCtl
.fields
.lutOffset
+= offsetWithinLut
;
622 static void hyperUndoITE(struct stifb_info
*fb
)
624 int nFreeFifoSlots
= 0;
629 GET_FIFO_SLOTS(fb
, nFreeFifoSlots
, 1);
630 WRITE_WORD(0xffffffff, fb
, REG_32
);
632 /* Write overlay transparency mask so only entry 255 is transparent */
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)));
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);
650 /* Finally, write a zero to clear the mask */
651 NGLE_BINC_WRITE32(fb
, 0);
657 ngleDepth8_ClearImagePlanes(struct stifb_info
*fb
)
663 ngleDepth24_ClearImagePlanes(struct stifb_info
*fb
)
669 ngleResetAttrPlanes(struct stifb_info
*fb
, unsigned int ctlPlaneReg
)
671 int nFreeFifoSlots
= 0;
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);
685 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb
,
686 IBOvals(RopSrc
, MaskAddrOffset(0),
687 BitmapExtent08
, StaticReg(1),
688 DataDynamic
, MaskOtc
,
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
);
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
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 */
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);
721 ngleClearOverlayPlanes(struct stifb_info
*fb
, int mask
, int data
)
723 int nFreeFifoSlots
= 0;
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)));
735 NGLE_SET_TRANSFERDATA(fb
, 0xffffffff); /* Write foreground color */
737 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb
, data
);
738 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb
, mask
);
741 packed_len
= (fb
->info
.var
.xres
<< 16) | fb
->info
.var
.yres
;
742 NGLE_SET_DSTXY(fb
, packed_dst
);
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)));
750 SET_LENXY_START_RECFILL(fb
, packed_len
);
756 hyperResetPlanes(struct stifb_info
*fb
, int enable
)
758 unsigned int controlPlaneReg
;
762 if (IS_24_DEVICE(fb
))
763 if (fb
->info
.var
.bits_per_pixel
== 32)
764 controlPlaneReg
= 0x04000F00;
766 controlPlaneReg
= 0x00000F00; /* 0x00000800 should be enough, but lets clear all 4 bits */
768 controlPlaneReg
= 0x00000F00; /* 0x00000100 should be enough, but lets clear all 4 bits */
773 if (IS_24_DEVICE(fb
))
774 ngleDepth24_ClearImagePlanes(fb
);
776 ngleDepth8_ClearImagePlanes(fb
);
778 /* Paint attribute planes for default case.
779 * On Hyperdrive, this means all windows using overlay cmap 0. */
780 ngleResetAttrPlanes(fb
, controlPlaneReg
);
782 /* clear overlay planes */
783 ngleClearOverlayPlanes(fb
, 0xff, 255);
785 /**************************************************
786 ** Also need to counteract ITE settings
787 **************************************************/
793 if (IS_24_DEVICE(fb
))
794 ngleDepth24_ClearImagePlanes(fb
);
796 ngleDepth8_ClearImagePlanes(fb
);
797 ngleResetAttrPlanes(fb
, controlPlaneReg
);
798 ngleClearOverlayPlanes(fb
, 0xff, 0);
803 ngleResetAttrPlanes(fb
, controlPlaneReg
);
810 /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
813 ngleGetDeviceRomData(struct stifb_info
*fb
)
817 int *pBytePerLongDevDepData
;/* data byte == LSB */
819 NgleDevRomData
*pPackedDevRomData
;
820 int sizePackedDevRomData
= sizeof(*pPackedDevRomData
);
823 char *mapOrigin
= NULL
;
827 pPackedDevRomData
= fb
->ngle_rom
;
830 if (fb
->id
== S9000_ID_ARTIST
) {
831 pPackedDevRomData
->cursor_pipeline_delay
= 4;
832 pPackedDevRomData
->video_interleaves
= 4;
834 /* Get pointer to unpacked byte/long data in ROM */
835 pBytePerLongDevDepData
= fb
->sti
->regions
[NGLEDEVDEPROM_CRT_REGION
];
837 /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
838 if (fb
->id
== S9000_ID_TOMCAT
)
840 /* jump to the correct ROM table */
841 GET_ROMTABLE_INDEX(romTableIdx
);
842 while (romTableIdx
> 0)
844 pCard8
= (Card8
*) pPackedDevRomData
;
845 pRomTable
= pBytePerLongDevDepData
;
846 /* Pack every fourth byte from ROM into structure */
847 for (i
= 0; i
< sizePackedDevRomData
; i
++)
849 *pCard8
++ = (Card8
) (*pRomTable
++);
852 pBytePerLongDevDepData
= (Card32
*)
853 ((Card8
*) pBytePerLongDevDepData
+
854 pPackedDevRomData
->sizeof_ngle_data
);
860 pCard8
= (Card8
*) pPackedDevRomData
;
862 /* Pack every fourth byte from ROM into structure */
863 for (i
= 0; i
< sizePackedDevRomData
; i
++)
865 *pCard8
++ = (Card8
) (*pBytePerLongDevDepData
++);
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
879 /* HCRX specific boot-time initialization */
881 SETUP_HCRX(struct stifb_info
*fb
)
884 int nFreeFifoSlots
= 0;
886 if (fb
->id
!= S9000_ID_HCRX
)
889 /* Initialize Hyperbowl registers */
890 GET_FIFO_SLOTS(fb
, nFreeFifoSlots
, 7);
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
;
897 /* First write to Hyperbowl must happen twice (bug) */
898 WRITE_WORD(hyperbowl
, fb
, REG_40
);
899 WRITE_WORD(hyperbowl
, fb
, REG_40
);
901 WRITE_WORD(HYPERBOWL_MODE2_8_24
, fb
, REG_39
);
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
);
908 hyperbowl
= HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES
;
910 /* First write to Hyperbowl must happen twice (bug) */
911 WRITE_WORD(hyperbowl
, fb
, REG_40
);
912 WRITE_WORD(hyperbowl
, fb
, REG_40
);
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
);
922 /* ------------------- driver specific functions --------------------------- */
925 stifb_setcolreg(u_int regno
, u_int red
, u_int green
,
926 u_int blue
, u_int transp
, struct fb_info
*info
)
928 struct stifb_info
*fb
= container_of(info
, struct stifb_info
, info
);
931 if (regno
>= NR_PALETTE
)
940 START_IMAGE_COLORMAP_ACCESS(fb
);
942 if (unlikely(fb
->info
.var
.grayscale
)) {
943 /* gray = 0.30*R + 0.59*G + 0.11*B */
944 color
= ((red
* 77) +
948 color
= ((red
<< 16) |
953 if (fb
->info
.fix
.visual
== FB_VISUAL_DIRECTCOLOR
) {
954 struct fb_var_screeninfo
*var
= &fb
->info
.var
;
956 ((u32
*)fb
->info
.pseudo_palette
)[regno
] =
957 regno
<< var
->red
.offset
|
958 regno
<< var
->green
.offset
|
959 regno
<< var
->blue
.offset
;
962 WRITE_IMAGE_COLOR(fb
, regno
, color
);
964 if (fb
->id
== S9000_ID_HCRX
) {
965 NgleLutBltCtl lutBltCtl
;
967 lutBltCtl
= setHyperLutBltCtl(fb
,
968 0, /* Offset w/i LUT */
969 256); /* Load entire LUT */
970 NGLE_BINC_SET_SRCADDR(fb
,
971 NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
972 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
973 START_COLORMAPLOAD(fb
, lutBltCtl
.all
);
976 /* cleanup colormap hardware */
977 FINISH_IMAGE_COLORMAP_ACCESS(fb
);
986 stifb_blank(int blank_mode
, struct fb_info
*info
)
988 struct stifb_info
*fb
= container_of(info
, struct stifb_info
, info
);
989 int enable
= (blank_mode
== 0) ? ENABLE
: DISABLE
;
992 case S9000_ID_A1439A
:
993 CRX24_ENABLE_DISABLE_DISPLAY(fb
, enable
);
995 case CRT_ID_VISUALIZE_EG
:
996 case S9000_ID_ARTIST
:
997 ARTIST_ENABLE_DISABLE_DISPLAY(fb
, enable
);
1000 HYPER_ENABLE_DISABLE_DISPLAY(fb
, enable
);
1002 case S9000_ID_A1659A
: /* fall through */
1003 case S9000_ID_TIMBER
:
1004 case CRX24_OVERLAY_PLANES
:
1006 ENABLE_DISABLE_DISPLAY(fb
, enable
);
1015 stifb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
1017 struct stifb_info
*fb
= container_of(info
, struct stifb_info
, info
);
1022 if (fb
->info
.var
.bits_per_pixel
== 32) {
1023 WRITE_WORD(0xBBA0A000, fb
, REG_10
);
1025 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb
, 0xffffffff);
1027 WRITE_WORD(fb
->id
== S9000_ID_HCRX
? 0x13a02000 : 0x13a01000, fb
, REG_10
);
1029 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb
, 0xff);
1032 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb
,
1033 IBOvals(RopSrc
, MaskAddrOffset(0),
1034 BitmapExtent08
, StaticReg(1),
1035 DataDynamic
, MaskOtc
, BGx(0), FGx(0)));
1037 WRITE_WORD(((area
->sx
<< 16) | area
->sy
), fb
, REG_24
);
1038 WRITE_WORD(((area
->width
<< 16) | area
->height
), fb
, REG_7
);
1039 WRITE_WORD(((area
->dx
<< 16) | area
->dy
), fb
, REG_25
);
1045 stifb_init_display(struct stifb_info
*fb
)
1051 /* HCRX specific initialization */
1055 if (id == S9000_ID_HCRX)
1056 hyperInitSprite(fb);
1061 /* Initialize the image planes. */
1064 hyperResetPlanes(fb
, ENABLE
);
1066 case S9000_ID_A1439A
:
1067 rattlerSetupPlanes(fb
);
1069 case S9000_ID_A1659A
:
1070 case S9000_ID_ARTIST
:
1071 case CRT_ID_VISUALIZE_EG
:
1076 /* Clear attribute planes on non HCRX devices. */
1078 case S9000_ID_A1659A
:
1079 case S9000_ID_A1439A
:
1080 if (fb
->info
.var
.bits_per_pixel
== 32)
1081 ngleSetupAttrPlanes(fb
, BUFF1_CMAP3
);
1083 ngleSetupAttrPlanes(fb
, BUFF1_CMAP0
);
1085 if (id
== S9000_ID_A1439A
)
1086 ngleClearOverlayPlanes(fb
, 0xff, 0);
1088 case S9000_ID_ARTIST
:
1089 case CRT_ID_VISUALIZE_EG
:
1090 if (fb
->info
.var
.bits_per_pixel
== 32)
1091 ngleSetupAttrPlanes(fb
, BUFF1_CMAP3
);
1093 ngleSetupAttrPlanes(fb
, ARTIST_CMAP0
);
1097 stifb_blank(0, (struct fb_info
*)fb
); /* 0=enable screen */
1102 /* ------------ Interfaces to hardware functions ------------ */
1104 static struct fb_ops stifb_ops
= {
1105 .owner
= THIS_MODULE
,
1106 .fb_setcolreg
= stifb_setcolreg
,
1107 .fb_blank
= stifb_blank
,
1108 .fb_fillrect
= cfb_fillrect
,
1109 .fb_copyarea
= stifb_copyarea
,
1110 .fb_imageblit
= cfb_imageblit
,
1118 static int __init
stifb_init_fb(struct sti_struct
*sti
, int bpp_pref
)
1120 struct fb_fix_screeninfo
*fix
;
1121 struct fb_var_screeninfo
*var
;
1122 struct stifb_info
*fb
;
1123 struct fb_info
*info
;
1124 unsigned long sti_rom_address
;
1126 int bpp
, xres
, yres
;
1128 fb
= kzalloc(sizeof(*fb
), GFP_ATOMIC
);
1134 /* set struct to a known state */
1139 dev_name
= sti
->sti_data
->inq_outptr
.dev_name
;
1140 /* store upper 32bits of the graphics id */
1141 fb
->id
= fb
->sti
->graphics_id
[0];
1143 /* only supported cards are allowed */
1145 case CRT_ID_VISUALIZE_EG
:
1146 /* Visualize cards can run either in "double buffer" or
1147 "standard" mode. Depending on the mode, the card reports
1148 a different device name, e.g. "INTERNAL_EG_DX1024" in double
1149 buffer mode and "INTERNAL_EG_X1024" in standard mode.
1150 Since this driver only supports standard mode, we check
1151 if the device name contains the string "DX" and tell the
1152 user how to reconfigure the card. */
1153 if (strstr(dev_name
, "DX")) {
1155 "WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
1156 "WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
1161 case S9000_ID_ARTIST
:
1163 case S9000_ID_TIMBER
:
1164 case S9000_ID_A1659A
:
1165 case S9000_ID_A1439A
:
1168 printk(KERN_WARNING
"stifb: '%s' (id: 0x%08x) not supported.\n",
1173 /* default to 8 bpp on most graphic chips */
1175 xres
= sti_onscreen_x(fb
->sti
);
1176 yres
= sti_onscreen_y(fb
->sti
);
1178 ngleGetDeviceRomData(fb
);
1180 /* get (virtual) io region base addr */
1181 fix
->mmio_start
= REGION_BASE(fb
,2);
1182 fix
->mmio_len
= 0x400000;
1184 /* Reject any device not in the NGLE family */
1186 case S9000_ID_A1659A
: /* CRX/A1659A */
1188 case S9000_ID_ELM
: /* GRX, grayscale but else same as A1659A */
1190 fb
->id
= S9000_ID_A1659A
;
1192 case S9000_ID_TIMBER
: /* HP9000/710 Any (may be a grayscale device) */
1193 if (strstr(dev_name
, "GRAYSCALE") ||
1194 strstr(dev_name
, "Grayscale") ||
1195 strstr(dev_name
, "grayscale"))
1198 case S9000_ID_TOMCAT
: /* Dual CRX, behaves else like a CRX */
1199 /* FIXME: TomCat supports two heads:
1200 * fb.iobase = REGION_BASE(fb_info,3);
1201 * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx);
1202 * for now we only support the left one ! */
1203 xres
= fb
->ngle_rom
.x_size_visible
;
1204 yres
= fb
->ngle_rom
.y_size_visible
;
1205 fb
->id
= S9000_ID_A1659A
;
1207 case S9000_ID_A1439A
: /* CRX24/A1439A */
1210 case S9000_ID_HCRX
: /* Hyperdrive/HCRX */
1211 memset(&fb
->ngle_rom
, 0, sizeof(fb
->ngle_rom
));
1212 if ((fb
->sti
->regions_phys
[0] & 0xfc000000) ==
1213 (fb
->sti
->regions_phys
[2] & 0xfc000000))
1214 sti_rom_address
= F_EXTEND(fb
->sti
->regions_phys
[0]);
1216 sti_rom_address
= F_EXTEND(fb
->sti
->regions_phys
[1]);
1218 fb
->deviceSpecificConfig
= gsc_readl(sti_rom_address
);
1219 if (IS_24_DEVICE(fb
)) {
1220 if (bpp_pref
== 8 || bpp_pref
== 32)
1226 READ_WORD(fb
, REG_15
);
1229 case CRT_ID_VISUALIZE_EG
:
1230 case S9000_ID_ARTIST
: /* Artist */
1233 #ifdef FALLBACK_TO_1BPP
1235 "stifb: Unsupported graphics card (id=0x%08x) "
1236 "- now trying 1bpp mode instead\n",
1238 bpp
= 1; /* default to 1 bpp */
1242 "stifb: Unsupported graphics card (id=0x%08x) "
1250 /* get framebuffer physical and virtual base addr & len (64bit ready) */
1251 fix
->smem_start
= F_EXTEND(fb
->sti
->regions_phys
[1]);
1252 fix
->smem_len
= fb
->sti
->regions
[1].region_desc
.length
* 4096;
1254 fix
->line_length
= (fb
->sti
->glob_cfg
->total_x
* bpp
) / 8;
1255 if (!fix
->line_length
)
1256 fix
->line_length
= 2048; /* default */
1258 /* limit fbsize to max visible screen size */
1259 if (fix
->smem_len
> yres
*fix
->line_length
)
1260 fix
->smem_len
= yres
*fix
->line_length
;
1262 fix
->accel
= FB_ACCEL_NONE
;
1266 fix
->type
= FB_TYPE_PLANES
; /* well, sort of */
1267 fix
->visual
= FB_VISUAL_MONO10
;
1268 var
->red
.length
= var
->green
.length
= var
->blue
.length
= 1;
1271 fix
->type
= FB_TYPE_PACKED_PIXELS
;
1272 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
1273 var
->red
.length
= var
->green
.length
= var
->blue
.length
= 8;
1276 fix
->type
= FB_TYPE_PACKED_PIXELS
;
1277 fix
->visual
= FB_VISUAL_DIRECTCOLOR
;
1278 var
->red
.length
= var
->green
.length
= var
->blue
.length
= var
->transp
.length
= 8;
1279 var
->blue
.offset
= 0;
1280 var
->green
.offset
= 8;
1281 var
->red
.offset
= 16;
1282 var
->transp
.offset
= 24;
1288 var
->xres
= var
->xres_virtual
= xres
;
1289 var
->yres
= var
->yres_virtual
= yres
;
1290 var
->bits_per_pixel
= bpp
;
1292 strcpy(fix
->id
, "stifb");
1293 info
->fbops
= &stifb_ops
;
1294 info
->screen_base
= ioremap_nocache(REGION_BASE(fb
,1), fix
->smem_len
);
1295 if (!info
->screen_base
) {
1296 printk(KERN_ERR
"stifb: failed to map memory\n");
1299 info
->screen_size
= fix
->smem_len
;
1300 info
->flags
= FBINFO_DEFAULT
| FBINFO_HWACCEL_COPYAREA
;
1301 info
->pseudo_palette
= &fb
->pseudo_palette
;
1303 /* This has to be done !!! */
1304 if (fb_alloc_cmap(&info
->cmap
, NR_PALETTE
, 0))
1306 stifb_init_display(fb
);
1308 if (!request_mem_region(fix
->smem_start
, fix
->smem_len
, "stifb fb")) {
1309 printk(KERN_ERR
"stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1310 fix
->smem_start
, fix
->smem_start
+fix
->smem_len
);
1314 if (!request_mem_region(fix
->mmio_start
, fix
->mmio_len
, "stifb mmio")) {
1315 printk(KERN_ERR
"stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1316 fix
->mmio_start
, fix
->mmio_start
+fix
->mmio_len
);
1320 if (register_framebuffer(&fb
->info
) < 0)
1323 sti
->info
= info
; /* save for unregister_framebuffer() */
1325 fb_info(&fb
->info
, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1329 var
->bits_per_pixel
,
1338 release_mem_region(fix
->mmio_start
, fix
->mmio_len
);
1340 release_mem_region(fix
->smem_start
, fix
->smem_len
);
1342 fb_dealloc_cmap(&info
->cmap
);
1344 iounmap(info
->screen_base
);
1350 static int stifb_disabled __initdata
;
1353 stifb_setup(char *options
);
1355 static int __init
stifb_init(void)
1357 struct sti_struct
*sti
;
1358 struct sti_struct
*def_sti
;
1362 char *option
= NULL
;
1364 if (fb_get_options("stifb", &option
))
1366 stifb_setup(option
);
1368 if (stifb_disabled
) {
1369 printk(KERN_INFO
"stifb: disabled by \"stifb=off\" kernel parameter\n");
1373 def_sti
= sti_get_rom(0);
1375 for (i
= 1; i
<= MAX_STI_ROMS
; i
++) {
1376 sti
= sti_get_rom(i
);
1379 if (sti
== def_sti
) {
1380 stifb_init_fb(sti
, stifb_bpp_pref
[i
- 1]);
1386 for (i
= 1; i
<= MAX_STI_ROMS
; i
++) {
1387 sti
= sti_get_rom(i
);
1392 stifb_init_fb(sti
, stifb_bpp_pref
[i
- 1]);
1404 struct sti_struct
*sti
;
1407 for (i
= 1; i
<= MAX_STI_ROMS
; i
++) {
1408 sti
= sti_get_rom(i
);
1412 struct fb_info
*info
= sti
->info
;
1413 unregister_framebuffer(sti
->info
);
1414 release_mem_region(info
->fix
.mmio_start
, info
->fix
.mmio_len
);
1415 release_mem_region(info
->fix
.smem_start
, info
->fix
.smem_len
);
1416 if (info
->screen_base
)
1417 iounmap(info
->screen_base
);
1418 fb_dealloc_cmap(&info
->cmap
);
1419 framebuffer_release(info
);
1426 stifb_setup(char *options
)
1430 if (!options
|| !*options
)
1433 if (strncmp(options
, "off", 3) == 0) {
1438 if (strncmp(options
, "bpp", 3) == 0) {
1440 for (i
= 0; i
< MAX_STI_ROMS
; i
++) {
1441 if (*options
++ != ':')
1443 stifb_bpp_pref
[i
] = simple_strtoul(options
, &options
, 10);
1449 __setup("stifb=", stifb_setup
);
1451 module_init(stifb_init
);
1452 module_exit(stifb_cleanup
);
1454 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1455 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1456 MODULE_LICENSE("GPL v2");