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>
68 #include <asm/grfioctl.h> /* for HP-UX compatibility */
69 #include <asm/uaccess.h>
73 /* REGION_BASE(fb_info, index) returns the virtual address for region <index> */
74 #define REGION_BASE(fb_info, index) \
75 F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index])
77 #define NGLEDEVDEPROM_CRT_REGION 1
79 #define NR_PALETTE 256
82 __s32 video_config_reg;
83 __s32 misc_video_start;
84 __s32 horiz_timing_fmt;
85 __s32 serr_timing_fmt;
86 __s32 vert_timing_fmt;
89 __s32 vtg_state_elements;
95 __s16 sizeof_ngle_data;
96 __s16 x_size_visible; /* visible screen dim in pixels */
99 __s16 cursor_pipeline_delay;
100 __s16 video_interleaves;
108 struct sti_struct *sti;
109 int deviceSpecificConfig;
110 u32 pseudo_palette[16];
113 static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
115 /* ------------------- chipset specific functions -------------------------- */
117 /* offsets to graphic-chip internal registers */
119 #define REG_1 0x000118
120 #define REG_2 0x000480
121 #define REG_3 0x0004a0
122 #define REG_4 0x000600
123 #define REG_6 0x000800
124 #define REG_8 0x000820
125 #define REG_9 0x000a04
126 #define REG_10 0x018000
127 #define REG_11 0x018004
128 #define REG_12 0x01800c
129 #define REG_13 0x018018
130 #define REG_14 0x01801c
131 #define REG_15 0x200000
132 #define REG_15b0 0x200000
133 #define REG_16b1 0x200005
134 #define REG_16b3 0x200007
135 #define REG_21 0x200218
136 #define REG_22 0x0005a0
137 #define REG_23 0x0005c0
138 #define REG_26 0x200118
139 #define REG_27 0x200308
140 #define REG_32 0x21003c
141 #define REG_33 0x210040
142 #define REG_34 0x200008
143 #define REG_35 0x018010
144 #define REG_38 0x210020
145 #define REG_39 0x210120
146 #define REG_40 0x210130
147 #define REG_42 0x210028
148 #define REG_43 0x21002c
149 #define REG_44 0x210030
150 #define REG_45 0x210034
152 #define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg))
153 #define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg))
156 #ifndef DEBUG_STIFB_REGS
159 # define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
160 # define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
162 static int debug_on = 1;
163 # define DEBUG_OFF() debug_on=0
164 # define DEBUG_ON() debug_on=1
165 # define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
166 printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
167 __FUNCTION__, reg, value, READ_BYTE(fb,reg)); \
168 gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
169 # define WRITE_WORD(value,fb,reg) do { if (debug_on) \
170 printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
171 __FUNCTION__, reg, value, READ_WORD(fb,reg)); \
172 gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
173 #endif /* DEBUG_STIFB_REGS */
176 #define ENABLE 1 /* for enabling/disabling screen */
179 #define NGLE_LOCK(fb_info) do { } while (0)
180 #define NGLE_UNLOCK(fb_info) do { } while (0)
183 SETUP_HW(struct stifb_info *fb)
188 stat = READ_BYTE(fb, REG_15b0);
190 stat = READ_BYTE(fb, REG_15b0);
196 SETUP_FB(struct stifb_info *fb)
198 unsigned int reg10_value = 0;
203 case CRT_ID_VISUALIZE_EG:
204 case S9000_ID_ARTIST:
205 case S9000_ID_A1659A:
206 reg10_value = 0x13601000;
208 case S9000_ID_A1439A:
209 if (fb->info.var.bits_per_pixel == 32)
210 reg10_value = 0xBBA0A000;
212 reg10_value = 0x13601000;
215 if (fb->info.var.bits_per_pixel == 32)
216 reg10_value = 0xBBA0A000;
218 reg10_value = 0x13602000;
220 case S9000_ID_TIMBER:
221 case CRX24_OVERLAY_PLANES:
222 reg10_value = 0x13602000;
226 WRITE_WORD(reg10_value, fb, REG_10);
227 WRITE_WORD(0x83000300, fb, REG_14);
229 WRITE_BYTE(1, fb, REG_16b1);
233 START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
236 WRITE_WORD(0xBBE0F000, fb, REG_10);
237 WRITE_WORD(0x03000300, fb, REG_14);
238 WRITE_WORD(~0, fb, REG_13);
242 WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
245 WRITE_WORD(((0x100+index)<<2), fb, REG_3);
246 WRITE_WORD(color, fb, REG_4);
250 FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
252 WRITE_WORD(0x400, fb, REG_2);
253 if (fb->info.var.bits_per_pixel == 32) {
254 WRITE_WORD(0x83000100, fb, REG_1);
256 if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
257 WRITE_WORD(0x80000100, fb, REG_26);
259 WRITE_WORD(0x80000100, fb, REG_1);
265 SETUP_RAMDAC(struct stifb_info *fb)
268 WRITE_WORD(0x04000000, fb, 0x1020);
269 WRITE_WORD(0xff000000, fb, 0x1028);
273 CRX24_SETUP_RAMDAC(struct stifb_info *fb)
276 WRITE_WORD(0x04000000, fb, 0x1000);
277 WRITE_WORD(0x02000000, fb, 0x1004);
278 WRITE_WORD(0xff000000, fb, 0x1008);
279 WRITE_WORD(0x05000000, fb, 0x1000);
280 WRITE_WORD(0x02000000, fb, 0x1004);
281 WRITE_WORD(0x03000000, fb, 0x1008);
286 HCRX_SETUP_RAMDAC(struct stifb_info *fb)
288 WRITE_WORD(0xffffffff, fb, REG_32);
293 CRX24_SET_OVLY_MASK(struct stifb_info *fb)
296 WRITE_WORD(0x13a02000, fb, REG_11);
297 WRITE_WORD(0x03000300, fb, REG_14);
298 WRITE_WORD(0x000017f0, fb, REG_3);
299 WRITE_WORD(0xffffffff, fb, REG_13);
300 WRITE_WORD(0xffffffff, fb, REG_22);
301 WRITE_WORD(0x00000000, fb, REG_23);
305 ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
307 unsigned int value = enable ? 0x43000000 : 0x03000000;
309 WRITE_WORD(0x06000000, fb, 0x1030);
310 WRITE_WORD(value, fb, 0x1038);
314 CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
316 unsigned int value = enable ? 0x10000000 : 0x30000000;
318 WRITE_WORD(0x01000000, fb, 0x1000);
319 WRITE_WORD(0x02000000, fb, 0x1004);
320 WRITE_WORD(value, fb, 0x1008);
324 ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
326 u32 DregsMiscVideo = REG_21;
327 u32 DregsMiscCtl = REG_27;
331 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
332 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl);
334 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
335 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl);
339 #define GET_ROMTABLE_INDEX(fb) \
340 (READ_BYTE(fb, REG_16b3) - 1)
342 #define HYPER_CONFIG_PLANES_24 0x00000100
344 #define IS_24_DEVICE(fb) \
345 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
347 #define IS_888_DEVICE(fb) \
348 (!(IS_24_DEVICE(fb)))
350 #define GET_FIFO_SLOTS(fb, cnt, numslots) \
351 { while (cnt < numslots) \
352 cnt = READ_WORD(fb, REG_34); \
356 #define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
357 #define Otc04 2 /* Pixels in each longword transfer (4) */
358 #define Otc32 5 /* Pixels in each longword transfer (32) */
359 #define Ots08 3 /* Each pixel is size (8)d transfer (1) */
360 #define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */
361 #define AddrLong 5 /* FB address is Long aligned (pixel) */
362 #define BINovly 0x2 /* 8 bit overlay */
363 #define BINapp0I 0x0 /* Application Buffer 0, Indexed */
364 #define BINapp1I 0x1 /* Application Buffer 1, Indexed */
365 #define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */
366 #define BINattr 0xd /* Attribute Bitmap */
368 #define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */
369 #define BitmapExtent32 5 /* Each write hits (32) bits in depth */
370 #define DataDynamic 0 /* Data register reloaded by direct access */
371 #define MaskDynamic 1 /* Mask register reloaded by direct access */
372 #define MaskOtc 0 /* Mask contains Object Count valid bits */
374 #define MaskAddrOffset(offset) (offset)
375 #define StaticReg(en) (en)
379 #define BAJustPoint(offset) (offset)
380 #define BAIndexBase(base) (base)
381 #define BA(F,C,S,A,J,B,I) \
382 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
384 #define IBOvals(R,M,X,S,D,L,B,F) \
385 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
387 #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
388 WRITE_WORD(val, fb, REG_14)
390 #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
391 WRITE_WORD(val, fb, REG_11)
393 #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
394 WRITE_WORD(val, fb, REG_12)
396 #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
397 WRITE_WORD(plnmsk32, fb, REG_13)
399 #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
400 WRITE_WORD(fg32, fb, REG_35)
402 #define NGLE_SET_TRANSFERDATA(fb, val) \
403 WRITE_WORD(val, fb, REG_8)
405 #define NGLE_SET_DSTXY(fb, val) \
406 WRITE_WORD(val, fb, REG_6)
408 #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
409 (u32) (fbaddrbase) + \
410 ( (unsigned int) ( (y) << 13 ) | \
411 (unsigned int) ( (x) << 2 ) ) \
414 #define NGLE_BINC_SET_DSTADDR(fb, addr) \
415 WRITE_WORD(addr, fb, REG_3)
417 #define NGLE_BINC_SET_SRCADDR(fb, addr) \
418 WRITE_WORD(addr, fb, REG_2)
420 #define NGLE_BINC_SET_DSTMASK(fb, mask) \
421 WRITE_WORD(mask, fb, REG_22)
423 #define NGLE_BINC_WRITE32(fb, data32) \
424 WRITE_WORD(data32, fb, REG_23)
426 #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
427 WRITE_WORD((cmapBltCtlData32), fb, REG_38)
429 #define SET_LENXY_START_RECFILL(fb, lenxy) \
430 WRITE_WORD(lenxy, fb, REG_9)
433 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
435 u32 DregsHypMiscVideo = REG_33;
438 value = READ_WORD(fb, DregsHypMiscVideo);
442 value &= ~0x0A000000;
443 WRITE_WORD(value, fb, DregsHypMiscVideo);
447 /* BufferNumbers used by SETUP_ATTR_ACCESS() */
448 #define BUFF0_CMAP0 0x00001e02
449 #define BUFF1_CMAP0 0x02001e02
450 #define BUFF1_CMAP3 0x0c001e02
451 #define ARTIST_CMAP0 0x00000102
452 #define HYPER_CMAP8 0x00000100
453 #define HYPER_CMAP24 0x00000800
456 SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
459 WRITE_WORD(0x2EA0D000, fb, REG_11);
460 WRITE_WORD(0x23000302, fb, REG_14);
461 WRITE_WORD(BufferNumber, fb, REG_12);
462 WRITE_WORD(0xffffffff, fb, REG_8);
466 SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
468 /* REG_6 seems to have special values when run on a
469 RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
470 INTERNAL_EG_X1024). The values are:
471 0x2f0: internal (LCD) & external display enabled
472 0x2a0: external display only
473 0x000: zero on standard artist graphic cards
475 WRITE_WORD(0x00000000, fb, REG_6);
476 WRITE_WORD((width<<16) | height, fb, REG_9);
477 WRITE_WORD(0x05000000, fb, REG_6);
478 WRITE_WORD(0x00040001, fb, REG_9);
482 FINISH_ATTR_ACCESS(struct stifb_info *fb)
485 WRITE_WORD(0x00000000, fb, REG_12);
489 elkSetupPlanes(struct stifb_info *fb)
496 ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
498 SETUP_ATTR_ACCESS(fb, BufferNumber);
499 SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
500 FINISH_ATTR_ACCESS(fb);
506 rattlerSetupPlanes(struct stifb_info *fb)
510 /* Write RAMDAC pixel read mask register so all overlay
511 * planes are display-enabled. (CRX24 uses Bt462 pixel
512 * read mask register for overlay planes, not image planes).
514 CRX24_SETUP_RAMDAC(fb);
516 /* change fb->id temporarily to fool SETUP_FB() */
518 fb->id = CRX24_OVERLAY_PLANES;
522 for (y = 0; y < fb->info.var.yres; ++y)
523 memset(fb->info.screen_base + y * fb->info.fix.line_length,
524 0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8);
526 CRX24_SET_OVLY_MASK(fb);
531 #define HYPER_CMAP_TYPE 0
532 #define NGLE_CMAP_INDEXED0_TYPE 0
533 #define NGLE_CMAP_OVERLAY_TYPE 3
535 /* typedef of LUT (Colormap) BLT Control Register */
536 typedef union /* Note assumption that fields are packed left-to-right */
541 unsigned waitBlank : 1;
542 unsigned reserved1 : 4;
543 unsigned lutOffset : 10; /* Within destination LUT */
544 unsigned lutType : 2; /* Cursor, image, overlay */
545 unsigned reserved2 : 4;
546 unsigned length : 10;
553 setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
555 NgleLutBltCtl lutBltCtl;
557 /* set enable, zero reserved fields */
558 lutBltCtl.all = 0x80000000;
559 lutBltCtl.fields.length = length;
563 case S9000_ID_A1439A: /* CRX24 */
564 if (fb->var.bits_per_pixel == 8) {
565 lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
566 lutBltCtl.fields.lutOffset = 0;
568 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
569 lutBltCtl.fields.lutOffset = 0 * 256;
573 case S9000_ID_ARTIST:
574 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
575 lutBltCtl.fields.lutOffset = 0 * 256;
579 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
580 lutBltCtl.fields.lutOffset = 0;
584 /* Offset points to start of LUT. Adjust for within LUT */
585 lutBltCtl.fields.lutOffset += offsetWithinLut;
592 setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
594 NgleLutBltCtl lutBltCtl;
596 /* set enable, zero reserved fields */
597 lutBltCtl.all = 0x80000000;
599 lutBltCtl.fields.length = length;
600 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
602 /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
603 if (fb->info.var.bits_per_pixel == 8)
604 lutBltCtl.fields.lutOffset = 2 * 256;
606 lutBltCtl.fields.lutOffset = 0 * 256;
608 /* Offset points to start of LUT. Adjust for within LUT */
609 lutBltCtl.fields.lutOffset += offsetWithinLut;
615 static void hyperUndoITE(struct stifb_info *fb)
617 int nFreeFifoSlots = 0;
622 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
623 WRITE_WORD(0xffffffff, fb, REG_32);
625 /* Write overlay transparency mask so only entry 255 is transparent */
627 /* Hardware setup for full-depth write to "magic" location */
628 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
629 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
630 BA(IndexedDcd, Otc04, Ots08, AddrLong,
631 BAJustPoint(0), BINovly, BAIndexBase(0)));
632 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
633 IBOvals(RopSrc, MaskAddrOffset(0),
634 BitmapExtent08, StaticReg(0),
635 DataDynamic, MaskOtc, BGx(0), FGx(0)));
637 /* Now prepare to write to the "magic" location */
638 fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
639 NGLE_BINC_SET_DSTADDR(fb, fbAddr);
640 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
641 NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
643 /* Finally, write a zero to clear the mask */
644 NGLE_BINC_WRITE32(fb, 0);
650 ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
656 ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
662 ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
664 int nFreeFifoSlots = 0;
670 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
671 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
672 BA(IndexedDcd, Otc32, OtsIndirect,
673 AddrLong, BAJustPoint(0),
674 BINattr, BAIndexBase(0)));
675 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
676 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
678 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
679 IBOvals(RopSrc, MaskAddrOffset(0),
680 BitmapExtent08, StaticReg(1),
681 DataDynamic, MaskOtc,
684 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
685 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
686 NGLE_SET_DSTXY(fb, packed_dst);
687 SET_LENXY_START_RECFILL(fb, packed_len);
690 * In order to work around an ELK hardware problem (Buffy doesn't
691 * always flush it's buffers when writing to the attribute
692 * planes), at least 4 pixels must be written to the attribute
693 * planes starting at (X == 1280) and (Y != to the last Y written
697 if (fb->id == S9000_ID_A1659A) { /* ELK_DEVICE_ID */
698 /* It's safe to use scanline zero: */
699 packed_dst = (1280 << 16);
700 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
701 NGLE_SET_DSTXY(fb, packed_dst);
702 packed_len = (4 << 16) | 1;
703 SET_LENXY_START_RECFILL(fb, packed_len);
704 } /* ELK Hardware Kludge */
706 /**** Finally, set the Control Plane Register back to zero: ****/
707 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
708 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
714 ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
716 int nFreeFifoSlots = 0;
723 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
724 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
725 BA(IndexedDcd, Otc04, Ots08, AddrLong,
726 BAJustPoint(0), BINovly, BAIndexBase(0)));
728 NGLE_SET_TRANSFERDATA(fb, 0xffffffff); /* Write foreground color */
730 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
731 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
734 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
735 NGLE_SET_DSTXY(fb, packed_dst);
737 /* Write zeroes to overlay planes */
738 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
739 IBOvals(RopSrc, MaskAddrOffset(0),
740 BitmapExtent08, StaticReg(0),
741 DataDynamic, MaskOtc, BGx(0), FGx(0)));
743 SET_LENXY_START_RECFILL(fb, packed_len);
749 hyperResetPlanes(struct stifb_info *fb, int enable)
751 unsigned int controlPlaneReg;
755 if (IS_24_DEVICE(fb))
756 if (fb->info.var.bits_per_pixel == 32)
757 controlPlaneReg = 0x04000F00;
759 controlPlaneReg = 0x00000F00; /* 0x00000800 should be enought, but lets clear all 4 bits */
761 controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
766 if (IS_24_DEVICE(fb))
767 ngleDepth24_ClearImagePlanes(fb);
769 ngleDepth8_ClearImagePlanes(fb);
771 /* Paint attribute planes for default case.
772 * On Hyperdrive, this means all windows using overlay cmap 0. */
773 ngleResetAttrPlanes(fb, controlPlaneReg);
775 /* clear overlay planes */
776 ngleClearOverlayPlanes(fb, 0xff, 255);
778 /**************************************************
779 ** Also need to counteract ITE settings
780 **************************************************/
786 if (IS_24_DEVICE(fb))
787 ngleDepth24_ClearImagePlanes(fb);
789 ngleDepth8_ClearImagePlanes(fb);
790 ngleResetAttrPlanes(fb, controlPlaneReg);
791 ngleClearOverlayPlanes(fb, 0xff, 0);
796 ngleResetAttrPlanes(fb, controlPlaneReg);
803 /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
806 ngleGetDeviceRomData(struct stifb_info *fb)
810 int *pBytePerLongDevDepData;/* data byte == LSB */
812 NgleDevRomData *pPackedDevRomData;
813 int sizePackedDevRomData = sizeof(*pPackedDevRomData);
816 char *mapOrigin = NULL;
820 pPackedDevRomData = fb->ngle_rom;
823 if (fb->id == S9000_ID_ARTIST) {
824 pPackedDevRomData->cursor_pipeline_delay = 4;
825 pPackedDevRomData->video_interleaves = 4;
827 /* Get pointer to unpacked byte/long data in ROM */
828 pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
830 /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
831 if (fb->id == S9000_ID_TOMCAT)
833 /* jump to the correct ROM table */
834 GET_ROMTABLE_INDEX(romTableIdx);
835 while (romTableIdx > 0)
837 pCard8 = (Card8 *) pPackedDevRomData;
838 pRomTable = pBytePerLongDevDepData;
839 /* Pack every fourth byte from ROM into structure */
840 for (i = 0; i < sizePackedDevRomData; i++)
842 *pCard8++ = (Card8) (*pRomTable++);
845 pBytePerLongDevDepData = (Card32 *)
846 ((Card8 *) pBytePerLongDevDepData +
847 pPackedDevRomData->sizeof_ngle_data);
853 pCard8 = (Card8 *) pPackedDevRomData;
855 /* Pack every fourth byte from ROM into structure */
856 for (i = 0; i < sizePackedDevRomData; i++)
858 *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
867 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
868 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8
869 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10
870 #define HYPERBOWL_MODE2_8_24 15
872 /* HCRX specific boot-time initialization */
874 SETUP_HCRX(struct stifb_info *fb)
877 int nFreeFifoSlots = 0;
879 if (fb->id != S9000_ID_HCRX)
882 /* Initialize Hyperbowl registers */
883 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
885 if (IS_24_DEVICE(fb)) {
886 hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
887 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
888 HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
890 /* First write to Hyperbowl must happen twice (bug) */
891 WRITE_WORD(hyperbowl, fb, REG_40);
892 WRITE_WORD(hyperbowl, fb, REG_40);
894 WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
896 WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
897 WRITE_WORD(0x404c4048, fb, REG_43);
898 WRITE_WORD(0x034c0348, fb, REG_44);
899 WRITE_WORD(0x444c4448, fb, REG_45);
901 hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
903 /* First write to Hyperbowl must happen twice (bug) */
904 WRITE_WORD(hyperbowl, fb, REG_40);
905 WRITE_WORD(hyperbowl, fb, REG_40);
907 WRITE_WORD(0x00000000, fb, REG_42);
908 WRITE_WORD(0x00000000, fb, REG_43);
909 WRITE_WORD(0x00000000, fb, REG_44);
910 WRITE_WORD(0x444c4048, fb, REG_45);
915 /* ------------------- driver specific functions --------------------------- */
918 stifb_setcolreg(u_int regno, u_int red, u_int green,
919 u_int blue, u_int transp, struct fb_info *info)
921 struct stifb_info *fb = (struct stifb_info *) info;
924 if (regno >= NR_PALETTE)
933 START_IMAGE_COLORMAP_ACCESS(fb);
935 if (unlikely(fb->info.var.grayscale)) {
936 /* gray = 0.30*R + 0.59*G + 0.11*B */
937 color = ((red * 77) +
941 color = ((red << 16) |
946 if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
947 struct fb_var_screeninfo *var = &fb->info.var;
949 ((u32 *)fb->info.pseudo_palette)[regno] =
950 regno << var->red.offset |
951 regno << var->green.offset |
952 regno << var->blue.offset;
955 WRITE_IMAGE_COLOR(fb, regno, color);
957 if (fb->id == S9000_ID_HCRX) {
958 NgleLutBltCtl lutBltCtl;
960 lutBltCtl = setHyperLutBltCtl(fb,
961 0, /* Offset w/i LUT */
962 256); /* Load entire LUT */
963 NGLE_BINC_SET_SRCADDR(fb,
964 NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
965 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
966 START_COLORMAPLOAD(fb, lutBltCtl.all);
969 /* cleanup colormap hardware */
970 FINISH_IMAGE_COLORMAP_ACCESS(fb);
979 stifb_blank(int blank_mode, struct fb_info *info)
981 struct stifb_info *fb = (struct stifb_info *) info;
982 int enable = (blank_mode == 0) ? ENABLE : DISABLE;
985 case S9000_ID_A1439A:
986 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
988 case CRT_ID_VISUALIZE_EG:
989 case S9000_ID_ARTIST:
990 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
993 HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
995 case S9000_ID_A1659A: /* fall through */
996 case S9000_ID_TIMBER:
997 case CRX24_OVERLAY_PLANES:
999 ENABLE_DISABLE_DISPLAY(fb, enable);
1008 stifb_init_display(struct stifb_info *fb)
1014 /* HCRX specific initialization */
1018 if (id == S9000_ID_HCRX)
1019 hyperInitSprite(fb);
1024 /* Initialize the image planes. */
1027 hyperResetPlanes(fb, ENABLE);
1029 case S9000_ID_A1439A:
1030 rattlerSetupPlanes(fb);
1032 case S9000_ID_A1659A:
1033 case S9000_ID_ARTIST:
1034 case CRT_ID_VISUALIZE_EG:
1039 /* Clear attribute planes on non HCRX devices. */
1041 case S9000_ID_A1659A:
1042 case S9000_ID_A1439A:
1043 if (fb->info.var.bits_per_pixel == 32)
1044 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1046 ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1048 if (id == S9000_ID_A1439A)
1049 ngleClearOverlayPlanes(fb, 0xff, 0);
1051 case S9000_ID_ARTIST:
1052 case CRT_ID_VISUALIZE_EG:
1053 if (fb->info.var.bits_per_pixel == 32)
1054 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1056 ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1060 stifb_blank(0, (struct fb_info *)fb); /* 0=enable screen */
1065 /* ------------ Interfaces to hardware functions ------------ */
1067 static struct fb_ops stifb_ops = {
1068 .owner = THIS_MODULE,
1069 .fb_setcolreg = stifb_setcolreg,
1070 .fb_blank = stifb_blank,
1071 .fb_fillrect = cfb_fillrect,
1072 .fb_copyarea = cfb_copyarea,
1073 .fb_imageblit = cfb_imageblit,
1082 stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1084 struct fb_fix_screeninfo *fix;
1085 struct fb_var_screeninfo *var;
1086 struct stifb_info *fb;
1087 struct fb_info *info;
1088 unsigned long sti_rom_address;
1090 int bpp, xres, yres;
1092 fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
1094 printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
1100 /* set struct to a known state */
1105 /* store upper 32bits of the graphics id */
1106 fb->id = fb->sti->graphics_id[0];
1108 /* only supported cards are allowed */
1110 case CRT_ID_VISUALIZE_EG:
1111 /* Visualize cards can run either in "double buffer" or
1112 "standard" mode. Depending on the mode, the card reports
1113 a different device name, e.g. "INTERNAL_EG_DX1024" in double
1114 buffer mode and "INTERNAL_EG_X1024" in standard mode.
1115 Since this driver only supports standard mode, we check
1116 if the device name contains the string "DX" and tell the
1117 user how to reconfigure the card. */
1118 if (strstr(sti->outptr.dev_name, "DX")) {
1119 printk(KERN_WARNING "WARNING: stifb framebuffer driver does not "
1120 "support '%s' in double-buffer mode.\n"
1121 KERN_WARNING "WARNING: Please disable the double-buffer mode "
1122 "in IPL menu (the PARISC-BIOS).\n",
1123 sti->outptr.dev_name);
1127 case S9000_ID_ARTIST:
1129 case S9000_ID_TIMBER:
1130 case S9000_ID_A1659A:
1131 case S9000_ID_A1439A:
1134 printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1135 sti->outptr.dev_name, fb->id);
1139 /* default to 8 bpp on most graphic chips */
1141 xres = sti_onscreen_x(fb->sti);
1142 yres = sti_onscreen_y(fb->sti);
1144 ngleGetDeviceRomData(fb);
1146 /* get (virtual) io region base addr */
1147 fix->mmio_start = REGION_BASE(fb,2);
1148 fix->mmio_len = 0x400000;
1150 /* Reject any device not in the NGLE family */
1152 case S9000_ID_A1659A: /* CRX/A1659A */
1154 case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */
1156 fb->id = S9000_ID_A1659A;
1158 case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */
1159 dev_name = fb->sti->outptr.dev_name;
1160 if (strstr(dev_name, "GRAYSCALE") ||
1161 strstr(dev_name, "Grayscale") ||
1162 strstr(dev_name, "grayscale"))
1165 case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */
1166 /* FIXME: TomCat supports two heads:
1167 * fb.iobase = REGION_BASE(fb_info,3);
1168 * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx);
1169 * for now we only support the left one ! */
1170 xres = fb->ngle_rom.x_size_visible;
1171 yres = fb->ngle_rom.y_size_visible;
1172 fb->id = S9000_ID_A1659A;
1174 case S9000_ID_A1439A: /* CRX24/A1439A */
1177 case S9000_ID_HCRX: /* Hyperdrive/HCRX */
1178 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1179 if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1180 (fb->sti->regions_phys[2] & 0xfc000000))
1181 sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1183 sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1185 fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1186 if (IS_24_DEVICE(fb)) {
1187 if (bpp_pref == 8 || bpp_pref == 32)
1193 READ_WORD(fb, REG_15);
1196 case CRT_ID_VISUALIZE_EG:
1197 case S9000_ID_ARTIST: /* Artist */
1200 #ifdef FALLBACK_TO_1BPP
1202 "stifb: Unsupported graphics card (id=0x%08x) "
1203 "- now trying 1bpp mode instead\n",
1205 bpp = 1; /* default to 1 bpp */
1209 "stifb: Unsupported graphics card (id=0x%08x) "
1217 /* get framebuffer physical and virtual base addr & len (64bit ready) */
1218 fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1219 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1221 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1222 if (!fix->line_length)
1223 fix->line_length = 2048; /* default */
1225 /* limit fbsize to max visible screen size */
1226 if (fix->smem_len > yres*fix->line_length)
1227 fix->smem_len = yres*fix->line_length;
1229 fix->accel = FB_ACCEL_NONE;
1233 fix->type = FB_TYPE_PLANES; /* well, sort of */
1234 fix->visual = FB_VISUAL_MONO10;
1235 var->red.length = var->green.length = var->blue.length = 1;
1238 fix->type = FB_TYPE_PACKED_PIXELS;
1239 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1240 var->red.length = var->green.length = var->blue.length = 8;
1243 fix->type = FB_TYPE_PACKED_PIXELS;
1244 fix->visual = FB_VISUAL_DIRECTCOLOR;
1245 var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1246 var->blue.offset = 0;
1247 var->green.offset = 8;
1248 var->red.offset = 16;
1249 var->transp.offset = 24;
1255 var->xres = var->xres_virtual = xres;
1256 var->yres = var->yres_virtual = yres;
1257 var->bits_per_pixel = bpp;
1259 strcpy(fix->id, "stifb");
1260 info->fbops = &stifb_ops;
1261 info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
1262 info->screen_size = fix->smem_len;
1263 info->flags = FBINFO_DEFAULT;
1264 info->pseudo_palette = &fb->pseudo_palette;
1266 /* This has to been done !!! */
1267 fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
1268 stifb_init_display(fb);
1270 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1271 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1272 fix->smem_start, fix->smem_start+fix->smem_len);
1276 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1277 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1278 fix->mmio_start, fix->mmio_start+fix->mmio_len);
1282 if (register_framebuffer(&fb->info) < 0)
1285 sti->info = info; /* save for unregister_framebuffer() */
1288 "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1293 var->bits_per_pixel,
1294 sti->outptr.dev_name,
1302 release_mem_region(fix->mmio_start, fix->mmio_len);
1304 release_mem_region(fix->smem_start, fix->smem_len);
1306 iounmap(info->screen_base);
1307 fb_dealloc_cmap(&info->cmap);
1313 static int stifb_disabled __initdata;
1316 stifb_setup(char *options);
1321 struct sti_struct *sti;
1322 struct sti_struct *def_sti;
1326 char *option = NULL;
1328 if (fb_get_options("stifb", &option))
1330 stifb_setup(option);
1332 if (stifb_disabled) {
1333 printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1337 def_sti = sti_get_rom(0);
1339 for (i = 1; i <= MAX_STI_ROMS; i++) {
1340 sti = sti_get_rom(i);
1343 if (sti == def_sti) {
1344 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1350 for (i = 1; i <= MAX_STI_ROMS; i++) {
1351 sti = sti_get_rom(i);
1356 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1368 struct sti_struct *sti;
1371 for (i = 1; i <= MAX_STI_ROMS; i++) {
1372 sti = sti_get_rom(i);
1376 struct fb_info *info = sti->info;
1377 unregister_framebuffer(sti->info);
1378 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1379 release_mem_region(info->fix.smem_start, info->fix.smem_len);
1380 if (info->screen_base)
1381 iounmap(info->screen_base);
1382 fb_dealloc_cmap(&info->cmap);
1390 stifb_setup(char *options)
1394 if (!options || !*options)
1397 if (strncmp(options, "off", 3) == 0) {
1402 if (strncmp(options, "bpp", 3) == 0) {
1404 for (i = 0; i < MAX_STI_ROMS; i++) {
1405 if (*options++ != ':')
1407 stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1413 __setup("stifb=", stifb_setup);
1415 module_init(stifb_init);
1416 module_exit(stifb_cleanup);
1418 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1419 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1420 MODULE_LICENSE("GPL v2");