2 * linux/drivers/video/sti/stifb.c -
3 * Frame buffer driver for HP workstations with STI (standard text interface)
6 * Copyright (C) 2001 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 * - Artist gfx is the only supported chip atm,
43 * - remove the static fb_info to support multiple cards
44 * - remove the completely untested 1bpp mode
45 * - add support for h/w acceleration
46 * - add hardware cursor
51 /* on supported graphic devices you may:
52 * #define FALLBACK_TO_1BPP to fall back to 1 bpp, or
53 * #undef FALLBACK_TO_1BPP to reject support for unsupported cards */
54 #undef FALLBACK_TO_1BPP
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/tty.h>
64 #include <linux/slab.h>
65 #include <linux/delay.h>
67 #include <linux/init.h>
68 #include <linux/selection.h>
69 #include <linux/ioport.h>
70 #include <linux/pci.h>
72 #include <video/fbcon.h>
73 #include <video/fbcon-cfb8.h>
74 #include <video/fbcon-cfb32.h>
76 #include <asm/grfioctl.h> /* for HP-UX compatibility */
80 extern struct display_switch fbcon_sti; /* fbcon-sti.c */
83 /* return virtual address */
84 #define REGION_BASE(fb_info, index) \
85 (fb_info->sti->glob_cfg->region_ptrs[index] | 0xffffffff00000000)
87 /* return virtual address */
88 #define REGION_BASE(fb_info, index) \
89 fb_info->sti->glob_cfg->region_ptrs[index]
92 #define NGLEDEVDEPROM_CRT_REGION 1
95 __s32 video_config_reg;
96 __s32 misc_video_start;
97 __s32 horiz_timing_fmt;
98 __s32 serr_timing_fmt;
99 __s32 vert_timing_fmt;
102 __s32 vtg_state_elements;
103 __s32 pipeline_delay;
104 __s32 misc_video_end;
108 __s16 sizeof_ngle_data;
109 __s16 x_size_visible; /* visible screen dim in pixels */
110 __s16 y_size_visible;
112 __s16 cursor_pipeline_delay;
113 __s16 video_interleaves;
119 struct fb_var_screeninfo var;
120 struct fb_fix_screeninfo fix;
122 struct sti_struct *sti;
123 unsigned int id, real_id;
126 int deviceSpecificConfig;
128 struct { u8 red, green, blue; } palette[256];
129 #ifdef FBCON_HAS_CFB32
136 static int stifb_force_bpp[MAX_STI_ROMS];
138 /* ------------------- chipset specific functions -------------------------- */
140 /* offsets to graphic-chip internal registers */
142 #define REG_1 0x000118
143 #define REG_2 0x000480
144 #define REG_3 0x0004a0
145 #define REG_4 0x000600
146 #define REG_6 0x000800
147 #define REG_8 0x000820
148 #define REG_9 0x000a04
149 #define REG_10 0x018000
150 #define REG_11 0x018004
151 #define REG_12 0x01800c
152 #define REG_13 0x018018
153 #define REG_14 0x01801c
154 #define REG_15 0x200000
155 #define REG_15b0 0x200000
156 #define REG_16b1 0x200005
157 #define REG_16b3 0x200007
158 #define REG_21 0x200218
159 #define REG_22 0x0005a0
160 #define REG_23 0x0005c0
161 #define REG_26 0x200118
162 #define REG_27 0x200308
163 #define REG_32 0x21003c
164 #define REG_33 0x210040
165 #define REG_34 0x200008
166 #define REG_35 0x018010
167 #define REG_38 0x210020
168 #define REG_39 0x210120
169 #define REG_40 0x210130
170 #define REG_42 0x210028
171 #define REG_43 0x21002c
172 #define REG_44 0x210030
173 #define REG_45 0x210034
175 #define READ_BYTE(fb,reg) __raw_readb((fb)->fix.mmio_start + (reg))
176 #define READ_WORD(fb,reg) __raw_readl((fb)->fix.mmio_start + (reg))
177 #define WRITE_BYTE(value,fb,reg) __raw_writeb((value),(fb)->fix.mmio_start + (reg))
178 #define WRITE_WORD(value,fb,reg) __raw_writel((value),(fb)->fix.mmio_start + (reg))
180 #define ENABLE 1 /* for enabling/disabling screen */
183 #define NGLE_LOCK(fb_info) do { } while (0)
184 #define NGLE_UNLOCK(fb_info) do { } while (0)
187 SETUP_HW(struct stifb_info *fb)
192 stat = READ_BYTE(fb, REG_15b0);
194 stat = READ_BYTE(fb, REG_15b0);
200 SETUP_FB(struct stifb_info *fb)
202 unsigned int reg10_value = 0;
207 case CRT_ID_VISUALIZE_EG:
208 case S9000_ID_ARTIST:
209 case S9000_ID_A1659A:
210 reg10_value = 0x13601000;
212 case S9000_ID_A1439A:
213 if (fb->var.bits_per_pixel == 32)
214 reg10_value = 0xBBA0A000;
216 reg10_value = 0x13601000;
219 if (fb->var.bits_per_pixel == 32)
220 reg10_value = 0xBBA0A000;
222 reg10_value = 0x13602000;
224 case S9000_ID_TIMBER:
225 case CRX24_OVERLAY_PLANES:
226 reg10_value = 0x13602000;
230 WRITE_WORD(reg10_value, fb, REG_10);
231 WRITE_WORD(0x83000300, fb, REG_14);
233 WRITE_BYTE(1, fb, REG_16b1);
237 START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
240 WRITE_WORD(0xBBE0F000, fb, REG_10);
241 WRITE_WORD(0x03000300, fb, REG_14);
242 WRITE_WORD(~0, fb, REG_13);
246 WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
249 WRITE_WORD(((0x100+index)<<2), fb, REG_3);
250 WRITE_WORD(color, fb, REG_4);
254 FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
256 WRITE_WORD(0x400, fb, REG_2);
257 if (fb->var.bits_per_pixel == 32) {
258 WRITE_WORD(0x83000100, fb, REG_1);
260 if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
261 WRITE_WORD(0x80000100, fb, REG_26);
263 WRITE_WORD(0x80000100, fb, REG_1);
269 SETUP_RAMDAC(struct stifb_info *fb)
272 WRITE_WORD(0x04000000, fb, 0x1020);
273 WRITE_WORD(0xff000000, fb, 0x1028);
277 CRX24_SETUP_RAMDAC(struct stifb_info *fb)
280 WRITE_WORD(0x04000000, fb, 0x1000);
281 WRITE_WORD(0x02000000, fb, 0x1004);
282 WRITE_WORD(0xff000000, fb, 0x1008);
283 WRITE_WORD(0x05000000, fb, 0x1000);
284 WRITE_WORD(0x02000000, fb, 0x1004);
285 WRITE_WORD(0x03000000, fb, 0x1008);
290 HCRX_SETUP_RAMDAC(struct stifb_info *fb)
292 WRITE_WORD(0xffffffff, fb, REG_32);
297 CRX24_SET_OVLY_MASK(struct stifb_info *fb)
300 WRITE_WORD(0x13a02000, fb, REG_11);
301 WRITE_WORD(0x03000300, fb, REG_14);
302 WRITE_WORD(0x000017f0, fb, REG_3);
303 WRITE_WORD(0xffffffff, fb, REG_13);
304 WRITE_WORD(0xffffffff, fb, REG_22);
305 WRITE_WORD(0x00000000, fb, REG_23);
309 ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
311 unsigned int value = enable ? 0x43000000 : 0x03000000;
313 WRITE_WORD(0x06000000, fb, 0x1030);
314 WRITE_WORD(value, fb, 0x1038);
318 CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
320 unsigned int value = enable ? 0x10000000 : 0x30000000;
322 WRITE_WORD(0x01000000, fb, 0x1000);
323 WRITE_WORD(0x02000000, fb, 0x1004);
324 WRITE_WORD(value, fb, 0x1008);
328 ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
330 u32 DregsMiscVideo = REG_21;
331 u32 DregsMiscCtl = REG_27;
335 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
336 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl);
338 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
339 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl);
343 #define GET_ROMTABLE_INDEX(fb) \
344 (READ_BYTE(fb, REG_16b3) - 1)
346 #define HYPER_CONFIG_PLANES_24 0x00000100
348 #define IS_24_DEVICE(fb) \
349 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
351 #define IS_888_DEVICE(fb) \
352 (!(IS_24_DEVICE(fb)))
354 #define GET_FIFO_SLOTS(fb, cnt, numslots) \
355 { while (cnt < numslots) \
356 cnt = READ_WORD(fb, REG_34); \
360 #define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
361 #define Otc04 2 /* Pixels in each longword transfer (4) */
362 #define Otc32 5 /* Pixels in each longword transfer (32) */
363 #define Ots08 3 /* Each pixel is size (8)d transfer (1) */
364 #define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */
365 #define AddrLong 5 /* FB address is Long aligned (pixel) */
366 #define BINovly 0x2 /* 8 bit overlay */
367 #define BINapp0I 0x0 /* Application Buffer 0, Indexed */
368 #define BINapp1I 0x1 /* Application Buffer 1, Indexed */
369 #define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */
370 #define BINattr 0xd /* Attribute Bitmap */
372 #define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */
373 #define BitmapExtent32 5 /* Each write hits (32) bits in depth */
374 #define DataDynamic 0 /* Data register reloaded by direct access */
375 #define MaskDynamic 1 /* Mask register reloaded by direct access */
376 #define MaskOtc 0 /* Mask contains Object Count valid bits */
378 #define MaskAddrOffset(offset) (offset)
379 #define StaticReg(en) (en)
383 #define BAJustPoint(offset) (offset)
384 #define BAIndexBase(base) (base)
385 #define BA(F,C,S,A,J,B,I) \
386 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
388 #define IBOvals(R,M,X,S,D,L,B,F) \
389 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
391 #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
392 WRITE_WORD(val, fb, REG_14)
394 #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
395 WRITE_WORD(val, fb, REG_11)
397 #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
398 WRITE_WORD(val, fb, REG_12)
400 #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
401 WRITE_WORD(plnmsk32, fb, REG_13)
403 #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
404 WRITE_WORD(fg32, fb, REG_35)
406 #define NGLE_SET_TRANSFERDATA(fb, val) \
407 WRITE_WORD(val, fb, REG_8)
409 #define NGLE_SET_DSTXY(fb, val) \
410 WRITE_WORD(val, fb, REG_6)
412 #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
413 (u32) (fbaddrbase) + \
414 ( (unsigned int) ( (y) << 13 ) | \
415 (unsigned int) ( (x) << 2 ) ) \
418 #define NGLE_BINC_SET_DSTADDR(fb, addr) \
419 WRITE_WORD(addr, fb, REG_3)
421 #define NGLE_BINC_SET_SRCADDR(fb, addr) \
422 WRITE_WORD(addr, fb, REG_2)
424 #define NGLE_BINC_SET_DSTMASK(fb, mask) \
425 WRITE_WORD(mask, fb, REG_22)
427 #define NGLE_BINC_WRITE32(fb, data32) \
428 WRITE_WORD(data32, fb, REG_23)
430 #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
431 WRITE_WORD((cmapBltCtlData32), fb, REG_38)
433 #define SET_LENXY_START_RECFILL(fb, lenxy) \
434 WRITE_WORD(lenxy, fb, REG_9)
437 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
439 u32 DregsHypMiscVideo = REG_33;
442 value = READ_WORD(fb, DregsHypMiscVideo);
446 value &= ~0x0A000000;
447 WRITE_WORD(value, fb, DregsHypMiscVideo);
451 /* BufferNumbers used by SETUP_ATTR_ACCESS() */
452 #define BUFF0_CMAP0 0x00001e02
453 #define BUFF1_CMAP0 0x02001e02
454 #define BUFF1_CMAP3 0x0c001e02
455 #define ARTIST_CMAP0 0x00000102
456 #define HYPER_CMAP8 0x00000100
457 #define HYPER_CMAP24 0x00000800
460 SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
463 WRITE_WORD(0x2EA0D000, fb, REG_11);
464 WRITE_WORD(0x23000302, fb, REG_14);
465 WRITE_WORD(BufferNumber, fb, REG_12);
466 WRITE_WORD(0xffffffff, fb, REG_8);
470 SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
472 WRITE_WORD(0x00000000, fb, REG_6);
473 WRITE_WORD((width<<16) | height, fb, REG_9);
474 WRITE_WORD(0x05000000, fb, REG_6);
475 WRITE_WORD(0x00040001, fb, REG_9);
479 FINISH_ATTR_ACCESS(struct stifb_info *fb)
482 WRITE_WORD(0x00000000, fb, REG_12);
486 elkSetupPlanes(struct stifb_info *fb)
493 ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
495 SETUP_ATTR_ACCESS(fb, BufferNumber);
496 SET_ATTR_SIZE(fb, fb->var.xres, fb->var.yres);
497 FINISH_ATTR_ACCESS(fb);
503 rattlerSetupPlanes(struct stifb_info *fb)
505 CRX24_SETUP_RAMDAC(fb);
507 /* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */
508 WRITE_WORD(0x83000300, fb, REG_14);
510 WRITE_BYTE(1, fb, REG_16b1);
512 /* XXX: replace by fb_setmem(), smem_start or screen_base ? */
513 memset_io(fb->fix.smem_start, 0xff,
514 fb->var.yres*fb->fix.line_length);
516 CRX24_SET_OVLY_MASK(fb);
521 #define HYPER_CMAP_TYPE 0
522 #define NGLE_CMAP_INDEXED0_TYPE 0
523 #define NGLE_CMAP_OVERLAY_TYPE 3
525 /* typedef of LUT (Colormap) BLT Control Register */
526 typedef union /* Note assumption that fields are packed left-to-right */
531 unsigned waitBlank : 1;
532 unsigned reserved1 : 4;
533 unsigned lutOffset : 10; /* Within destination LUT */
534 unsigned lutType : 2; /* Cursor, image, overlay */
535 unsigned reserved2 : 4;
536 unsigned length : 10;
543 setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
545 NgleLutBltCtl lutBltCtl;
547 /* set enable, zero reserved fields */
548 lutBltCtl.all = 0x80000000;
549 lutBltCtl.fields.length = length;
553 case S9000_ID_A1439A: /* CRX24 */
554 if (fb->var.bits_per_pixel == 8) {
555 lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
556 lutBltCtl.fields.lutOffset = 0;
558 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
559 lutBltCtl.fields.lutOffset = 0 * 256;
563 case S9000_ID_ARTIST:
564 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
565 lutBltCtl.fields.lutOffset = 0 * 256;
569 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
570 lutBltCtl.fields.lutOffset = 0;
574 /* Offset points to start of LUT. Adjust for within LUT */
575 lutBltCtl.fields.lutOffset += offsetWithinLut;
582 setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
584 NgleLutBltCtl lutBltCtl;
586 /* set enable, zero reserved fields */
587 lutBltCtl.all = 0x80000000;
589 lutBltCtl.fields.length = length;
590 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
592 /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
593 if (fb->var.bits_per_pixel == 8)
594 lutBltCtl.fields.lutOffset = 2 * 256;
596 lutBltCtl.fields.lutOffset = 0 * 256;
598 /* Offset points to start of LUT. Adjust for within LUT */
599 lutBltCtl.fields.lutOffset += offsetWithinLut;
605 static void hyperUndoITE(struct stifb_info *fb)
607 int nFreeFifoSlots = 0;
612 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
613 WRITE_WORD(0xffffffff, fb, REG_32);
615 /* Write overlay transparency mask so only entry 255 is transparent */
617 /* Hardware setup for full-depth write to "magic" location */
618 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
619 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
620 BA(IndexedDcd, Otc04, Ots08, AddrLong,
621 BAJustPoint(0), BINovly, BAIndexBase(0)));
622 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
623 IBOvals(RopSrc, MaskAddrOffset(0),
624 BitmapExtent08, StaticReg(0),
625 DataDynamic, MaskOtc, BGx(0), FGx(0)));
627 /* Now prepare to write to the "magic" location */
628 fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
629 NGLE_BINC_SET_DSTADDR(fb, fbAddr);
630 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
631 NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
633 /* Finally, write a zero to clear the mask */
634 NGLE_BINC_WRITE32(fb, 0);
640 ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
646 ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
652 ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
654 int nFreeFifoSlots = 0;
660 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
661 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
662 BA(IndexedDcd, Otc32, OtsIndirect,
663 AddrLong, BAJustPoint(0),
664 BINattr, BAIndexBase(0)));
665 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
666 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
668 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
669 IBOvals(RopSrc, MaskAddrOffset(0),
670 BitmapExtent08, StaticReg(1),
671 DataDynamic, MaskOtc,
674 packed_len = (fb->var.xres << 16) | fb->var.yres;
675 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
676 NGLE_SET_DSTXY(fb, packed_dst);
677 SET_LENXY_START_RECFILL(fb, packed_len);
680 * In order to work around an ELK hardware problem (Buffy doesn't
681 * always flush it's buffers when writing to the attribute
682 * planes), at least 4 pixels must be written to the attribute
683 * planes starting at (X == 1280) and (Y != to the last Y written
687 if (fb->id == S9000_ID_A1659A) { /* ELK_DEVICE_ID */
688 /* It's safe to use scanline zero: */
689 packed_dst = (1280 << 16);
690 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
691 NGLE_SET_DSTXY(fb, packed_dst);
692 packed_len = (4 << 16) | 1;
693 SET_LENXY_START_RECFILL(fb, packed_len);
694 } /* ELK Hardware Kludge */
696 /**** Finally, set the Control Plane Register back to zero: ****/
697 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
698 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
704 ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
706 int nFreeFifoSlots = 0;
713 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
714 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
715 BA(IndexedDcd, Otc04, Ots08, AddrLong,
716 BAJustPoint(0), BINovly, BAIndexBase(0)));
718 NGLE_SET_TRANSFERDATA(fb, 0xffffffff); /* Write foreground color */
720 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
721 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
724 packed_len = (fb->var.xres << 16) | fb->var.yres;
725 NGLE_SET_DSTXY(fb, packed_dst);
727 /* Write zeroes to overlay planes */
728 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
729 IBOvals(RopSrc, MaskAddrOffset(0),
730 BitmapExtent08, StaticReg(0),
731 DataDynamic, MaskOtc, BGx(0), FGx(0)));
733 SET_LENXY_START_RECFILL(fb, packed_len);
739 hyperResetPlanes(struct stifb_info *fb, int enable)
741 unsigned int controlPlaneReg;
745 if (IS_24_DEVICE(fb))
746 if (fb->var.bits_per_pixel == 32)
747 controlPlaneReg = 0x04000F00;
749 controlPlaneReg = 0x00000F00; /* 0x00000800 should be enought, but lets clear all 4 bits */
751 controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
756 if (IS_24_DEVICE(fb))
757 ngleDepth24_ClearImagePlanes(fb);
759 ngleDepth8_ClearImagePlanes(fb);
761 /* Paint attribute planes for default case.
762 * On Hyperdrive, this means all windows using overlay cmap 0. */
763 ngleResetAttrPlanes(fb, controlPlaneReg);
765 /* clear overlay planes */
766 ngleClearOverlayPlanes(fb, 0xff, 255);
768 /**************************************************
769 ** Also need to counteract ITE settings
770 **************************************************/
774 case 0: /* DISABLE */
776 if (IS_24_DEVICE(fb))
777 ngleDepth24_ClearImagePlanes(fb);
779 ngleDepth8_ClearImagePlanes(fb);
780 ngleResetAttrPlanes(fb, controlPlaneReg);
781 ngleClearOverlayPlanes(fb, 0xff, 0);
786 ngleResetAttrPlanes(fb, controlPlaneReg);
793 /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
796 ngleGetDeviceRomData(struct stifb_info *fb)
800 int *pBytePerLongDevDepData;/* data byte == LSB */
802 NgleDevRomData *pPackedDevRomData;
803 int sizePackedDevRomData = sizeof(*pPackedDevRomData);
806 char *mapOrigin = NULL;
810 pPackedDevRomData = fb->ngle_rom;
813 if (fb->id == S9000_ID_ARTIST) {
814 pPackedDevRomData->cursor_pipeline_delay = 4;
815 pPackedDevRomData->video_interleaves = 4;
817 /* Get pointer to unpacked byte/long data in ROM */
818 pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
820 /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
821 if (fb->id == S9000_ID_TOMCAT)
823 /* jump to the correct ROM table */
824 GET_ROMTABLE_INDEX(romTableIdx);
825 while (romTableIdx > 0)
827 pCard8 = (Card8 *) pPackedDevRomData;
828 pRomTable = pBytePerLongDevDepData;
829 /* Pack every fourth byte from ROM into structure */
830 for (i = 0; i < sizePackedDevRomData; i++)
832 *pCard8++ = (Card8) (*pRomTable++);
835 pBytePerLongDevDepData = (Card32 *)
836 ((Card8 *) pBytePerLongDevDepData +
837 pPackedDevRomData->sizeof_ngle_data);
843 pCard8 = (Card8 *) pPackedDevRomData;
845 /* Pack every fourth byte from ROM into structure */
846 for (i = 0; i < sizePackedDevRomData; i++)
848 *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
857 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
858 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8
859 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10
860 #define HYPERBOWL_MODE2_8_24 15
862 /* HCRX specific boot-time initialization */
864 SETUP_HCRX(struct stifb_info *fb)
867 int nFreeFifoSlots = 0;
869 if (fb->id != S9000_ID_HCRX)
872 /* Initialize Hyperbowl registers */
873 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
875 if (IS_24_DEVICE(fb)) {
876 hyperbowl = (fb->var.bits_per_pixel == 32) ?
877 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
878 HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
880 /* First write to Hyperbowl must happen twice (bug) */
881 WRITE_WORD(hyperbowl, fb, REG_40);
882 WRITE_WORD(hyperbowl, fb, REG_40);
884 WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
886 WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
887 WRITE_WORD(0x404c4048, fb, REG_43);
888 WRITE_WORD(0x034c0348, fb, REG_44);
889 WRITE_WORD(0x444c4448, fb, REG_45);
891 hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
893 /* First write to Hyperbowl must happen twice (bug) */
894 WRITE_WORD(hyperbowl, fb, REG_40);
895 WRITE_WORD(hyperbowl, fb, REG_40);
897 WRITE_WORD(0x00000000, fb, REG_42);
898 WRITE_WORD(0x00000000, fb, REG_43);
899 WRITE_WORD(0x00000000, fb, REG_44);
900 WRITE_WORD(0x444c4048, fb, REG_45);
905 /* ------------------- driver specific functions --------------------------- */
908 stifb_getcolreg(u_int regno, u_int *red, u_int *green,
909 u_int *blue, u_int *transp, struct fb_info *info)
911 struct stifb_info *fb = (struct stifb_info *) info;
915 *red = (fb->palette[regno].red<<8) | fb->palette[regno].red;
916 *green = (fb->palette[regno].green<<8) | fb->palette[regno].green;
917 *blue = (fb->palette[regno].blue<<8) | fb->palette[regno].blue;
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 = (struct stifb_info *) info;
936 if ((fb->palette[regno].red != red) ||
937 (fb->palette[regno].green != green) ||
938 (fb->palette[regno].blue != blue))
941 fb->palette[regno].red = red;
942 fb->palette[regno].green = green;
943 fb->palette[regno].blue = blue;
945 #ifdef FBCON_HAS_CFB32
946 if (regno < 16 && fb->var.bits_per_pixel == 32) {
947 fb->fbcon_cmap.cfb32[regno] = ((red << 16) |
957 stifb_loadcmap(struct stifb_info *fb)
962 if (!fb->cmap_reload)
965 START_IMAGE_COLORMAP_ACCESS(fb);
966 for (i = 0; i < 256; i++) {
967 if (fb->var.bits_per_pixel > 8) {
968 color = (i << 16) | (i << 8) | i;
970 if (fb->var.grayscale) {
971 /* gray = 0.30*R + 0.59*G + 0.11*B */
972 color = ((fb->palette[i].red * 77) +
973 (fb->palette[i].green * 151) +
974 (fb->palette[i].blue * 28)) >> 8;
976 color = ((fb->palette[i].red << 16) |
977 (fb->palette[i].green << 8) |
978 (fb->palette[i].blue));
981 WRITE_IMAGE_COLOR(fb, i, color);
983 if (fb->id == S9000_ID_HCRX) {
984 NgleLutBltCtl lutBltCtl;
986 lutBltCtl = setHyperLutBltCtl(fb,
987 0, /* Offset w/i LUT */
988 256); /* Load entire LUT */
989 NGLE_BINC_SET_SRCADDR(fb,
990 NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
991 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
992 START_COLORMAPLOAD(fb, lutBltCtl.all);
995 /* cleanup colormap hardware */
996 FINISH_IMAGE_COLORMAP_ACCESS(fb);
1002 stifb_get_fix(struct fb_fix_screeninfo *fix, int con,
1003 struct fb_info *info)
1005 memcpy (fix, &((struct stifb_info *)info)->fix, sizeof (*fix));
1010 stifb_get_var(struct fb_var_screeninfo *var, int con,
1011 struct fb_info *info)
1013 memcpy (var, &((struct stifb_info *)info)->var, sizeof (*var));
1018 stifb_set_var(struct fb_var_screeninfo *var, int con,
1019 struct fb_info *info)
1021 struct display *disp;
1024 disp = &fb_display[con];
1028 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1029 if (disp->var.xres != var->xres ||
1030 disp->var.yres != var->yres ||
1031 disp->var.xres_virtual != var->xres_virtual ||
1032 disp->var.yres_virtual != var->yres_virtual ||
1033 disp->var.bits_per_pixel != var->bits_per_pixel ||
1034 disp->var.accel_flags != var->accel_flags)
1041 stifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
1042 struct fb_info *info)
1044 struct stifb_info *fb = (struct stifb_info *)info;
1046 if (con == fb->currcon) /* current console ? */
1047 return fb_get_cmap(cmap, kspc, stifb_getcolreg, info);
1048 else if (fb_display[con].cmap.len) /* non default colormap ? */
1049 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
1051 fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel > 8 ? 16 : 256), cmap, kspc ? 0: 2);
1056 stifb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
1057 struct fb_info *info)
1059 struct stifb_info *fb = (struct stifb_info *)info;
1060 struct display *disp;
1064 disp = &fb_display[con];
1068 if (!disp->cmap.len) { /* no colormap allocated ? */
1069 if ((err = fb_alloc_cmap(&disp->cmap, disp->var.bits_per_pixel > 8 ? 16 : 256, 0)))
1072 if (con == fb->currcon || con == -1) {
1073 err = fb_set_cmap(cmap, kspc, stifb_setcolreg, info);
1075 stifb_loadcmap ((struct stifb_info *)info);
1078 fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
1083 stifb_blank(int blank_mode, struct fb_info *info)
1085 struct stifb_info *fb = (struct stifb_info *) info;
1086 int enable = (blank_mode == 0) ? ENABLE : DISABLE;
1089 case S9000_ID_A1439A:
1090 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
1092 case CRT_ID_VISUALIZE_EG:
1093 case S9000_ID_ARTIST:
1094 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
1097 HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
1099 case S9000_ID_A1659A:; /* fall through */
1100 case S9000_ID_TIMBER:;
1101 case CRX24_OVERLAY_PLANES:;
1103 ENABLE_DISABLE_DISPLAY(fb, enable);
1111 stifb_set_disp(struct stifb_info *fb)
1117 /* HCRX specific initialization */
1121 if (id == S9000_ID_HCRX)
1122 hyperInitSprite(fb);
1127 /* Initialize the image planes. */
1130 hyperResetPlanes(fb, ENABLE);
1132 case S9000_ID_A1439A:
1133 rattlerSetupPlanes(fb);
1135 case S9000_ID_A1659A:
1136 case S9000_ID_ARTIST:
1137 case CRT_ID_VISUALIZE_EG:
1142 /* Clear attribute planes on non HCRX devices. */
1144 case S9000_ID_A1659A:
1145 case S9000_ID_A1439A:
1146 if (fb->var.bits_per_pixel == 32)
1147 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1149 ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1151 if (id == S9000_ID_A1439A)
1152 ngleClearOverlayPlanes(fb, 0xff, 0);
1154 case S9000_ID_ARTIST:
1155 case CRT_ID_VISUALIZE_EG:
1156 if (fb->var.bits_per_pixel == 32)
1157 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1159 ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1163 stifb_blank(0, (struct fb_info *)fb); /* 0=enable screen */
1169 stifb_switch(int con, struct fb_info *info)
1171 struct stifb_info *fb = (struct stifb_info *)info;
1173 /* Do we have to save the colormap ? */
1174 if (fb->currcon != -1 && fb_display[fb->currcon].cmap.len)
1175 fb_get_cmap(&fb_display[fb->currcon].cmap, 1, stifb_getcolreg, info);
1178 /* Install new colormap */
1179 if (fb_display[con].cmap.len)
1180 fb_set_cmap(&fb_display[con].cmap, 1, stifb_setcolreg, info);
1182 fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel > 8 ? 16 : 256),
1183 1, stifb_setcolreg, info);
1184 stifb_loadcmap ((struct stifb_info *)info);
1189 stifb_update_var(int con, struct fb_info *info)
1194 /* ------------ Interfaces to hardware functions ------------ */
1196 static struct fb_ops stifb_ops = {
1198 fb_get_fix: stifb_get_fix,
1199 fb_get_var: stifb_get_var,
1200 fb_set_var: stifb_set_var,
1201 fb_get_cmap: stifb_get_cmap,
1202 fb_set_cmap: stifb_set_cmap,
1203 // fb_pan_display: fbgen_pan_display,
1204 // fb_ioctl: xxxfb_ioctl, /* optional */
1213 stifb_init_fb(struct sti_struct *sti, int force_bpp)
1215 struct fb_fix_screeninfo *fix;
1216 struct fb_var_screeninfo *var;
1217 struct display *disp;
1218 struct stifb_info *fb;
1219 unsigned long sti_rom_address;
1221 int bpp, xres, yres;
1223 fb = kmalloc(sizeof(struct stifb_info), GFP_ATOMIC);
1225 printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
1229 /* set struct to a known state */
1230 memset(fb, 0, sizeof(struct stifb_info));
1236 fb->cmap_reload = 1;
1238 /* store upper 32bits of the graphics id */
1239 fb->id = fb->sti->graphics_id[0];
1240 fb->real_id = fb->id; /* save the real id */
1242 /* only supported cards are allowed */
1244 case S9000_ID_ARTIST:
1246 case S9000_ID_TIMBER:
1247 case S9000_ID_A1659A:
1248 case S9000_ID_A1439A:
1249 case CRT_ID_VISUALIZE_EG:
1252 printk(KERN_WARNING "stifb: Unsupported gfx card id 0x%08x\n",
1257 /* default to 8 bpp on most graphic chips */
1259 xres = sti_onscreen_x(fb->sti);
1260 yres = sti_onscreen_y(fb->sti);
1262 ngleGetDeviceRomData(fb);
1264 /* get (virtual) io region base addr */
1265 fix->mmio_start = REGION_BASE(fb,2);
1266 fix->mmio_len = 0x400000;
1268 /* Reject any device not in the NGLE family */
1270 case S9000_ID_A1659A: /* CRX/A1659A */
1272 case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */
1274 fb->id = S9000_ID_A1659A;
1276 case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */
1277 dev_name = fb->sti->outptr.dev_name;
1278 if (strstr(dev_name, "GRAYSCALE") ||
1279 strstr(dev_name, "Grayscale") ||
1280 strstr(dev_name, "grayscale"))
1283 case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */
1284 /* FIXME: TomCat supports two heads:
1285 * fb.iobase = REGION_BASE(fb_info,3);
1286 * fb.screen_base = (void*) REGION_BASE(fb_info,2);
1287 * for now we only support the left one ! */
1288 xres = fb->ngle_rom.x_size_visible;
1289 yres = fb->ngle_rom.y_size_visible;
1290 fb->id = S9000_ID_A1659A;
1292 case S9000_ID_A1439A: /* CRX24/A1439A */
1293 if (force_bpp == 8 || force_bpp == 32)
1298 case S9000_ID_HCRX: /* Hyperdrive/HCRX */
1299 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1300 if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1301 (fb->sti->regions_phys[2] & 0xfc000000))
1302 sti_rom_address = fb->sti->regions_phys[0];
1304 sti_rom_address = fb->sti->regions_phys[1];
1306 sti_rom_address |= 0xffffffff00000000;
1308 fb->deviceSpecificConfig = __raw_readl(sti_rom_address);
1309 if (IS_24_DEVICE(fb)) {
1310 if (force_bpp == 8 || force_bpp == 32)
1316 READ_WORD(fb, REG_15);
1319 case CRT_ID_VISUALIZE_EG:
1320 case S9000_ID_ARTIST: /* Artist */
1323 #ifdef FALLBACK_TO_1BPP
1325 "stifb: Unsupported graphics card (id=0x%08x) "
1326 "- now trying 1bpp mode instead\n",
1328 bpp = 1; /* default to 1 bpp */
1332 "stifb: Unsupported graphics card (id=0x%08x) "
1340 /* get framebuffer pysical and virtual base addr & len (64bit ready) */
1341 fix->smem_start = fb->sti->regions_phys[1] | 0xffffffff00000000;
1342 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1344 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1345 if (!fix->line_length)
1346 fix->line_length = 2048; /* default */
1347 fix->accel = FB_ACCEL_NONE;
1351 fix->type = FB_TYPE_PLANES; /* well, sort of */
1352 fix->visual = FB_VISUAL_MONO10;
1353 disp->dispsw = &fbcon_sti;
1355 #ifdef FBCON_HAS_CFB8
1357 fix->type = FB_TYPE_PACKED_PIXELS;
1358 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1359 disp->dispsw = &fbcon_cfb8;
1360 var->red.length = var->green.length = var->blue.length = 8;
1363 #ifdef FBCON_HAS_CFB32
1365 fix->type = FB_TYPE_PACKED_PIXELS;
1366 fix->visual = FB_VISUAL_TRUECOLOR;
1367 disp->dispsw = &fbcon_cfb32;
1368 disp->dispsw_data = fb->fbcon_cmap.cfb32;
1369 var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1370 var->blue.offset = 0;
1371 var->green.offset = 8;
1372 var->red.offset = 16;
1373 var->transp.offset = 24;
1377 disp->dispsw = &fbcon_dummy;
1381 var->xres = var->xres_virtual = xres;
1382 var->yres = var->yres_virtual = yres;
1383 var->bits_per_pixel = bpp;
1386 disp->visual = fix->visual;
1387 disp->type = fix->type;
1388 disp->type_aux = fix->type_aux;
1389 disp->line_length = fix->line_length;
1390 disp->var.activate = FB_ACTIVATE_NOW;
1391 disp->screen_base = (void*) REGION_BASE(fb,1);
1392 disp->can_soft_blank = 1;
1393 disp->scrollmode = SCROLL_YREDRAW;
1395 strcpy(fb->info.modename, "stifb");
1397 fb->info.flags = FBINFO_FLAG_DEFAULT;
1398 fb->info.fbops = &stifb_ops;
1399 fb->info.disp = disp;
1400 fb->info.changevar = NULL;
1401 fb->info.switch_con = &stifb_switch;
1402 fb->info.updatevar = &stifb_update_var;
1403 fb->info.blank = &stifb_blank;
1404 fb->info.flags = FBINFO_FLAG_DEFAULT;
1406 stifb_set_var(&disp->var, 1, &fb->info);
1410 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb")) {
1411 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1412 fix->smem_start, fix->smem_start+fix->smem_len);
1416 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1417 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1418 fix->mmio_start, fix->mmio_start+fix->mmio_len);
1422 if (register_framebuffer(&fb->info) < 0)
1426 "fb%d: %s %dx%d-%d frame buffer device, id: %04x, mmio: 0x%04lx\n",
1427 GET_FB_IDX(fb->info.node),
1431 disp->var.bits_per_pixel,
1439 release_mem_region(fix->mmio_start, fix->mmio_len);
1441 release_mem_region(fix->smem_start, fix->smem_len);
1450 struct sti_struct *sti;
1454 if (sti_init_roms() == NULL)
1455 return -ENXIO; /* no STI cards available */
1457 for (i = 0; i < MAX_STI_ROMS; i++) {
1458 sti = sti_get_rom(i);
1460 stifb_init_fb (sti, stifb_force_bpp[i]);
1472 stifb_cleanup(struct fb_info *info)
1474 // unregister_framebuffer(info);
1478 stifb_setup(char *options)
1482 if (!options || !*options)
1485 if (strncmp(options, "bpp", 3) == 0) {
1487 for (i = 0; i < MAX_STI_ROMS; i++) {
1488 if (*options++ == ':')
1489 stifb_force_bpp[i] = simple_strtoul(options, &options, 10);
1497 __setup("stifb=", stifb_setup);
1500 module_init(stifb_init);
1502 module_exit(stifb_cleanup);
1504 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1505 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1506 MODULE_LICENSE("GPL");
1508 MODULE_PARM(bpp, "i");
1509 MODULE_PARM_DESC(mem, "Bits per pixel (default: 8)");