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-2005 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/config.h>
58 #include <linux/module.h>
59 #include <linux/kernel.h>
60 #include <linux/errno.h>
61 #include <linux/string.h>
63 #include <linux/slab.h>
64 #include <linux/delay.h>
66 #include <linux/init.h>
67 #include <linux/ioport.h>
68 #include <linux/pci.h>
70 #include <asm/grfioctl.h> /* for HP-UX compatibility */
71 #include <asm/uaccess.h>
75 /* REGION_BASE(fb_info, index) returns the virtual address for region <index> */
76 #define REGION_BASE(fb_info, index) \
77 F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index])
79 #define NGLEDEVDEPROM_CRT_REGION 1
81 #define NR_PALETTE 256
84 __s32 video_config_reg
;
85 __s32 misc_video_start
;
86 __s32 horiz_timing_fmt
;
87 __s32 serr_timing_fmt
;
88 __s32 vert_timing_fmt
;
91 __s32 vtg_state_elements
;
97 __s16 sizeof_ngle_data
;
98 __s16 x_size_visible
; /* visible screen dim in pixels */
101 __s16 cursor_pipeline_delay
;
102 __s16 video_interleaves
;
110 struct sti_struct
*sti
;
111 int deviceSpecificConfig
;
112 u32 pseudo_palette
[16];
115 static int __initdata stifb_bpp_pref
[MAX_STI_ROMS
];
117 /* ------------------- chipset specific functions -------------------------- */
119 /* offsets to graphic-chip internal registers */
121 #define REG_1 0x000118
122 #define REG_2 0x000480
123 #define REG_3 0x0004a0
124 #define REG_4 0x000600
125 #define REG_6 0x000800
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_26 0x200118
141 #define REG_27 0x200308
142 #define REG_32 0x21003c
143 #define REG_33 0x210040
144 #define REG_34 0x200008
145 #define REG_35 0x018010
146 #define REG_38 0x210020
147 #define REG_39 0x210120
148 #define REG_40 0x210130
149 #define REG_42 0x210028
150 #define REG_43 0x21002c
151 #define REG_44 0x210030
152 #define REG_45 0x210034
154 #define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg))
155 #define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg))
158 #ifndef DEBUG_STIFB_REGS
161 # define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
162 # define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
164 static int debug_on
= 1;
165 # define DEBUG_OFF() debug_on=0
166 # define DEBUG_ON() debug_on=1
167 # define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
168 printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
169 __FUNCTION__, reg, value, READ_BYTE(fb,reg)); \
170 gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
171 # define WRITE_WORD(value,fb,reg) do { if (debug_on) \
172 printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
173 __FUNCTION__, reg, value, READ_WORD(fb,reg)); \
174 gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
175 #endif /* DEBUG_STIFB_REGS */
178 #define ENABLE 1 /* for enabling/disabling screen */
181 #define NGLE_LOCK(fb_info) do { } while (0)
182 #define NGLE_UNLOCK(fb_info) do { } while (0)
185 SETUP_HW(struct stifb_info
*fb
)
190 stat
= READ_BYTE(fb
, REG_15b0
);
192 stat
= READ_BYTE(fb
, REG_15b0
);
198 SETUP_FB(struct stifb_info
*fb
)
200 unsigned int reg10_value
= 0;
205 case CRT_ID_VISUALIZE_EG
:
206 case S9000_ID_ARTIST
:
207 case S9000_ID_A1659A
:
208 reg10_value
= 0x13601000;
210 case S9000_ID_A1439A
:
211 if (fb
->info
.var
.bits_per_pixel
== 32)
212 reg10_value
= 0xBBA0A000;
214 reg10_value
= 0x13601000;
217 if (fb
->info
.var
.bits_per_pixel
== 32)
218 reg10_value
= 0xBBA0A000;
220 reg10_value
= 0x13602000;
222 case S9000_ID_TIMBER
:
223 case CRX24_OVERLAY_PLANES
:
224 reg10_value
= 0x13602000;
228 WRITE_WORD(reg10_value
, fb
, REG_10
);
229 WRITE_WORD(0x83000300, fb
, REG_14
);
231 WRITE_BYTE(1, fb
, REG_16b1
);
235 START_IMAGE_COLORMAP_ACCESS(struct stifb_info
*fb
)
238 WRITE_WORD(0xBBE0F000, fb
, REG_10
);
239 WRITE_WORD(0x03000300, fb
, REG_14
);
240 WRITE_WORD(~0, fb
, REG_13
);
244 WRITE_IMAGE_COLOR(struct stifb_info
*fb
, int index
, int color
)
247 WRITE_WORD(((0x100+index
)<<2), fb
, REG_3
);
248 WRITE_WORD(color
, fb
, REG_4
);
252 FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info
*fb
)
254 WRITE_WORD(0x400, fb
, REG_2
);
255 if (fb
->info
.var
.bits_per_pixel
== 32) {
256 WRITE_WORD(0x83000100, fb
, REG_1
);
258 if (fb
->id
== S9000_ID_ARTIST
|| fb
->id
== CRT_ID_VISUALIZE_EG
)
259 WRITE_WORD(0x80000100, fb
, REG_26
);
261 WRITE_WORD(0x80000100, fb
, REG_1
);
267 SETUP_RAMDAC(struct stifb_info
*fb
)
270 WRITE_WORD(0x04000000, fb
, 0x1020);
271 WRITE_WORD(0xff000000, fb
, 0x1028);
275 CRX24_SETUP_RAMDAC(struct stifb_info
*fb
)
278 WRITE_WORD(0x04000000, fb
, 0x1000);
279 WRITE_WORD(0x02000000, fb
, 0x1004);
280 WRITE_WORD(0xff000000, fb
, 0x1008);
281 WRITE_WORD(0x05000000, fb
, 0x1000);
282 WRITE_WORD(0x02000000, fb
, 0x1004);
283 WRITE_WORD(0x03000000, fb
, 0x1008);
288 HCRX_SETUP_RAMDAC(struct stifb_info
*fb
)
290 WRITE_WORD(0xffffffff, fb
, REG_32
);
295 CRX24_SET_OVLY_MASK(struct stifb_info
*fb
)
298 WRITE_WORD(0x13a02000, fb
, REG_11
);
299 WRITE_WORD(0x03000300, fb
, REG_14
);
300 WRITE_WORD(0x000017f0, fb
, REG_3
);
301 WRITE_WORD(0xffffffff, fb
, REG_13
);
302 WRITE_WORD(0xffffffff, fb
, REG_22
);
303 WRITE_WORD(0x00000000, fb
, REG_23
);
307 ENABLE_DISABLE_DISPLAY(struct stifb_info
*fb
, int enable
)
309 unsigned int value
= enable
? 0x43000000 : 0x03000000;
311 WRITE_WORD(0x06000000, fb
, 0x1030);
312 WRITE_WORD(value
, fb
, 0x1038);
316 CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info
*fb
, int enable
)
318 unsigned int value
= enable
? 0x10000000 : 0x30000000;
320 WRITE_WORD(0x01000000, fb
, 0x1000);
321 WRITE_WORD(0x02000000, fb
, 0x1004);
322 WRITE_WORD(value
, fb
, 0x1008);
326 ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info
*fb
, int enable
)
328 u32 DregsMiscVideo
= REG_21
;
329 u32 DregsMiscCtl
= REG_27
;
333 WRITE_WORD(READ_WORD(fb
, DregsMiscVideo
) | 0x0A000000, fb
, DregsMiscVideo
);
334 WRITE_WORD(READ_WORD(fb
, DregsMiscCtl
) | 0x00800000, fb
, DregsMiscCtl
);
336 WRITE_WORD(READ_WORD(fb
, DregsMiscVideo
) & ~0x0A000000, fb
, DregsMiscVideo
);
337 WRITE_WORD(READ_WORD(fb
, DregsMiscCtl
) & ~0x00800000, fb
, DregsMiscCtl
);
341 #define GET_ROMTABLE_INDEX(fb) \
342 (READ_BYTE(fb, REG_16b3) - 1)
344 #define HYPER_CONFIG_PLANES_24 0x00000100
346 #define IS_24_DEVICE(fb) \
347 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
349 #define IS_888_DEVICE(fb) \
350 (!(IS_24_DEVICE(fb)))
352 #define GET_FIFO_SLOTS(fb, cnt, numslots) \
353 { while (cnt < numslots) \
354 cnt = READ_WORD(fb, REG_34); \
358 #define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
359 #define Otc04 2 /* Pixels in each longword transfer (4) */
360 #define Otc32 5 /* Pixels in each longword transfer (32) */
361 #define Ots08 3 /* Each pixel is size (8)d transfer (1) */
362 #define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */
363 #define AddrLong 5 /* FB address is Long aligned (pixel) */
364 #define BINovly 0x2 /* 8 bit overlay */
365 #define BINapp0I 0x0 /* Application Buffer 0, Indexed */
366 #define BINapp1I 0x1 /* Application Buffer 1, Indexed */
367 #define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */
368 #define BINattr 0xd /* Attribute Bitmap */
370 #define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */
371 #define BitmapExtent32 5 /* Each write hits (32) bits in depth */
372 #define DataDynamic 0 /* Data register reloaded by direct access */
373 #define MaskDynamic 1 /* Mask register reloaded by direct access */
374 #define MaskOtc 0 /* Mask contains Object Count valid bits */
376 #define MaskAddrOffset(offset) (offset)
377 #define StaticReg(en) (en)
381 #define BAJustPoint(offset) (offset)
382 #define BAIndexBase(base) (base)
383 #define BA(F,C,S,A,J,B,I) \
384 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
386 #define IBOvals(R,M,X,S,D,L,B,F) \
387 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
389 #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
390 WRITE_WORD(val, fb, REG_14)
392 #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
393 WRITE_WORD(val, fb, REG_11)
395 #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
396 WRITE_WORD(val, fb, REG_12)
398 #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
399 WRITE_WORD(plnmsk32, fb, REG_13)
401 #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
402 WRITE_WORD(fg32, fb, REG_35)
404 #define NGLE_SET_TRANSFERDATA(fb, val) \
405 WRITE_WORD(val, fb, REG_8)
407 #define NGLE_SET_DSTXY(fb, val) \
408 WRITE_WORD(val, fb, REG_6)
410 #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
411 (u32) (fbaddrbase) + \
412 ( (unsigned int) ( (y) << 13 ) | \
413 (unsigned int) ( (x) << 2 ) ) \
416 #define NGLE_BINC_SET_DSTADDR(fb, addr) \
417 WRITE_WORD(addr, fb, REG_3)
419 #define NGLE_BINC_SET_SRCADDR(fb, addr) \
420 WRITE_WORD(addr, fb, REG_2)
422 #define NGLE_BINC_SET_DSTMASK(fb, mask) \
423 WRITE_WORD(mask, fb, REG_22)
425 #define NGLE_BINC_WRITE32(fb, data32) \
426 WRITE_WORD(data32, fb, REG_23)
428 #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
429 WRITE_WORD((cmapBltCtlData32), fb, REG_38)
431 #define SET_LENXY_START_RECFILL(fb, lenxy) \
432 WRITE_WORD(lenxy, fb, REG_9)
435 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info
*fb
, int enable
)
437 u32 DregsHypMiscVideo
= REG_33
;
440 value
= READ_WORD(fb
, DregsHypMiscVideo
);
444 value
&= ~0x0A000000;
445 WRITE_WORD(value
, fb
, DregsHypMiscVideo
);
449 /* BufferNumbers used by SETUP_ATTR_ACCESS() */
450 #define BUFF0_CMAP0 0x00001e02
451 #define BUFF1_CMAP0 0x02001e02
452 #define BUFF1_CMAP3 0x0c001e02
453 #define ARTIST_CMAP0 0x00000102
454 #define HYPER_CMAP8 0x00000100
455 #define HYPER_CMAP24 0x00000800
458 SETUP_ATTR_ACCESS(struct stifb_info
*fb
, unsigned BufferNumber
)
461 WRITE_WORD(0x2EA0D000, fb
, REG_11
);
462 WRITE_WORD(0x23000302, fb
, REG_14
);
463 WRITE_WORD(BufferNumber
, fb
, REG_12
);
464 WRITE_WORD(0xffffffff, fb
, REG_8
);
468 SET_ATTR_SIZE(struct stifb_info
*fb
, int width
, int height
)
470 /* REG_6 seems to have special values when run on a
471 RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
472 INTERNAL_EG_X1024). The values are:
473 0x2f0: internal (LCD) & external display enabled
474 0x2a0: external display only
475 0x000: zero on standard artist graphic cards
477 WRITE_WORD(0x00000000, fb
, REG_6
);
478 WRITE_WORD((width
<<16) | height
, fb
, REG_9
);
479 WRITE_WORD(0x05000000, fb
, REG_6
);
480 WRITE_WORD(0x00040001, fb
, REG_9
);
484 FINISH_ATTR_ACCESS(struct stifb_info
*fb
)
487 WRITE_WORD(0x00000000, fb
, REG_12
);
491 elkSetupPlanes(struct stifb_info
*fb
)
498 ngleSetupAttrPlanes(struct stifb_info
*fb
, int BufferNumber
)
500 SETUP_ATTR_ACCESS(fb
, BufferNumber
);
501 SET_ATTR_SIZE(fb
, fb
->info
.var
.xres
, fb
->info
.var
.yres
);
502 FINISH_ATTR_ACCESS(fb
);
508 rattlerSetupPlanes(struct stifb_info
*fb
)
510 CRX24_SETUP_RAMDAC(fb
);
512 /* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */
513 WRITE_WORD(0x83000300, fb
, REG_14
);
515 WRITE_BYTE(1, fb
, REG_16b1
);
517 fb_memset(fb
->info
.fix
.smem_start
, 0xff,
518 fb
->info
.var
.yres
*fb
->info
.fix
.line_length
);
520 CRX24_SET_OVLY_MASK(fb
);
525 #define HYPER_CMAP_TYPE 0
526 #define NGLE_CMAP_INDEXED0_TYPE 0
527 #define NGLE_CMAP_OVERLAY_TYPE 3
529 /* typedef of LUT (Colormap) BLT Control Register */
530 typedef union /* Note assumption that fields are packed left-to-right */
535 unsigned waitBlank
: 1;
536 unsigned reserved1
: 4;
537 unsigned lutOffset
: 10; /* Within destination LUT */
538 unsigned lutType
: 2; /* Cursor, image, overlay */
539 unsigned reserved2
: 4;
540 unsigned length
: 10;
547 setNgleLutBltCtl(struct stifb_info
*fb
, int offsetWithinLut
, int length
)
549 NgleLutBltCtl lutBltCtl
;
551 /* set enable, zero reserved fields */
552 lutBltCtl
.all
= 0x80000000;
553 lutBltCtl
.fields
.length
= length
;
557 case S9000_ID_A1439A
: /* CRX24 */
558 if (fb
->var
.bits_per_pixel
== 8) {
559 lutBltCtl
.fields
.lutType
= NGLE_CMAP_OVERLAY_TYPE
;
560 lutBltCtl
.fields
.lutOffset
= 0;
562 lutBltCtl
.fields
.lutType
= NGLE_CMAP_INDEXED0_TYPE
;
563 lutBltCtl
.fields
.lutOffset
= 0 * 256;
567 case S9000_ID_ARTIST
:
568 lutBltCtl
.fields
.lutType
= NGLE_CMAP_INDEXED0_TYPE
;
569 lutBltCtl
.fields
.lutOffset
= 0 * 256;
573 lutBltCtl
.fields
.lutType
= NGLE_CMAP_INDEXED0_TYPE
;
574 lutBltCtl
.fields
.lutOffset
= 0;
578 /* Offset points to start of LUT. Adjust for within LUT */
579 lutBltCtl
.fields
.lutOffset
+= offsetWithinLut
;
586 setHyperLutBltCtl(struct stifb_info
*fb
, int offsetWithinLut
, int length
)
588 NgleLutBltCtl lutBltCtl
;
590 /* set enable, zero reserved fields */
591 lutBltCtl
.all
= 0x80000000;
593 lutBltCtl
.fields
.length
= length
;
594 lutBltCtl
.fields
.lutType
= HYPER_CMAP_TYPE
;
596 /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
597 if (fb
->info
.var
.bits_per_pixel
== 8)
598 lutBltCtl
.fields
.lutOffset
= 2 * 256;
600 lutBltCtl
.fields
.lutOffset
= 0 * 256;
602 /* Offset points to start of LUT. Adjust for within LUT */
603 lutBltCtl
.fields
.lutOffset
+= offsetWithinLut
;
609 static void hyperUndoITE(struct stifb_info
*fb
)
611 int nFreeFifoSlots
= 0;
616 GET_FIFO_SLOTS(fb
, nFreeFifoSlots
, 1);
617 WRITE_WORD(0xffffffff, fb
, REG_32
);
619 /* Write overlay transparency mask so only entry 255 is transparent */
621 /* Hardware setup for full-depth write to "magic" location */
622 GET_FIFO_SLOTS(fb
, nFreeFifoSlots
, 7);
623 NGLE_QUICK_SET_DST_BM_ACCESS(fb
,
624 BA(IndexedDcd
, Otc04
, Ots08
, AddrLong
,
625 BAJustPoint(0), BINovly
, BAIndexBase(0)));
626 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb
,
627 IBOvals(RopSrc
, MaskAddrOffset(0),
628 BitmapExtent08
, StaticReg(0),
629 DataDynamic
, MaskOtc
, BGx(0), FGx(0)));
631 /* Now prepare to write to the "magic" location */
632 fbAddr
= NGLE_LONG_FB_ADDRESS(0, 1532, 0);
633 NGLE_BINC_SET_DSTADDR(fb
, fbAddr
);
634 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb
, 0xffffff);
635 NGLE_BINC_SET_DSTMASK(fb
, 0xffffffff);
637 /* Finally, write a zero to clear the mask */
638 NGLE_BINC_WRITE32(fb
, 0);
644 ngleDepth8_ClearImagePlanes(struct stifb_info
*fb
)
650 ngleDepth24_ClearImagePlanes(struct stifb_info
*fb
)
656 ngleResetAttrPlanes(struct stifb_info
*fb
, unsigned int ctlPlaneReg
)
658 int nFreeFifoSlots
= 0;
664 GET_FIFO_SLOTS(fb
, nFreeFifoSlots
, 4);
665 NGLE_QUICK_SET_DST_BM_ACCESS(fb
,
666 BA(IndexedDcd
, Otc32
, OtsIndirect
,
667 AddrLong
, BAJustPoint(0),
668 BINattr
, BAIndexBase(0)));
669 NGLE_QUICK_SET_CTL_PLN_REG(fb
, ctlPlaneReg
);
670 NGLE_SET_TRANSFERDATA(fb
, 0xffffffff);
672 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb
,
673 IBOvals(RopSrc
, MaskAddrOffset(0),
674 BitmapExtent08
, StaticReg(1),
675 DataDynamic
, MaskOtc
,
678 packed_len
= (fb
->info
.var
.xres
<< 16) | fb
->info
.var
.yres
;
679 GET_FIFO_SLOTS(fb
, nFreeFifoSlots
, 2);
680 NGLE_SET_DSTXY(fb
, packed_dst
);
681 SET_LENXY_START_RECFILL(fb
, packed_len
);
684 * In order to work around an ELK hardware problem (Buffy doesn't
685 * always flush it's buffers when writing to the attribute
686 * planes), at least 4 pixels must be written to the attribute
687 * planes starting at (X == 1280) and (Y != to the last Y written
691 if (fb
->id
== S9000_ID_A1659A
) { /* ELK_DEVICE_ID */
692 /* It's safe to use scanline zero: */
693 packed_dst
= (1280 << 16);
694 GET_FIFO_SLOTS(fb
, nFreeFifoSlots
, 2);
695 NGLE_SET_DSTXY(fb
, packed_dst
);
696 packed_len
= (4 << 16) | 1;
697 SET_LENXY_START_RECFILL(fb
, packed_len
);
698 } /* ELK Hardware Kludge */
700 /**** Finally, set the Control Plane Register back to zero: ****/
701 GET_FIFO_SLOTS(fb
, nFreeFifoSlots
, 1);
702 NGLE_QUICK_SET_CTL_PLN_REG(fb
, 0);
708 ngleClearOverlayPlanes(struct stifb_info
*fb
, int mask
, int data
)
710 int nFreeFifoSlots
= 0;
717 GET_FIFO_SLOTS(fb
, nFreeFifoSlots
, 8);
718 NGLE_QUICK_SET_DST_BM_ACCESS(fb
,
719 BA(IndexedDcd
, Otc04
, Ots08
, AddrLong
,
720 BAJustPoint(0), BINovly
, BAIndexBase(0)));
722 NGLE_SET_TRANSFERDATA(fb
, 0xffffffff); /* Write foreground color */
724 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb
, data
);
725 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb
, mask
);
728 packed_len
= (fb
->info
.var
.xres
<< 16) | fb
->info
.var
.yres
;
729 NGLE_SET_DSTXY(fb
, packed_dst
);
731 /* Write zeroes to overlay planes */
732 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb
,
733 IBOvals(RopSrc
, MaskAddrOffset(0),
734 BitmapExtent08
, StaticReg(0),
735 DataDynamic
, MaskOtc
, BGx(0), FGx(0)));
737 SET_LENXY_START_RECFILL(fb
, packed_len
);
743 hyperResetPlanes(struct stifb_info
*fb
, int enable
)
745 unsigned int controlPlaneReg
;
749 if (IS_24_DEVICE(fb
))
750 if (fb
->info
.var
.bits_per_pixel
== 32)
751 controlPlaneReg
= 0x04000F00;
753 controlPlaneReg
= 0x00000F00; /* 0x00000800 should be enought, but lets clear all 4 bits */
755 controlPlaneReg
= 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
760 if (IS_24_DEVICE(fb
))
761 ngleDepth24_ClearImagePlanes(fb
);
763 ngleDepth8_ClearImagePlanes(fb
);
765 /* Paint attribute planes for default case.
766 * On Hyperdrive, this means all windows using overlay cmap 0. */
767 ngleResetAttrPlanes(fb
, controlPlaneReg
);
769 /* clear overlay planes */
770 ngleClearOverlayPlanes(fb
, 0xff, 255);
772 /**************************************************
773 ** Also need to counteract ITE settings
774 **************************************************/
780 if (IS_24_DEVICE(fb
))
781 ngleDepth24_ClearImagePlanes(fb
);
783 ngleDepth8_ClearImagePlanes(fb
);
784 ngleResetAttrPlanes(fb
, controlPlaneReg
);
785 ngleClearOverlayPlanes(fb
, 0xff, 0);
790 ngleResetAttrPlanes(fb
, controlPlaneReg
);
797 /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
800 ngleGetDeviceRomData(struct stifb_info
*fb
)
804 int *pBytePerLongDevDepData
;/* data byte == LSB */
806 NgleDevRomData
*pPackedDevRomData
;
807 int sizePackedDevRomData
= sizeof(*pPackedDevRomData
);
810 char *mapOrigin
= NULL
;
814 pPackedDevRomData
= fb
->ngle_rom
;
817 if (fb
->id
== S9000_ID_ARTIST
) {
818 pPackedDevRomData
->cursor_pipeline_delay
= 4;
819 pPackedDevRomData
->video_interleaves
= 4;
821 /* Get pointer to unpacked byte/long data in ROM */
822 pBytePerLongDevDepData
= fb
->sti
->regions
[NGLEDEVDEPROM_CRT_REGION
];
824 /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
825 if (fb
->id
== S9000_ID_TOMCAT
)
827 /* jump to the correct ROM table */
828 GET_ROMTABLE_INDEX(romTableIdx
);
829 while (romTableIdx
> 0)
831 pCard8
= (Card8
*) pPackedDevRomData
;
832 pRomTable
= pBytePerLongDevDepData
;
833 /* Pack every fourth byte from ROM into structure */
834 for (i
= 0; i
< sizePackedDevRomData
; i
++)
836 *pCard8
++ = (Card8
) (*pRomTable
++);
839 pBytePerLongDevDepData
= (Card32
*)
840 ((Card8
*) pBytePerLongDevDepData
+
841 pPackedDevRomData
->sizeof_ngle_data
);
847 pCard8
= (Card8
*) pPackedDevRomData
;
849 /* Pack every fourth byte from ROM into structure */
850 for (i
= 0; i
< sizePackedDevRomData
; i
++)
852 *pCard8
++ = (Card8
) (*pBytePerLongDevDepData
++);
861 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
862 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8
863 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10
864 #define HYPERBOWL_MODE2_8_24 15
866 /* HCRX specific boot-time initialization */
868 SETUP_HCRX(struct stifb_info
*fb
)
871 int nFreeFifoSlots
= 0;
873 if (fb
->id
!= S9000_ID_HCRX
)
876 /* Initialize Hyperbowl registers */
877 GET_FIFO_SLOTS(fb
, nFreeFifoSlots
, 7);
879 if (IS_24_DEVICE(fb
)) {
880 hyperbowl
= (fb
->info
.var
.bits_per_pixel
== 32) ?
881 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE
:
882 HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE
;
884 /* First write to Hyperbowl must happen twice (bug) */
885 WRITE_WORD(hyperbowl
, fb
, REG_40
);
886 WRITE_WORD(hyperbowl
, fb
, REG_40
);
888 WRITE_WORD(HYPERBOWL_MODE2_8_24
, fb
, REG_39
);
890 WRITE_WORD(0x014c0148, fb
, REG_42
); /* Set lut 0 to be the direct color */
891 WRITE_WORD(0x404c4048, fb
, REG_43
);
892 WRITE_WORD(0x034c0348, fb
, REG_44
);
893 WRITE_WORD(0x444c4448, fb
, REG_45
);
895 hyperbowl
= HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES
;
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(0x00000000, fb
, REG_42
);
902 WRITE_WORD(0x00000000, fb
, REG_43
);
903 WRITE_WORD(0x00000000, fb
, REG_44
);
904 WRITE_WORD(0x444c4048, fb
, REG_45
);
909 /* ------------------- driver specific functions --------------------------- */
911 #define TMPBUFLEN 2048
914 stifb_read(struct file
*file
, char *buf
, size_t count
, loff_t
*ppos
)
916 unsigned long p
= *ppos
;
917 struct inode
*inode
= file
->f_dentry
->d_inode
;
918 int fbidx
= iminor(inode
);
919 struct fb_info
*info
= registered_fb
[fbidx
];
920 char tmpbuf
[TMPBUFLEN
];
922 if (!info
|| ! info
->screen_base
)
925 if (p
>= info
->fix
.smem_len
)
927 if (count
>= info
->fix
.smem_len
)
928 count
= info
->fix
.smem_len
;
929 if (count
+ p
> info
->fix
.smem_len
)
930 count
= info
->fix
.smem_len
- p
;
931 if (count
> sizeof(tmpbuf
))
932 count
= sizeof(tmpbuf
);
936 base_addr
= info
->screen_base
;
937 memcpy_fromio(&tmpbuf
, base_addr
+p
, count
);
938 count
-= copy_to_user(buf
, &tmpbuf
, count
);
947 stifb_write(struct file
*file
, const char *buf
, size_t count
, loff_t
*ppos
)
949 struct inode
*inode
= file
->f_dentry
->d_inode
;
950 int fbidx
= iminor(inode
);
951 struct fb_info
*info
= registered_fb
[fbidx
];
952 unsigned long p
= *ppos
;
955 char tmpbuf
[TMPBUFLEN
];
957 if (!info
|| !info
->screen_base
)
960 if (p
> info
->fix
.smem_len
)
962 if (count
>= info
->fix
.smem_len
)
963 count
= info
->fix
.smem_len
;
965 if (count
+ p
> info
->fix
.smem_len
) {
966 count
= info
->fix
.smem_len
- p
;
970 p
+= (unsigned long)info
->screen_base
;
973 int len
= c
> sizeof(tmpbuf
) ? sizeof(tmpbuf
) : c
;
975 if (copy_from_user(&tmpbuf
, buf
, len
))
977 memcpy_toio(p
, &tmpbuf
, len
);
989 stifb_setcolreg(u_int regno
, u_int red
, u_int green
,
990 u_int blue
, u_int transp
, struct fb_info
*info
)
992 struct stifb_info
*fb
= (struct stifb_info
*) info
;
995 if (regno
>= NR_PALETTE
)
1004 START_IMAGE_COLORMAP_ACCESS(fb
);
1006 if (unlikely(fb
->info
.var
.grayscale
)) {
1007 /* gray = 0.30*R + 0.59*G + 0.11*B */
1008 color
= ((red
* 77) +
1012 color
= ((red
<< 16) |
1017 if (fb
->info
.fix
.visual
== FB_VISUAL_DIRECTCOLOR
) {
1018 struct fb_var_screeninfo
*var
= &fb
->info
.var
;
1020 ((u32
*)fb
->info
.pseudo_palette
)[regno
] =
1021 regno
<< var
->red
.offset
|
1022 regno
<< var
->green
.offset
|
1023 regno
<< var
->blue
.offset
;
1026 WRITE_IMAGE_COLOR(fb
, regno
, color
);
1028 if (fb
->id
== S9000_ID_HCRX
) {
1029 NgleLutBltCtl lutBltCtl
;
1031 lutBltCtl
= setHyperLutBltCtl(fb
,
1032 0, /* Offset w/i LUT */
1033 256); /* Load entire LUT */
1034 NGLE_BINC_SET_SRCADDR(fb
,
1035 NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
1036 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
1037 START_COLORMAPLOAD(fb
, lutBltCtl
.all
);
1040 /* cleanup colormap hardware */
1041 FINISH_IMAGE_COLORMAP_ACCESS(fb
);
1050 stifb_blank(int blank_mode
, struct fb_info
*info
)
1052 struct stifb_info
*fb
= (struct stifb_info
*) info
;
1053 int enable
= (blank_mode
== 0) ? ENABLE
: DISABLE
;
1056 case S9000_ID_A1439A
:
1057 CRX24_ENABLE_DISABLE_DISPLAY(fb
, enable
);
1059 case CRT_ID_VISUALIZE_EG
:
1060 case S9000_ID_ARTIST
:
1061 ARTIST_ENABLE_DISABLE_DISPLAY(fb
, enable
);
1064 HYPER_ENABLE_DISABLE_DISPLAY(fb
, enable
);
1066 case S9000_ID_A1659A
: /* fall through */
1067 case S9000_ID_TIMBER
:
1068 case CRX24_OVERLAY_PLANES
:
1070 ENABLE_DISABLE_DISPLAY(fb
, enable
);
1079 stifb_init_display(struct stifb_info
*fb
)
1085 /* HCRX specific initialization */
1089 if (id == S9000_ID_HCRX)
1090 hyperInitSprite(fb);
1095 /* Initialize the image planes. */
1098 hyperResetPlanes(fb
, ENABLE
);
1100 case S9000_ID_A1439A
:
1101 rattlerSetupPlanes(fb
);
1103 case S9000_ID_A1659A
:
1104 case S9000_ID_ARTIST
:
1105 case CRT_ID_VISUALIZE_EG
:
1110 /* Clear attribute planes on non HCRX devices. */
1112 case S9000_ID_A1659A
:
1113 case S9000_ID_A1439A
:
1114 if (fb
->info
.var
.bits_per_pixel
== 32)
1115 ngleSetupAttrPlanes(fb
, BUFF1_CMAP3
);
1117 ngleSetupAttrPlanes(fb
, BUFF1_CMAP0
);
1119 if (id
== S9000_ID_A1439A
)
1120 ngleClearOverlayPlanes(fb
, 0xff, 0);
1122 case S9000_ID_ARTIST
:
1123 case CRT_ID_VISUALIZE_EG
:
1124 if (fb
->info
.var
.bits_per_pixel
== 32)
1125 ngleSetupAttrPlanes(fb
, BUFF1_CMAP3
);
1127 ngleSetupAttrPlanes(fb
, ARTIST_CMAP0
);
1131 stifb_blank(0, (struct fb_info
*)fb
); /* 0=enable screen */
1136 /* ------------ Interfaces to hardware functions ------------ */
1138 static struct fb_ops stifb_ops
= {
1139 .owner
= THIS_MODULE
,
1140 .fb_read
= stifb_read
,
1141 .fb_write
= stifb_write
,
1142 .fb_setcolreg
= stifb_setcolreg
,
1143 .fb_blank
= stifb_blank
,
1144 .fb_fillrect
= cfb_fillrect
,
1145 .fb_copyarea
= cfb_copyarea
,
1146 .fb_imageblit
= cfb_imageblit
,
1155 stifb_init_fb(struct sti_struct
*sti
, int bpp_pref
)
1157 struct fb_fix_screeninfo
*fix
;
1158 struct fb_var_screeninfo
*var
;
1159 struct stifb_info
*fb
;
1160 struct fb_info
*info
;
1161 unsigned long sti_rom_address
;
1163 int bpp
, xres
, yres
;
1165 fb
= kmalloc(sizeof(*fb
), GFP_ATOMIC
);
1167 printk(KERN_ERR
"stifb: Could not allocate stifb structure\n");
1173 /* set struct to a known state */
1174 memset(fb
, 0, sizeof(*fb
));
1179 /* store upper 32bits of the graphics id */
1180 fb
->id
= fb
->sti
->graphics_id
[0];
1182 /* only supported cards are allowed */
1184 case CRT_ID_VISUALIZE_EG
:
1185 /* look for a double buffering device like e.g. the
1186 "INTERNAL_EG_DX1024" in the RDI precisionbook laptop
1187 which won't work. The same device in non-double
1188 buffering mode returns "INTERNAL_EG_X1024". */
1189 if (strstr(sti
->outptr
.dev_name
, "EG_DX")) {
1191 "stifb: ignoring '%s'. Disable double buffering in IPL menu.\n",
1192 sti
->outptr
.dev_name
);
1196 case S9000_ID_ARTIST
:
1198 case S9000_ID_TIMBER
:
1199 case S9000_ID_A1659A
:
1200 case S9000_ID_A1439A
:
1203 printk(KERN_WARNING
"stifb: '%s' (id: 0x%08x) not supported.\n",
1204 sti
->outptr
.dev_name
, fb
->id
);
1208 /* default to 8 bpp on most graphic chips */
1210 xres
= sti_onscreen_x(fb
->sti
);
1211 yres
= sti_onscreen_y(fb
->sti
);
1213 ngleGetDeviceRomData(fb
);
1215 /* get (virtual) io region base addr */
1216 fix
->mmio_start
= REGION_BASE(fb
,2);
1217 fix
->mmio_len
= 0x400000;
1219 /* Reject any device not in the NGLE family */
1221 case S9000_ID_A1659A
: /* CRX/A1659A */
1223 case S9000_ID_ELM
: /* GRX, grayscale but else same as A1659A */
1225 fb
->id
= S9000_ID_A1659A
;
1227 case S9000_ID_TIMBER
: /* HP9000/710 Any (may be a grayscale device) */
1228 dev_name
= fb
->sti
->outptr
.dev_name
;
1229 if (strstr(dev_name
, "GRAYSCALE") ||
1230 strstr(dev_name
, "Grayscale") ||
1231 strstr(dev_name
, "grayscale"))
1234 case S9000_ID_TOMCAT
: /* Dual CRX, behaves else like a CRX */
1235 /* FIXME: TomCat supports two heads:
1236 * fb.iobase = REGION_BASE(fb_info,3);
1237 * fb.screen_base = (void*) REGION_BASE(fb_info,2);
1238 * for now we only support the left one ! */
1239 xres
= fb
->ngle_rom
.x_size_visible
;
1240 yres
= fb
->ngle_rom
.y_size_visible
;
1241 fb
->id
= S9000_ID_A1659A
;
1243 case S9000_ID_A1439A
: /* CRX24/A1439A */
1246 case S9000_ID_HCRX
: /* Hyperdrive/HCRX */
1247 memset(&fb
->ngle_rom
, 0, sizeof(fb
->ngle_rom
));
1248 if ((fb
->sti
->regions_phys
[0] & 0xfc000000) ==
1249 (fb
->sti
->regions_phys
[2] & 0xfc000000))
1250 sti_rom_address
= F_EXTEND(fb
->sti
->regions_phys
[0]);
1252 sti_rom_address
= F_EXTEND(fb
->sti
->regions_phys
[1]);
1254 fb
->deviceSpecificConfig
= gsc_readl(sti_rom_address
);
1255 if (IS_24_DEVICE(fb
)) {
1256 if (bpp_pref
== 8 || bpp_pref
== 32)
1262 READ_WORD(fb
, REG_15
);
1265 case CRT_ID_VISUALIZE_EG
:
1266 case S9000_ID_ARTIST
: /* Artist */
1269 #ifdef FALLBACK_TO_1BPP
1271 "stifb: Unsupported graphics card (id=0x%08x) "
1272 "- now trying 1bpp mode instead\n",
1274 bpp
= 1; /* default to 1 bpp */
1278 "stifb: Unsupported graphics card (id=0x%08x) "
1286 /* get framebuffer physical and virtual base addr & len (64bit ready) */
1287 fix
->smem_start
= F_EXTEND(fb
->sti
->regions_phys
[1]);
1288 fix
->smem_len
= fb
->sti
->regions
[1].region_desc
.length
* 4096;
1290 fix
->line_length
= (fb
->sti
->glob_cfg
->total_x
* bpp
) / 8;
1291 if (!fix
->line_length
)
1292 fix
->line_length
= 2048; /* default */
1294 /* limit fbsize to max visible screen size */
1295 if (fix
->smem_len
> yres
*fix
->line_length
)
1296 fix
->smem_len
= yres
*fix
->line_length
;
1298 fix
->accel
= FB_ACCEL_NONE
;
1302 fix
->type
= FB_TYPE_PLANES
; /* well, sort of */
1303 fix
->visual
= FB_VISUAL_MONO10
;
1304 var
->red
.length
= var
->green
.length
= var
->blue
.length
= 1;
1307 fix
->type
= FB_TYPE_PACKED_PIXELS
;
1308 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
1309 var
->red
.length
= var
->green
.length
= var
->blue
.length
= 8;
1312 fix
->type
= FB_TYPE_PACKED_PIXELS
;
1313 fix
->visual
= FB_VISUAL_DIRECTCOLOR
;
1314 var
->red
.length
= var
->green
.length
= var
->blue
.length
= var
->transp
.length
= 8;
1315 var
->blue
.offset
= 0;
1316 var
->green
.offset
= 8;
1317 var
->red
.offset
= 16;
1318 var
->transp
.offset
= 24;
1324 var
->xres
= var
->xres_virtual
= xres
;
1325 var
->yres
= var
->yres_virtual
= yres
;
1326 var
->bits_per_pixel
= bpp
;
1328 strcpy(fix
->id
, "stifb");
1329 info
->fbops
= &stifb_ops
;
1330 info
->screen_base
= (void*) REGION_BASE(fb
,1);
1331 info
->flags
= FBINFO_DEFAULT
;
1332 info
->pseudo_palette
= &fb
->pseudo_palette
;
1334 /* This has to been done !!! */
1335 fb_alloc_cmap(&info
->cmap
, NR_PALETTE
, 0);
1336 stifb_init_display(fb
);
1338 if (!request_mem_region(fix
->smem_start
, fix
->smem_len
, "stifb fb")) {
1339 printk(KERN_ERR
"stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1340 fix
->smem_start
, fix
->smem_start
+fix
->smem_len
);
1344 if (!request_mem_region(fix
->mmio_start
, fix
->mmio_len
, "stifb mmio")) {
1345 printk(KERN_ERR
"stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1346 fix
->mmio_start
, fix
->mmio_start
+fix
->mmio_len
);
1350 if (register_framebuffer(&fb
->info
) < 0)
1353 sti
->info
= info
; /* save for unregister_framebuffer() */
1356 "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1361 var
->bits_per_pixel
,
1362 sti
->outptr
.dev_name
,
1370 release_mem_region(fix
->mmio_start
, fix
->mmio_len
);
1372 release_mem_region(fix
->smem_start
, fix
->smem_len
);
1374 fb_dealloc_cmap(&info
->cmap
);
1380 static int stifb_disabled __initdata
;
1383 stifb_setup(char *options
);
1388 struct sti_struct
*sti
;
1389 struct sti_struct
*def_sti
;
1393 char *option
= NULL
;
1395 if (fb_get_options("stifb", &option
))
1397 stifb_setup(option
);
1399 if (stifb_disabled
) {
1400 printk(KERN_INFO
"stifb: disabled by \"stifb=off\" kernel parameter\n");
1404 def_sti
= sti_get_rom(0);
1406 for (i
= 1; i
<= MAX_STI_ROMS
; i
++) {
1407 sti
= sti_get_rom(i
);
1410 if (sti
== def_sti
) {
1411 stifb_init_fb(sti
, stifb_bpp_pref
[i
- 1]);
1417 for (i
= 1; i
<= MAX_STI_ROMS
; i
++) {
1418 sti
= sti_get_rom(i
);
1423 stifb_init_fb(sti
, stifb_bpp_pref
[i
- 1]);
1435 struct sti_struct
*sti
;
1438 for (i
= 1; i
<= MAX_STI_ROMS
; i
++) {
1439 sti
= sti_get_rom(i
);
1443 struct fb_info
*info
= sti
->info
;
1444 unregister_framebuffer(sti
->info
);
1445 release_mem_region(info
->fix
.mmio_start
, info
->fix
.mmio_len
);
1446 release_mem_region(info
->fix
.smem_start
, info
->fix
.smem_len
);
1447 fb_dealloc_cmap(&info
->cmap
);
1455 stifb_setup(char *options
)
1459 if (!options
|| !*options
)
1462 if (strncmp(options
, "off", 3) == 0) {
1467 if (strncmp(options
, "bpp", 3) == 0) {
1469 for (i
= 0; i
< MAX_STI_ROMS
; i
++) {
1470 if (*options
++ != ':')
1472 stifb_bpp_pref
[i
] = simple_strtoul(options
, &options
, 10);
1478 __setup("stifb=", stifb_setup
);
1480 module_init(stifb_init
);
1481 module_exit(stifb_cleanup
);
1483 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1484 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1485 MODULE_LICENSE("GPL v2");