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_7 0x000804
125 #define REG_8 0x000820
126 #define REG_9 0x000a04
127 #define REG_10 0x018000
128 #define REG_11 0x018004
129 #define REG_12 0x01800c
130 #define REG_13 0x018018
131 #define REG_14 0x01801c
132 #define REG_15 0x200000
133 #define REG_15b0 0x200000
134 #define REG_16b1 0x200005
135 #define REG_16b3 0x200007
136 #define REG_21 0x200218
137 #define REG_22 0x0005a0
138 #define REG_23 0x0005c0
139 #define REG_24 0x000808
140 #define REG_25 0x000b00
141 #define REG_26 0x200118
142 #define REG_27 0x200308
143 #define REG_32 0x21003c
144 #define REG_33 0x210040
145 #define REG_34 0x200008
146 #define REG_35 0x018010
147 #define REG_38 0x210020
148 #define REG_39 0x210120
149 #define REG_40 0x210130
150 #define REG_42 0x210028
151 #define REG_43 0x21002c
152 #define REG_44 0x210030
153 #define REG_45 0x210034
155 #define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg))
156 #define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg))
159 #ifndef DEBUG_STIFB_REGS
162 # define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
163 # define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
165 static int debug_on = 1;
166 # define DEBUG_OFF() debug_on=0
167 # define DEBUG_ON() debug_on=1
168 # define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
169 printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
170 __func__, reg, value, READ_BYTE(fb,reg)); \
171 gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
172 # define WRITE_WORD(value,fb,reg) do { if (debug_on) \
173 printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
174 __func__, reg, value, READ_WORD(fb,reg)); \
175 gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
176 #endif /* DEBUG_STIFB_REGS */
179 #define ENABLE 1 /* for enabling/disabling screen */
182 #define NGLE_LOCK(fb_info) do { } while (0)
183 #define NGLE_UNLOCK(fb_info) do { } while (0)
186 SETUP_HW(struct stifb_info *fb)
191 stat = READ_BYTE(fb, REG_15b0);
193 stat = READ_BYTE(fb, REG_15b0);
199 SETUP_FB(struct stifb_info *fb)
201 unsigned int reg10_value = 0;
206 case CRT_ID_VISUALIZE_EG:
207 case S9000_ID_ARTIST:
208 case S9000_ID_A1659A:
209 reg10_value = 0x13601000;
211 case S9000_ID_A1439A:
212 if (fb->info.var.bits_per_pixel == 32)
213 reg10_value = 0xBBA0A000;
215 reg10_value = 0x13601000;
218 if (fb->info.var.bits_per_pixel == 32)
219 reg10_value = 0xBBA0A000;
221 reg10_value = 0x13602000;
223 case S9000_ID_TIMBER:
224 case CRX24_OVERLAY_PLANES:
225 reg10_value = 0x13602000;
229 WRITE_WORD(reg10_value, fb, REG_10);
230 WRITE_WORD(0x83000300, fb, REG_14);
232 WRITE_BYTE(1, fb, REG_16b1);
236 START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
239 WRITE_WORD(0xBBE0F000, fb, REG_10);
240 WRITE_WORD(0x03000300, fb, REG_14);
241 WRITE_WORD(~0, fb, REG_13);
245 WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
248 WRITE_WORD(((0x100+index)<<2), fb, REG_3);
249 WRITE_WORD(color, fb, REG_4);
253 FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
255 WRITE_WORD(0x400, fb, REG_2);
256 if (fb->info.var.bits_per_pixel == 32) {
257 WRITE_WORD(0x83000100, fb, REG_1);
259 if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
260 WRITE_WORD(0x80000100, fb, REG_26);
262 WRITE_WORD(0x80000100, fb, REG_1);
268 SETUP_RAMDAC(struct stifb_info *fb)
271 WRITE_WORD(0x04000000, fb, 0x1020);
272 WRITE_WORD(0xff000000, fb, 0x1028);
276 CRX24_SETUP_RAMDAC(struct stifb_info *fb)
279 WRITE_WORD(0x04000000, fb, 0x1000);
280 WRITE_WORD(0x02000000, fb, 0x1004);
281 WRITE_WORD(0xff000000, fb, 0x1008);
282 WRITE_WORD(0x05000000, fb, 0x1000);
283 WRITE_WORD(0x02000000, fb, 0x1004);
284 WRITE_WORD(0x03000000, fb, 0x1008);
289 HCRX_SETUP_RAMDAC(struct stifb_info *fb)
291 WRITE_WORD(0xffffffff, fb, REG_32);
296 CRX24_SET_OVLY_MASK(struct stifb_info *fb)
299 WRITE_WORD(0x13a02000, fb, REG_11);
300 WRITE_WORD(0x03000300, fb, REG_14);
301 WRITE_WORD(0x000017f0, fb, REG_3);
302 WRITE_WORD(0xffffffff, fb, REG_13);
303 WRITE_WORD(0xffffffff, fb, REG_22);
304 WRITE_WORD(0x00000000, fb, REG_23);
308 ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
310 unsigned int value = enable ? 0x43000000 : 0x03000000;
312 WRITE_WORD(0x06000000, fb, 0x1030);
313 WRITE_WORD(value, fb, 0x1038);
317 CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
319 unsigned int value = enable ? 0x10000000 : 0x30000000;
321 WRITE_WORD(0x01000000, fb, 0x1000);
322 WRITE_WORD(0x02000000, fb, 0x1004);
323 WRITE_WORD(value, fb, 0x1008);
327 ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
329 u32 DregsMiscVideo = REG_21;
330 u32 DregsMiscCtl = REG_27;
334 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
335 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl);
337 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
338 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl);
342 #define GET_ROMTABLE_INDEX(fb) \
343 (READ_BYTE(fb, REG_16b3) - 1)
345 #define HYPER_CONFIG_PLANES_24 0x00000100
347 #define IS_24_DEVICE(fb) \
348 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
350 #define IS_888_DEVICE(fb) \
351 (!(IS_24_DEVICE(fb)))
353 #define GET_FIFO_SLOTS(fb, cnt, numslots) \
354 { while (cnt < numslots) \
355 cnt = READ_WORD(fb, REG_34); \
359 #define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
360 #define Otc04 2 /* Pixels in each longword transfer (4) */
361 #define Otc32 5 /* Pixels in each longword transfer (32) */
362 #define Ots08 3 /* Each pixel is size (8)d transfer (1) */
363 #define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */
364 #define AddrLong 5 /* FB address is Long aligned (pixel) */
365 #define BINovly 0x2 /* 8 bit overlay */
366 #define BINapp0I 0x0 /* Application Buffer 0, Indexed */
367 #define BINapp1I 0x1 /* Application Buffer 1, Indexed */
368 #define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */
369 #define BINattr 0xd /* Attribute Bitmap */
371 #define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */
372 #define BitmapExtent32 5 /* Each write hits (32) bits in depth */
373 #define DataDynamic 0 /* Data register reloaded by direct access */
374 #define MaskDynamic 1 /* Mask register reloaded by direct access */
375 #define MaskOtc 0 /* Mask contains Object Count valid bits */
377 #define MaskAddrOffset(offset) (offset)
378 #define StaticReg(en) (en)
382 #define BAJustPoint(offset) (offset)
383 #define BAIndexBase(base) (base)
384 #define BA(F,C,S,A,J,B,I) \
385 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
387 #define IBOvals(R,M,X,S,D,L,B,F) \
388 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
390 #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
391 WRITE_WORD(val, fb, REG_14)
393 #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
394 WRITE_WORD(val, fb, REG_11)
396 #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
397 WRITE_WORD(val, fb, REG_12)
399 #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
400 WRITE_WORD(plnmsk32, fb, REG_13)
402 #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
403 WRITE_WORD(fg32, fb, REG_35)
405 #define NGLE_SET_TRANSFERDATA(fb, val) \
406 WRITE_WORD(val, fb, REG_8)
408 #define NGLE_SET_DSTXY(fb, val) \
409 WRITE_WORD(val, fb, REG_6)
411 #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
412 (u32) (fbaddrbase) + \
413 ( (unsigned int) ( (y) << 13 ) | \
414 (unsigned int) ( (x) << 2 ) ) \
417 #define NGLE_BINC_SET_DSTADDR(fb, addr) \
418 WRITE_WORD(addr, fb, REG_3)
420 #define NGLE_BINC_SET_SRCADDR(fb, addr) \
421 WRITE_WORD(addr, fb, REG_2)
423 #define NGLE_BINC_SET_DSTMASK(fb, mask) \
424 WRITE_WORD(mask, fb, REG_22)
426 #define NGLE_BINC_WRITE32(fb, data32) \
427 WRITE_WORD(data32, fb, REG_23)
429 #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
430 WRITE_WORD((cmapBltCtlData32), fb, REG_38)
432 #define SET_LENXY_START_RECFILL(fb, lenxy) \
433 WRITE_WORD(lenxy, fb, REG_9)
435 #define SETUP_COPYAREA(fb) \
436 WRITE_BYTE(0, fb, REG_16b1)
439 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
441 u32 DregsHypMiscVideo = REG_33;
444 value = READ_WORD(fb, DregsHypMiscVideo);
448 value &= ~0x0A000000;
449 WRITE_WORD(value, fb, DregsHypMiscVideo);
453 /* BufferNumbers used by SETUP_ATTR_ACCESS() */
454 #define BUFF0_CMAP0 0x00001e02
455 #define BUFF1_CMAP0 0x02001e02
456 #define BUFF1_CMAP3 0x0c001e02
457 #define ARTIST_CMAP0 0x00000102
458 #define HYPER_CMAP8 0x00000100
459 #define HYPER_CMAP24 0x00000800
462 SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
465 WRITE_WORD(0x2EA0D000, fb, REG_11);
466 WRITE_WORD(0x23000302, fb, REG_14);
467 WRITE_WORD(BufferNumber, fb, REG_12);
468 WRITE_WORD(0xffffffff, fb, REG_8);
472 SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
474 /* REG_6 seems to have special values when run on a
475 RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
476 INTERNAL_EG_X1024). The values are:
477 0x2f0: internal (LCD) & external display enabled
478 0x2a0: external display only
479 0x000: zero on standard artist graphic cards
481 WRITE_WORD(0x00000000, fb, REG_6);
482 WRITE_WORD((width<<16) | height, fb, REG_9);
483 WRITE_WORD(0x05000000, fb, REG_6);
484 WRITE_WORD(0x00040001, fb, REG_9);
488 FINISH_ATTR_ACCESS(struct stifb_info *fb)
491 WRITE_WORD(0x00000000, fb, REG_12);
495 elkSetupPlanes(struct stifb_info *fb)
502 ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
504 SETUP_ATTR_ACCESS(fb, BufferNumber);
505 SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
506 FINISH_ATTR_ACCESS(fb);
512 rattlerSetupPlanes(struct stifb_info *fb)
516 /* Write RAMDAC pixel read mask register so all overlay
517 * planes are display-enabled. (CRX24 uses Bt462 pixel
518 * read mask register for overlay planes, not image planes).
520 CRX24_SETUP_RAMDAC(fb);
522 /* change fb->id temporarily to fool SETUP_FB() */
524 fb->id = CRX24_OVERLAY_PLANES;
528 for (y = 0; y < fb->info.var.yres; ++y)
529 memset(fb->info.screen_base + y * fb->info.fix.line_length,
530 0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8);
532 CRX24_SET_OVLY_MASK(fb);
537 #define HYPER_CMAP_TYPE 0
538 #define NGLE_CMAP_INDEXED0_TYPE 0
539 #define NGLE_CMAP_OVERLAY_TYPE 3
541 /* typedef of LUT (Colormap) BLT Control Register */
542 typedef union /* Note assumption that fields are packed left-to-right */
547 unsigned waitBlank : 1;
548 unsigned reserved1 : 4;
549 unsigned lutOffset : 10; /* Within destination LUT */
550 unsigned lutType : 2; /* Cursor, image, overlay */
551 unsigned reserved2 : 4;
552 unsigned length : 10;
559 setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
561 NgleLutBltCtl lutBltCtl;
563 /* set enable, zero reserved fields */
564 lutBltCtl.all = 0x80000000;
565 lutBltCtl.fields.length = length;
569 case S9000_ID_A1439A: /* CRX24 */
570 if (fb->var.bits_per_pixel == 8) {
571 lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
572 lutBltCtl.fields.lutOffset = 0;
574 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
575 lutBltCtl.fields.lutOffset = 0 * 256;
579 case S9000_ID_ARTIST:
580 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
581 lutBltCtl.fields.lutOffset = 0 * 256;
585 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
586 lutBltCtl.fields.lutOffset = 0;
590 /* Offset points to start of LUT. Adjust for within LUT */
591 lutBltCtl.fields.lutOffset += offsetWithinLut;
598 setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
600 NgleLutBltCtl lutBltCtl;
602 /* set enable, zero reserved fields */
603 lutBltCtl.all = 0x80000000;
605 lutBltCtl.fields.length = length;
606 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
608 /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
609 if (fb->info.var.bits_per_pixel == 8)
610 lutBltCtl.fields.lutOffset = 2 * 256;
612 lutBltCtl.fields.lutOffset = 0 * 256;
614 /* Offset points to start of LUT. Adjust for within LUT */
615 lutBltCtl.fields.lutOffset += offsetWithinLut;
621 static void hyperUndoITE(struct stifb_info *fb)
623 int nFreeFifoSlots = 0;
628 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
629 WRITE_WORD(0xffffffff, fb, REG_32);
631 /* Write overlay transparency mask so only entry 255 is transparent */
633 /* Hardware setup for full-depth write to "magic" location */
634 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
635 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
636 BA(IndexedDcd, Otc04, Ots08, AddrLong,
637 BAJustPoint(0), BINovly, BAIndexBase(0)));
638 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
639 IBOvals(RopSrc, MaskAddrOffset(0),
640 BitmapExtent08, StaticReg(0),
641 DataDynamic, MaskOtc, BGx(0), FGx(0)));
643 /* Now prepare to write to the "magic" location */
644 fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
645 NGLE_BINC_SET_DSTADDR(fb, fbAddr);
646 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
647 NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
649 /* Finally, write a zero to clear the mask */
650 NGLE_BINC_WRITE32(fb, 0);
656 ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
662 ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
668 ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
670 int nFreeFifoSlots = 0;
676 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
677 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
678 BA(IndexedDcd, Otc32, OtsIndirect,
679 AddrLong, BAJustPoint(0),
680 BINattr, BAIndexBase(0)));
681 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
682 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
684 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
685 IBOvals(RopSrc, MaskAddrOffset(0),
686 BitmapExtent08, StaticReg(1),
687 DataDynamic, MaskOtc,
690 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
691 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
692 NGLE_SET_DSTXY(fb, packed_dst);
693 SET_LENXY_START_RECFILL(fb, packed_len);
696 * In order to work around an ELK hardware problem (Buffy doesn't
697 * always flush it's buffers when writing to the attribute
698 * planes), at least 4 pixels must be written to the attribute
699 * planes starting at (X == 1280) and (Y != to the last Y written
703 if (fb->id == S9000_ID_A1659A) { /* ELK_DEVICE_ID */
704 /* It's safe to use scanline zero: */
705 packed_dst = (1280 << 16);
706 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
707 NGLE_SET_DSTXY(fb, packed_dst);
708 packed_len = (4 << 16) | 1;
709 SET_LENXY_START_RECFILL(fb, packed_len);
710 } /* ELK Hardware Kludge */
712 /**** Finally, set the Control Plane Register back to zero: ****/
713 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
714 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
720 ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
722 int nFreeFifoSlots = 0;
729 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
730 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
731 BA(IndexedDcd, Otc04, Ots08, AddrLong,
732 BAJustPoint(0), BINovly, BAIndexBase(0)));
734 NGLE_SET_TRANSFERDATA(fb, 0xffffffff); /* Write foreground color */
736 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
737 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
740 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
741 NGLE_SET_DSTXY(fb, packed_dst);
743 /* Write zeroes to overlay planes */
744 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
745 IBOvals(RopSrc, MaskAddrOffset(0),
746 BitmapExtent08, StaticReg(0),
747 DataDynamic, MaskOtc, BGx(0), FGx(0)));
749 SET_LENXY_START_RECFILL(fb, packed_len);
755 hyperResetPlanes(struct stifb_info *fb, int enable)
757 unsigned int controlPlaneReg;
761 if (IS_24_DEVICE(fb))
762 if (fb->info.var.bits_per_pixel == 32)
763 controlPlaneReg = 0x04000F00;
765 controlPlaneReg = 0x00000F00; /* 0x00000800 should be enough, but lets clear all 4 bits */
767 controlPlaneReg = 0x00000F00; /* 0x00000100 should be enough, but lets clear all 4 bits */
772 if (IS_24_DEVICE(fb))
773 ngleDepth24_ClearImagePlanes(fb);
775 ngleDepth8_ClearImagePlanes(fb);
777 /* Paint attribute planes for default case.
778 * On Hyperdrive, this means all windows using overlay cmap 0. */
779 ngleResetAttrPlanes(fb, controlPlaneReg);
781 /* clear overlay planes */
782 ngleClearOverlayPlanes(fb, 0xff, 255);
784 /**************************************************
785 ** Also need to counteract ITE settings
786 **************************************************/
792 if (IS_24_DEVICE(fb))
793 ngleDepth24_ClearImagePlanes(fb);
795 ngleDepth8_ClearImagePlanes(fb);
796 ngleResetAttrPlanes(fb, controlPlaneReg);
797 ngleClearOverlayPlanes(fb, 0xff, 0);
802 ngleResetAttrPlanes(fb, controlPlaneReg);
809 /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
812 ngleGetDeviceRomData(struct stifb_info *fb)
816 int *pBytePerLongDevDepData;/* data byte == LSB */
818 NgleDevRomData *pPackedDevRomData;
819 int sizePackedDevRomData = sizeof(*pPackedDevRomData);
822 char *mapOrigin = NULL;
826 pPackedDevRomData = fb->ngle_rom;
829 if (fb->id == S9000_ID_ARTIST) {
830 pPackedDevRomData->cursor_pipeline_delay = 4;
831 pPackedDevRomData->video_interleaves = 4;
833 /* Get pointer to unpacked byte/long data in ROM */
834 pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
836 /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
837 if (fb->id == S9000_ID_TOMCAT)
839 /* jump to the correct ROM table */
840 GET_ROMTABLE_INDEX(romTableIdx);
841 while (romTableIdx > 0)
843 pCard8 = (Card8 *) pPackedDevRomData;
844 pRomTable = pBytePerLongDevDepData;
845 /* Pack every fourth byte from ROM into structure */
846 for (i = 0; i < sizePackedDevRomData; i++)
848 *pCard8++ = (Card8) (*pRomTable++);
851 pBytePerLongDevDepData = (Card32 *)
852 ((Card8 *) pBytePerLongDevDepData +
853 pPackedDevRomData->sizeof_ngle_data);
859 pCard8 = (Card8 *) pPackedDevRomData;
861 /* Pack every fourth byte from ROM into structure */
862 for (i = 0; i < sizePackedDevRomData; i++)
864 *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
873 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
874 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8
875 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10
876 #define HYPERBOWL_MODE2_8_24 15
878 /* HCRX specific boot-time initialization */
880 SETUP_HCRX(struct stifb_info *fb)
883 int nFreeFifoSlots = 0;
885 if (fb->id != S9000_ID_HCRX)
888 /* Initialize Hyperbowl registers */
889 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
891 if (IS_24_DEVICE(fb)) {
892 hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
893 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
894 HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
896 /* First write to Hyperbowl must happen twice (bug) */
897 WRITE_WORD(hyperbowl, fb, REG_40);
898 WRITE_WORD(hyperbowl, fb, REG_40);
900 WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
902 WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
903 WRITE_WORD(0x404c4048, fb, REG_43);
904 WRITE_WORD(0x034c0348, fb, REG_44);
905 WRITE_WORD(0x444c4448, fb, REG_45);
907 hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
909 /* First write to Hyperbowl must happen twice (bug) */
910 WRITE_WORD(hyperbowl, fb, REG_40);
911 WRITE_WORD(hyperbowl, fb, REG_40);
913 WRITE_WORD(0x00000000, fb, REG_42);
914 WRITE_WORD(0x00000000, fb, REG_43);
915 WRITE_WORD(0x00000000, fb, REG_44);
916 WRITE_WORD(0x444c4048, fb, REG_45);
921 /* ------------------- driver specific functions --------------------------- */
924 stifb_setcolreg(u_int regno, u_int red, u_int green,
925 u_int blue, u_int transp, struct fb_info *info)
927 struct stifb_info *fb = container_of(info, struct stifb_info, info);
930 if (regno >= NR_PALETTE)
939 START_IMAGE_COLORMAP_ACCESS(fb);
941 if (unlikely(fb->info.var.grayscale)) {
942 /* gray = 0.30*R + 0.59*G + 0.11*B */
943 color = ((red * 77) +
947 color = ((red << 16) |
952 if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
953 struct fb_var_screeninfo *var = &fb->info.var;
955 ((u32 *)fb->info.pseudo_palette)[regno] =
956 regno << var->red.offset |
957 regno << var->green.offset |
958 regno << var->blue.offset;
961 WRITE_IMAGE_COLOR(fb, regno, color);
963 if (fb->id == S9000_ID_HCRX) {
964 NgleLutBltCtl lutBltCtl;
966 lutBltCtl = setHyperLutBltCtl(fb,
967 0, /* Offset w/i LUT */
968 256); /* Load entire LUT */
969 NGLE_BINC_SET_SRCADDR(fb,
970 NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
971 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
972 START_COLORMAPLOAD(fb, lutBltCtl.all);
975 /* cleanup colormap hardware */
976 FINISH_IMAGE_COLORMAP_ACCESS(fb);
985 stifb_blank(int blank_mode, struct fb_info *info)
987 struct stifb_info *fb = container_of(info, struct stifb_info, info);
988 int enable = (blank_mode == 0) ? ENABLE : DISABLE;
991 case S9000_ID_A1439A:
992 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
994 case CRT_ID_VISUALIZE_EG:
995 case S9000_ID_ARTIST:
996 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
999 HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
1001 case S9000_ID_A1659A: /* fall through */
1002 case S9000_ID_TIMBER:
1003 case CRX24_OVERLAY_PLANES:
1005 ENABLE_DISABLE_DISPLAY(fb, enable);
1014 stifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1016 struct stifb_info *fb = container_of(info, struct stifb_info, info);
1021 if (fb->info.var.bits_per_pixel == 32) {
1022 WRITE_WORD(0xBBA0A000, fb, REG_10);
1024 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
1026 WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
1028 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
1031 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
1032 IBOvals(RopSrc, MaskAddrOffset(0),
1033 BitmapExtent08, StaticReg(1),
1034 DataDynamic, MaskOtc, BGx(0), FGx(0)));
1036 WRITE_WORD(((area->sx << 16) | area->sy), fb, REG_24);
1037 WRITE_WORD(((area->width << 16) | area->height), fb, REG_7);
1038 WRITE_WORD(((area->dx << 16) | area->dy), fb, REG_25);
1044 stifb_init_display(struct stifb_info *fb)
1050 /* HCRX specific initialization */
1054 if (id == S9000_ID_HCRX)
1055 hyperInitSprite(fb);
1060 /* Initialize the image planes. */
1063 hyperResetPlanes(fb, ENABLE);
1065 case S9000_ID_A1439A:
1066 rattlerSetupPlanes(fb);
1068 case S9000_ID_A1659A:
1069 case S9000_ID_ARTIST:
1070 case CRT_ID_VISUALIZE_EG:
1075 /* Clear attribute planes on non HCRX devices. */
1077 case S9000_ID_A1659A:
1078 case S9000_ID_A1439A:
1079 if (fb->info.var.bits_per_pixel == 32)
1080 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1082 ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1084 if (id == S9000_ID_A1439A)
1085 ngleClearOverlayPlanes(fb, 0xff, 0);
1087 case S9000_ID_ARTIST:
1088 case CRT_ID_VISUALIZE_EG:
1089 if (fb->info.var.bits_per_pixel == 32)
1090 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1092 ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1096 stifb_blank(0, (struct fb_info *)fb); /* 0=enable screen */
1101 /* ------------ Interfaces to hardware functions ------------ */
1103 static struct fb_ops stifb_ops = {
1104 .owner = THIS_MODULE,
1105 .fb_setcolreg = stifb_setcolreg,
1106 .fb_blank = stifb_blank,
1107 .fb_fillrect = cfb_fillrect,
1108 .fb_copyarea = stifb_copyarea,
1109 .fb_imageblit = cfb_imageblit,
1117 static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1119 struct fb_fix_screeninfo *fix;
1120 struct fb_var_screeninfo *var;
1121 struct stifb_info *fb;
1122 struct fb_info *info;
1123 unsigned long sti_rom_address;
1125 int bpp, xres, yres;
1127 fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
1129 printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
1135 /* set struct to a known state */
1140 dev_name = sti->sti_data->inq_outptr.dev_name;
1141 /* store upper 32bits of the graphics id */
1142 fb->id = fb->sti->graphics_id[0];
1144 /* only supported cards are allowed */
1146 case CRT_ID_VISUALIZE_EG:
1147 /* Visualize cards can run either in "double buffer" or
1148 "standard" mode. Depending on the mode, the card reports
1149 a different device name, e.g. "INTERNAL_EG_DX1024" in double
1150 buffer mode and "INTERNAL_EG_X1024" in standard mode.
1151 Since this driver only supports standard mode, we check
1152 if the device name contains the string "DX" and tell the
1153 user how to reconfigure the card. */
1154 if (strstr(dev_name, "DX")) {
1156 "WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
1157 "WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
1162 case S9000_ID_ARTIST:
1164 case S9000_ID_TIMBER:
1165 case S9000_ID_A1659A:
1166 case S9000_ID_A1439A:
1169 printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1174 /* default to 8 bpp on most graphic chips */
1176 xres = sti_onscreen_x(fb->sti);
1177 yres = sti_onscreen_y(fb->sti);
1179 ngleGetDeviceRomData(fb);
1181 /* get (virtual) io region base addr */
1182 fix->mmio_start = REGION_BASE(fb,2);
1183 fix->mmio_len = 0x400000;
1185 /* Reject any device not in the NGLE family */
1187 case S9000_ID_A1659A: /* CRX/A1659A */
1189 case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */
1191 fb->id = S9000_ID_A1659A;
1193 case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */
1194 if (strstr(dev_name, "GRAYSCALE") ||
1195 strstr(dev_name, "Grayscale") ||
1196 strstr(dev_name, "grayscale"))
1199 case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */
1200 /* FIXME: TomCat supports two heads:
1201 * fb.iobase = REGION_BASE(fb_info,3);
1202 * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx);
1203 * for now we only support the left one ! */
1204 xres = fb->ngle_rom.x_size_visible;
1205 yres = fb->ngle_rom.y_size_visible;
1206 fb->id = S9000_ID_A1659A;
1208 case S9000_ID_A1439A: /* CRX24/A1439A */
1211 case S9000_ID_HCRX: /* Hyperdrive/HCRX */
1212 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1213 if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1214 (fb->sti->regions_phys[2] & 0xfc000000))
1215 sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1217 sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1219 fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1220 if (IS_24_DEVICE(fb)) {
1221 if (bpp_pref == 8 || bpp_pref == 32)
1227 READ_WORD(fb, REG_15);
1230 case CRT_ID_VISUALIZE_EG:
1231 case S9000_ID_ARTIST: /* Artist */
1234 #ifdef FALLBACK_TO_1BPP
1236 "stifb: Unsupported graphics card (id=0x%08x) "
1237 "- now trying 1bpp mode instead\n",
1239 bpp = 1; /* default to 1 bpp */
1243 "stifb: Unsupported graphics card (id=0x%08x) "
1251 /* get framebuffer physical and virtual base addr & len (64bit ready) */
1252 fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1253 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1255 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1256 if (!fix->line_length)
1257 fix->line_length = 2048; /* default */
1259 /* limit fbsize to max visible screen size */
1260 if (fix->smem_len > yres*fix->line_length)
1261 fix->smem_len = yres*fix->line_length;
1263 fix->accel = FB_ACCEL_NONE;
1267 fix->type = FB_TYPE_PLANES; /* well, sort of */
1268 fix->visual = FB_VISUAL_MONO10;
1269 var->red.length = var->green.length = var->blue.length = 1;
1272 fix->type = FB_TYPE_PACKED_PIXELS;
1273 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1274 var->red.length = var->green.length = var->blue.length = 8;
1277 fix->type = FB_TYPE_PACKED_PIXELS;
1278 fix->visual = FB_VISUAL_DIRECTCOLOR;
1279 var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1280 var->blue.offset = 0;
1281 var->green.offset = 8;
1282 var->red.offset = 16;
1283 var->transp.offset = 24;
1289 var->xres = var->xres_virtual = xres;
1290 var->yres = var->yres_virtual = yres;
1291 var->bits_per_pixel = bpp;
1293 strcpy(fix->id, "stifb");
1294 info->fbops = &stifb_ops;
1295 info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
1296 info->screen_size = fix->smem_len;
1297 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA;
1298 info->pseudo_palette = &fb->pseudo_palette;
1300 /* This has to be done !!! */
1301 if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
1303 stifb_init_display(fb);
1305 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1306 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1307 fix->smem_start, fix->smem_start+fix->smem_len);
1311 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1312 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1313 fix->mmio_start, fix->mmio_start+fix->mmio_len);
1317 if (register_framebuffer(&fb->info) < 0)
1320 sti->info = info; /* save for unregister_framebuffer() */
1322 fb_info(&fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1326 var->bits_per_pixel,
1335 release_mem_region(fix->mmio_start, fix->mmio_len);
1337 release_mem_region(fix->smem_start, fix->smem_len);
1339 fb_dealloc_cmap(&info->cmap);
1341 iounmap(info->screen_base);
1347 static int stifb_disabled __initdata;
1350 stifb_setup(char *options);
1352 static int __init stifb_init(void)
1354 struct sti_struct *sti;
1355 struct sti_struct *def_sti;
1359 char *option = NULL;
1361 if (fb_get_options("stifb", &option))
1363 stifb_setup(option);
1365 if (stifb_disabled) {
1366 printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1370 def_sti = sti_get_rom(0);
1372 for (i = 1; i <= MAX_STI_ROMS; i++) {
1373 sti = sti_get_rom(i);
1376 if (sti == def_sti) {
1377 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1383 for (i = 1; i <= MAX_STI_ROMS; i++) {
1384 sti = sti_get_rom(i);
1389 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1401 struct sti_struct *sti;
1404 for (i = 1; i <= MAX_STI_ROMS; i++) {
1405 sti = sti_get_rom(i);
1409 struct fb_info *info = sti->info;
1410 unregister_framebuffer(sti->info);
1411 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1412 release_mem_region(info->fix.smem_start, info->fix.smem_len);
1413 if (info->screen_base)
1414 iounmap(info->screen_base);
1415 fb_dealloc_cmap(&info->cmap);
1416 framebuffer_release(info);
1423 stifb_setup(char *options)
1427 if (!options || !*options)
1430 if (strncmp(options, "off", 3) == 0) {
1435 if (strncmp(options, "bpp", 3) == 0) {
1437 for (i = 0; i < MAX_STI_ROMS; i++) {
1438 if (*options++ != ':')
1440 stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1446 __setup("stifb=", stifb_setup);
1448 module_init(stifb_init);
1449 module_exit(stifb_cleanup);
1451 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1452 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1453 MODULE_LICENSE("GPL v2");