GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / video / stifb.c
blob4bbe837f40a895cd2211c479171708636c3a0164
1 /*
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>
8 *
9 * Based on:
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
38 * for more details.
41 /* TODO:
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>
61 #include <linux/mm.h>
62 #include <linux/slab.h>
63 #include <linux/delay.h>
64 #include <linux/fb.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>
71 #include "sticore.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
81 typedef struct {
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;
87 __s32 horiz_state;
88 __s32 vert_state;
89 __s32 vtg_state_elements;
90 __s32 pipeline_delay;
91 __s32 misc_video_end;
92 } video_setup_t;
94 typedef struct {
95 __s16 sizeof_ngle_data;
96 __s16 x_size_visible; /* visible screen dim in pixels */
97 __s16 y_size_visible;
98 __s16 pad2[15];
99 __s16 cursor_pipeline_delay;
100 __s16 video_interleaves;
101 __s32 pad3[11];
102 } ngle_rom_t;
104 struct stifb_info {
105 struct fb_info info;
106 unsigned int id;
107 ngle_rom_t ngle_rom;
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
157 # define DEBUG_OFF()
158 # define DEBUG_ON()
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))
161 #else
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 __func__, 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 __func__, 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 */
177 #define DISABLE 0
179 #define NGLE_LOCK(fb_info) do { } while (0)
180 #define NGLE_UNLOCK(fb_info) do { } while (0)
182 static void
183 SETUP_HW(struct stifb_info *fb)
185 char stat;
187 do {
188 stat = READ_BYTE(fb, REG_15b0);
189 if (!stat)
190 stat = READ_BYTE(fb, REG_15b0);
191 } while (stat);
195 static void
196 SETUP_FB(struct stifb_info *fb)
198 unsigned int reg10_value = 0;
200 SETUP_HW(fb);
201 switch (fb->id)
203 case CRT_ID_VISUALIZE_EG:
204 case S9000_ID_ARTIST:
205 case S9000_ID_A1659A:
206 reg10_value = 0x13601000;
207 break;
208 case S9000_ID_A1439A:
209 if (fb->info.var.bits_per_pixel == 32)
210 reg10_value = 0xBBA0A000;
211 else
212 reg10_value = 0x13601000;
213 break;
214 case S9000_ID_HCRX:
215 if (fb->info.var.bits_per_pixel == 32)
216 reg10_value = 0xBBA0A000;
217 else
218 reg10_value = 0x13602000;
219 break;
220 case S9000_ID_TIMBER:
221 case CRX24_OVERLAY_PLANES:
222 reg10_value = 0x13602000;
223 break;
225 if (reg10_value)
226 WRITE_WORD(reg10_value, fb, REG_10);
227 WRITE_WORD(0x83000300, fb, REG_14);
228 SETUP_HW(fb);
229 WRITE_BYTE(1, fb, REG_16b1);
232 static void
233 START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
235 SETUP_HW(fb);
236 WRITE_WORD(0xBBE0F000, fb, REG_10);
237 WRITE_WORD(0x03000300, fb, REG_14);
238 WRITE_WORD(~0, fb, REG_13);
241 static void
242 WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
244 SETUP_HW(fb);
245 WRITE_WORD(((0x100+index)<<2), fb, REG_3);
246 WRITE_WORD(color, fb, REG_4);
249 static void
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);
255 } else {
256 if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
257 WRITE_WORD(0x80000100, fb, REG_26);
258 else
259 WRITE_WORD(0x80000100, fb, REG_1);
261 SETUP_FB(fb);
264 static void
265 SETUP_RAMDAC(struct stifb_info *fb)
267 SETUP_HW(fb);
268 WRITE_WORD(0x04000000, fb, 0x1020);
269 WRITE_WORD(0xff000000, fb, 0x1028);
272 static void
273 CRX24_SETUP_RAMDAC(struct stifb_info *fb)
275 SETUP_HW(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);
285 static void
286 CRX24_SET_OVLY_MASK(struct stifb_info *fb)
288 SETUP_HW(fb);
289 WRITE_WORD(0x13a02000, fb, REG_11);
290 WRITE_WORD(0x03000300, fb, REG_14);
291 WRITE_WORD(0x000017f0, fb, REG_3);
292 WRITE_WORD(0xffffffff, fb, REG_13);
293 WRITE_WORD(0xffffffff, fb, REG_22);
294 WRITE_WORD(0x00000000, fb, REG_23);
297 static void
298 ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
300 unsigned int value = enable ? 0x43000000 : 0x03000000;
301 SETUP_HW(fb);
302 WRITE_WORD(0x06000000, fb, 0x1030);
303 WRITE_WORD(value, fb, 0x1038);
306 static void
307 CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
309 unsigned int value = enable ? 0x10000000 : 0x30000000;
310 SETUP_HW(fb);
311 WRITE_WORD(0x01000000, fb, 0x1000);
312 WRITE_WORD(0x02000000, fb, 0x1004);
313 WRITE_WORD(value, fb, 0x1008);
316 static void
317 ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
319 u32 DregsMiscVideo = REG_21;
320 u32 DregsMiscCtl = REG_27;
322 SETUP_HW(fb);
323 if (enable) {
324 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
325 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl);
326 } else {
327 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
328 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl);
332 #define GET_ROMTABLE_INDEX(fb) \
333 (READ_BYTE(fb, REG_16b3) - 1)
335 #define HYPER_CONFIG_PLANES_24 0x00000100
337 #define IS_24_DEVICE(fb) \
338 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
340 #define IS_888_DEVICE(fb) \
341 (!(IS_24_DEVICE(fb)))
343 #define GET_FIFO_SLOTS(fb, cnt, numslots) \
344 { while (cnt < numslots) \
345 cnt = READ_WORD(fb, REG_34); \
346 cnt -= numslots; \
349 #define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
350 #define Otc04 2 /* Pixels in each longword transfer (4) */
351 #define Otc32 5 /* Pixels in each longword transfer (32) */
352 #define Ots08 3 /* Each pixel is size (8)d transfer (1) */
353 #define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */
354 #define AddrLong 5 /* FB address is Long aligned (pixel) */
355 #define BINovly 0x2 /* 8 bit overlay */
356 #define BINapp0I 0x0 /* Application Buffer 0, Indexed */
357 #define BINapp1I 0x1 /* Application Buffer 1, Indexed */
358 #define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */
359 #define BINattr 0xd /* Attribute Bitmap */
360 #define RopSrc 0x3
361 #define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */
362 #define BitmapExtent32 5 /* Each write hits (32) bits in depth */
363 #define DataDynamic 0 /* Data register reloaded by direct access */
364 #define MaskDynamic 1 /* Mask register reloaded by direct access */
365 #define MaskOtc 0 /* Mask contains Object Count valid bits */
367 #define MaskAddrOffset(offset) (offset)
368 #define StaticReg(en) (en)
369 #define BGx(en) (en)
370 #define FGx(en) (en)
372 #define BAJustPoint(offset) (offset)
373 #define BAIndexBase(base) (base)
374 #define BA(F,C,S,A,J,B,I) \
375 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
377 #define IBOvals(R,M,X,S,D,L,B,F) \
378 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
380 #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
381 WRITE_WORD(val, fb, REG_14)
383 #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
384 WRITE_WORD(val, fb, REG_11)
386 #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
387 WRITE_WORD(val, fb, REG_12)
389 #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
390 WRITE_WORD(plnmsk32, fb, REG_13)
392 #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
393 WRITE_WORD(fg32, fb, REG_35)
395 #define NGLE_SET_TRANSFERDATA(fb, val) \
396 WRITE_WORD(val, fb, REG_8)
398 #define NGLE_SET_DSTXY(fb, val) \
399 WRITE_WORD(val, fb, REG_6)
401 #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
402 (u32) (fbaddrbase) + \
403 ( (unsigned int) ( (y) << 13 ) | \
404 (unsigned int) ( (x) << 2 ) ) \
407 #define NGLE_BINC_SET_DSTADDR(fb, addr) \
408 WRITE_WORD(addr, fb, REG_3)
410 #define NGLE_BINC_SET_SRCADDR(fb, addr) \
411 WRITE_WORD(addr, fb, REG_2)
413 #define NGLE_BINC_SET_DSTMASK(fb, mask) \
414 WRITE_WORD(mask, fb, REG_22)
416 #define NGLE_BINC_WRITE32(fb, data32) \
417 WRITE_WORD(data32, fb, REG_23)
419 #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
420 WRITE_WORD((cmapBltCtlData32), fb, REG_38)
422 #define SET_LENXY_START_RECFILL(fb, lenxy) \
423 WRITE_WORD(lenxy, fb, REG_9)
425 static void
426 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
428 u32 DregsHypMiscVideo = REG_33;
429 unsigned int value;
430 SETUP_HW(fb);
431 value = READ_WORD(fb, DregsHypMiscVideo);
432 if (enable)
433 value |= 0x0A000000;
434 else
435 value &= ~0x0A000000;
436 WRITE_WORD(value, fb, DregsHypMiscVideo);
440 /* BufferNumbers used by SETUP_ATTR_ACCESS() */
441 #define BUFF0_CMAP0 0x00001e02
442 #define BUFF1_CMAP0 0x02001e02
443 #define BUFF1_CMAP3 0x0c001e02
444 #define ARTIST_CMAP0 0x00000102
445 #define HYPER_CMAP8 0x00000100
446 #define HYPER_CMAP24 0x00000800
448 static void
449 SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
451 SETUP_HW(fb);
452 WRITE_WORD(0x2EA0D000, fb, REG_11);
453 WRITE_WORD(0x23000302, fb, REG_14);
454 WRITE_WORD(BufferNumber, fb, REG_12);
455 WRITE_WORD(0xffffffff, fb, REG_8);
458 static void
459 SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
461 /* REG_6 seems to have special values when run on a
462 RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
463 INTERNAL_EG_X1024). The values are:
464 0x2f0: internal (LCD) & external display enabled
465 0x2a0: external display only
466 0x000: zero on standard artist graphic cards
468 WRITE_WORD(0x00000000, fb, REG_6);
469 WRITE_WORD((width<<16) | height, fb, REG_9);
470 WRITE_WORD(0x05000000, fb, REG_6);
471 WRITE_WORD(0x00040001, fb, REG_9);
474 static void
475 FINISH_ATTR_ACCESS(struct stifb_info *fb)
477 SETUP_HW(fb);
478 WRITE_WORD(0x00000000, fb, REG_12);
481 static void
482 elkSetupPlanes(struct stifb_info *fb)
484 SETUP_RAMDAC(fb);
485 SETUP_FB(fb);
488 static void
489 ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
491 SETUP_ATTR_ACCESS(fb, BufferNumber);
492 SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
493 FINISH_ATTR_ACCESS(fb);
494 SETUP_FB(fb);
498 static void
499 rattlerSetupPlanes(struct stifb_info *fb)
501 int saved_id, y;
503 /* Write RAMDAC pixel read mask register so all overlay
504 * planes are display-enabled. (CRX24 uses Bt462 pixel
505 * read mask register for overlay planes, not image planes).
507 CRX24_SETUP_RAMDAC(fb);
509 /* change fb->id temporarily to fool SETUP_FB() */
510 saved_id = fb->id;
511 fb->id = CRX24_OVERLAY_PLANES;
512 SETUP_FB(fb);
513 fb->id = saved_id;
515 for (y = 0; y < fb->info.var.yres; ++y)
516 memset(fb->info.screen_base + y * fb->info.fix.line_length,
517 0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8);
519 CRX24_SET_OVLY_MASK(fb);
520 SETUP_FB(fb);
524 #define HYPER_CMAP_TYPE 0
525 #define NGLE_CMAP_INDEXED0_TYPE 0
526 #define NGLE_CMAP_OVERLAY_TYPE 3
528 /* typedef of LUT (Colormap) BLT Control Register */
529 typedef union /* Note assumption that fields are packed left-to-right */
530 { u32 all;
531 struct
533 unsigned enable : 1;
534 unsigned waitBlank : 1;
535 unsigned reserved1 : 4;
536 unsigned lutOffset : 10; /* Within destination LUT */
537 unsigned lutType : 2; /* Cursor, image, overlay */
538 unsigned reserved2 : 4;
539 unsigned length : 10;
540 } fields;
541 } NgleLutBltCtl;
545 static NgleLutBltCtl
546 setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
548 NgleLutBltCtl lutBltCtl;
550 /* set enable, zero reserved fields */
551 lutBltCtl.all = 0x80000000;
553 lutBltCtl.fields.length = length;
554 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
556 /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
557 if (fb->info.var.bits_per_pixel == 8)
558 lutBltCtl.fields.lutOffset = 2 * 256;
559 else
560 lutBltCtl.fields.lutOffset = 0 * 256;
562 /* Offset points to start of LUT. Adjust for within LUT */
563 lutBltCtl.fields.lutOffset += offsetWithinLut;
565 return lutBltCtl;
569 static void hyperUndoITE(struct stifb_info *fb)
571 int nFreeFifoSlots = 0;
572 u32 fbAddr;
574 NGLE_LOCK(fb);
576 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
577 WRITE_WORD(0xffffffff, fb, REG_32);
579 /* Write overlay transparency mask so only entry 255 is transparent */
581 /* Hardware setup for full-depth write to "magic" location */
582 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
583 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
584 BA(IndexedDcd, Otc04, Ots08, AddrLong,
585 BAJustPoint(0), BINovly, BAIndexBase(0)));
586 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
587 IBOvals(RopSrc, MaskAddrOffset(0),
588 BitmapExtent08, StaticReg(0),
589 DataDynamic, MaskOtc, BGx(0), FGx(0)));
591 /* Now prepare to write to the "magic" location */
592 fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
593 NGLE_BINC_SET_DSTADDR(fb, fbAddr);
594 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
595 NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
597 /* Finally, write a zero to clear the mask */
598 NGLE_BINC_WRITE32(fb, 0);
600 NGLE_UNLOCK(fb);
603 static void
604 ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
608 static void
609 ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
613 static void
614 ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
616 int nFreeFifoSlots = 0;
617 u32 packed_dst;
618 u32 packed_len;
620 NGLE_LOCK(fb);
622 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
623 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
624 BA(IndexedDcd, Otc32, OtsIndirect,
625 AddrLong, BAJustPoint(0),
626 BINattr, BAIndexBase(0)));
627 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
628 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
630 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
631 IBOvals(RopSrc, MaskAddrOffset(0),
632 BitmapExtent08, StaticReg(1),
633 DataDynamic, MaskOtc,
634 BGx(0), FGx(0)));
635 packed_dst = 0;
636 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
637 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
638 NGLE_SET_DSTXY(fb, packed_dst);
639 SET_LENXY_START_RECFILL(fb, packed_len);
642 if (fb->id == S9000_ID_A1659A) { /* ELK_DEVICE_ID */
643 /* It's safe to use scanline zero: */
644 packed_dst = (1280 << 16);
645 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
646 NGLE_SET_DSTXY(fb, packed_dst);
647 packed_len = (4 << 16) | 1;
648 SET_LENXY_START_RECFILL(fb, packed_len);
649 } /* ELK Hardware Kludge */
651 /**** Finally, set the Control Plane Register back to zero: ****/
652 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
653 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
655 NGLE_UNLOCK(fb);
658 static void
659 ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
661 int nFreeFifoSlots = 0;
662 u32 packed_dst;
663 u32 packed_len;
665 NGLE_LOCK(fb);
667 /* Hardware setup */
668 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
669 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
670 BA(IndexedDcd, Otc04, Ots08, AddrLong,
671 BAJustPoint(0), BINovly, BAIndexBase(0)));
673 NGLE_SET_TRANSFERDATA(fb, 0xffffffff); /* Write foreground color */
675 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
676 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
678 packed_dst = 0;
679 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
680 NGLE_SET_DSTXY(fb, packed_dst);
682 /* Write zeroes to overlay planes */
683 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
684 IBOvals(RopSrc, MaskAddrOffset(0),
685 BitmapExtent08, StaticReg(0),
686 DataDynamic, MaskOtc, BGx(0), FGx(0)));
688 SET_LENXY_START_RECFILL(fb, packed_len);
690 NGLE_UNLOCK(fb);
693 static void
694 hyperResetPlanes(struct stifb_info *fb, int enable)
696 unsigned int controlPlaneReg;
698 NGLE_LOCK(fb);
700 if (IS_24_DEVICE(fb))
701 if (fb->info.var.bits_per_pixel == 32)
702 controlPlaneReg = 0x04000F00;
703 else
704 controlPlaneReg = 0x00000F00; /* 0x00000800 should be enough, but lets clear all 4 bits */
705 else
706 controlPlaneReg = 0x00000F00; /* 0x00000100 should be enough, but lets clear all 4 bits */
708 switch (enable) {
709 case ENABLE:
710 /* clear screen */
711 if (IS_24_DEVICE(fb))
712 ngleDepth24_ClearImagePlanes(fb);
713 else
714 ngleDepth8_ClearImagePlanes(fb);
716 /* Paint attribute planes for default case.
717 * On Hyperdrive, this means all windows using overlay cmap 0. */
718 ngleResetAttrPlanes(fb, controlPlaneReg);
720 /* clear overlay planes */
721 ngleClearOverlayPlanes(fb, 0xff, 255);
723 /**************************************************
724 ** Also need to counteract ITE settings
725 **************************************************/
726 hyperUndoITE(fb);
727 break;
729 case DISABLE:
730 /* clear screen */
731 if (IS_24_DEVICE(fb))
732 ngleDepth24_ClearImagePlanes(fb);
733 else
734 ngleDepth8_ClearImagePlanes(fb);
735 ngleResetAttrPlanes(fb, controlPlaneReg);
736 ngleClearOverlayPlanes(fb, 0xff, 0);
737 break;
739 case -1: /* RESET */
740 hyperUndoITE(fb);
741 ngleResetAttrPlanes(fb, controlPlaneReg);
742 break;
745 NGLE_UNLOCK(fb);
748 /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
750 static void
751 ngleGetDeviceRomData(struct stifb_info *fb)
756 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
757 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8
758 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10
759 #define HYPERBOWL_MODE2_8_24 15
761 /* HCRX specific boot-time initialization */
762 static void __init
763 SETUP_HCRX(struct stifb_info *fb)
765 int hyperbowl;
766 int nFreeFifoSlots = 0;
768 if (fb->id != S9000_ID_HCRX)
769 return;
771 /* Initialize Hyperbowl registers */
772 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
774 if (IS_24_DEVICE(fb)) {
775 hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
776 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
777 HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
779 /* First write to Hyperbowl must happen twice (bug) */
780 WRITE_WORD(hyperbowl, fb, REG_40);
781 WRITE_WORD(hyperbowl, fb, REG_40);
783 WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
785 WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
786 WRITE_WORD(0x404c4048, fb, REG_43);
787 WRITE_WORD(0x034c0348, fb, REG_44);
788 WRITE_WORD(0x444c4448, fb, REG_45);
789 } else {
790 hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
792 /* First write to Hyperbowl must happen twice (bug) */
793 WRITE_WORD(hyperbowl, fb, REG_40);
794 WRITE_WORD(hyperbowl, fb, REG_40);
796 WRITE_WORD(0x00000000, fb, REG_42);
797 WRITE_WORD(0x00000000, fb, REG_43);
798 WRITE_WORD(0x00000000, fb, REG_44);
799 WRITE_WORD(0x444c4048, fb, REG_45);
804 /* ------------------- driver specific functions --------------------------- */
806 static int
807 stifb_setcolreg(u_int regno, u_int red, u_int green,
808 u_int blue, u_int transp, struct fb_info *info)
810 struct stifb_info *fb = (struct stifb_info *) info;
811 u32 color;
813 if (regno >= NR_PALETTE)
814 return 1;
816 red >>= 8;
817 green >>= 8;
818 blue >>= 8;
820 DEBUG_OFF();
822 START_IMAGE_COLORMAP_ACCESS(fb);
824 if (unlikely(fb->info.var.grayscale)) {
825 /* gray = 0.30*R + 0.59*G + 0.11*B */
826 color = ((red * 77) +
827 (green * 151) +
828 (blue * 28)) >> 8;
829 } else {
830 color = ((red << 16) |
831 (green << 8) |
832 (blue));
835 if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
836 struct fb_var_screeninfo *var = &fb->info.var;
837 if (regno < 16)
838 ((u32 *)fb->info.pseudo_palette)[regno] =
839 regno << var->red.offset |
840 regno << var->green.offset |
841 regno << var->blue.offset;
844 WRITE_IMAGE_COLOR(fb, regno, color);
846 if (fb->id == S9000_ID_HCRX) {
847 NgleLutBltCtl lutBltCtl;
849 lutBltCtl = setHyperLutBltCtl(fb,
850 0, /* Offset w/i LUT */
851 256); /* Load entire LUT */
852 NGLE_BINC_SET_SRCADDR(fb,
853 NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
854 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
855 START_COLORMAPLOAD(fb, lutBltCtl.all);
856 SETUP_FB(fb);
857 } else {
858 /* cleanup colormap hardware */
859 FINISH_IMAGE_COLORMAP_ACCESS(fb);
862 DEBUG_ON();
864 return 0;
867 static int
868 stifb_blank(int blank_mode, struct fb_info *info)
870 struct stifb_info *fb = (struct stifb_info *) info;
871 int enable = (blank_mode == 0) ? ENABLE : DISABLE;
873 switch (fb->id) {
874 case S9000_ID_A1439A:
875 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
876 break;
877 case CRT_ID_VISUALIZE_EG:
878 case S9000_ID_ARTIST:
879 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
880 break;
881 case S9000_ID_HCRX:
882 HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
883 break;
884 case S9000_ID_A1659A: /* fall through */
885 case S9000_ID_TIMBER:
886 case CRX24_OVERLAY_PLANES:
887 default:
888 ENABLE_DISABLE_DISPLAY(fb, enable);
889 break;
892 SETUP_FB(fb);
893 return 0;
896 static void __init
897 stifb_init_display(struct stifb_info *fb)
899 int id = fb->id;
901 SETUP_FB(fb);
903 /* HCRX specific initialization */
904 SETUP_HCRX(fb);
907 if (id == S9000_ID_HCRX)
908 hyperInitSprite(fb);
909 else
910 ngleInitSprite(fb);
913 /* Initialize the image planes. */
914 switch (id) {
915 case S9000_ID_HCRX:
916 hyperResetPlanes(fb, ENABLE);
917 break;
918 case S9000_ID_A1439A:
919 rattlerSetupPlanes(fb);
920 break;
921 case S9000_ID_A1659A:
922 case S9000_ID_ARTIST:
923 case CRT_ID_VISUALIZE_EG:
924 elkSetupPlanes(fb);
925 break;
928 /* Clear attribute planes on non HCRX devices. */
929 switch (id) {
930 case S9000_ID_A1659A:
931 case S9000_ID_A1439A:
932 if (fb->info.var.bits_per_pixel == 32)
933 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
934 else {
935 ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
937 if (id == S9000_ID_A1439A)
938 ngleClearOverlayPlanes(fb, 0xff, 0);
939 break;
940 case S9000_ID_ARTIST:
941 case CRT_ID_VISUALIZE_EG:
942 if (fb->info.var.bits_per_pixel == 32)
943 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
944 else {
945 ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
947 break;
949 stifb_blank(0, (struct fb_info *)fb); /* 0=enable screen */
951 SETUP_FB(fb);
954 /* ------------ Interfaces to hardware functions ------------ */
956 static struct fb_ops stifb_ops = {
957 .owner = THIS_MODULE,
958 .fb_setcolreg = stifb_setcolreg,
959 .fb_blank = stifb_blank,
960 .fb_fillrect = cfb_fillrect,
961 .fb_copyarea = cfb_copyarea,
962 .fb_imageblit = cfb_imageblit,
967 * Initialization
970 static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
972 struct fb_fix_screeninfo *fix;
973 struct fb_var_screeninfo *var;
974 struct stifb_info *fb;
975 struct fb_info *info;
976 unsigned long sti_rom_address;
977 char *dev_name;
978 int bpp, xres, yres;
980 fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
981 if (!fb) {
982 printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
983 return -ENODEV;
986 info = &fb->info;
988 /* set struct to a known state */
989 fix = &info->fix;
990 var = &info->var;
992 fb->sti = sti;
993 /* store upper 32bits of the graphics id */
994 fb->id = fb->sti->graphics_id[0];
996 /* only supported cards are allowed */
997 switch (fb->id) {
998 case CRT_ID_VISUALIZE_EG:
999 /* Visualize cards can run either in "double buffer" or
1000 "standard" mode. Depending on the mode, the card reports
1001 a different device name, e.g. "INTERNAL_EG_DX1024" in double
1002 buffer mode and "INTERNAL_EG_X1024" in standard mode.
1003 Since this driver only supports standard mode, we check
1004 if the device name contains the string "DX" and tell the
1005 user how to reconfigure the card. */
1006 if (strstr(sti->outptr.dev_name, "DX")) {
1007 printk(KERN_WARNING
1008 "WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
1009 "WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
1010 sti->outptr.dev_name);
1011 goto out_err0;
1013 /* fall though */
1014 case S9000_ID_ARTIST:
1015 case S9000_ID_HCRX:
1016 case S9000_ID_TIMBER:
1017 case S9000_ID_A1659A:
1018 case S9000_ID_A1439A:
1019 break;
1020 default:
1021 printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1022 sti->outptr.dev_name, fb->id);
1023 goto out_err0;
1026 /* default to 8 bpp on most graphic chips */
1027 bpp = 8;
1028 xres = sti_onscreen_x(fb->sti);
1029 yres = sti_onscreen_y(fb->sti);
1031 ngleGetDeviceRomData(fb);
1033 /* get (virtual) io region base addr */
1034 fix->mmio_start = REGION_BASE(fb,2);
1035 fix->mmio_len = 0x400000;
1037 /* Reject any device not in the NGLE family */
1038 switch (fb->id) {
1039 case S9000_ID_A1659A: /* CRX/A1659A */
1040 break;
1041 case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */
1042 var->grayscale = 1;
1043 fb->id = S9000_ID_A1659A;
1044 break;
1045 case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */
1046 dev_name = fb->sti->outptr.dev_name;
1047 if (strstr(dev_name, "GRAYSCALE") ||
1048 strstr(dev_name, "Grayscale") ||
1049 strstr(dev_name, "grayscale"))
1050 var->grayscale = 1;
1051 break;
1052 case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */
1053 xres = fb->ngle_rom.x_size_visible;
1054 yres = fb->ngle_rom.y_size_visible;
1055 fb->id = S9000_ID_A1659A;
1056 break;
1057 case S9000_ID_A1439A: /* CRX24/A1439A */
1058 bpp = 32;
1059 break;
1060 case S9000_ID_HCRX: /* Hyperdrive/HCRX */
1061 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1062 if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1063 (fb->sti->regions_phys[2] & 0xfc000000))
1064 sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1065 else
1066 sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1068 fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1069 if (IS_24_DEVICE(fb)) {
1070 if (bpp_pref == 8 || bpp_pref == 32)
1071 bpp = bpp_pref;
1072 else
1073 bpp = 32;
1074 } else
1075 bpp = 8;
1076 READ_WORD(fb, REG_15);
1077 SETUP_HW(fb);
1078 break;
1079 case CRT_ID_VISUALIZE_EG:
1080 case S9000_ID_ARTIST: /* Artist */
1081 break;
1082 default:
1083 #ifdef FALLBACK_TO_1BPP
1084 printk(KERN_WARNING
1085 "stifb: Unsupported graphics card (id=0x%08x) "
1086 "- now trying 1bpp mode instead\n",
1087 fb->id);
1088 bpp = 1; /* default to 1 bpp */
1089 break;
1090 #else
1091 printk(KERN_WARNING
1092 "stifb: Unsupported graphics card (id=0x%08x) "
1093 "- skipping.\n",
1094 fb->id);
1095 goto out_err0;
1096 #endif
1100 /* get framebuffer physical and virtual base addr & len (64bit ready) */
1101 fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1102 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1104 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1105 if (!fix->line_length)
1106 fix->line_length = 2048; /* default */
1108 /* limit fbsize to max visible screen size */
1109 if (fix->smem_len > yres*fix->line_length)
1110 fix->smem_len = yres*fix->line_length;
1112 fix->accel = FB_ACCEL_NONE;
1114 switch (bpp) {
1115 case 1:
1116 fix->type = FB_TYPE_PLANES; /* well, sort of */
1117 fix->visual = FB_VISUAL_MONO10;
1118 var->red.length = var->green.length = var->blue.length = 1;
1119 break;
1120 case 8:
1121 fix->type = FB_TYPE_PACKED_PIXELS;
1122 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1123 var->red.length = var->green.length = var->blue.length = 8;
1124 break;
1125 case 32:
1126 fix->type = FB_TYPE_PACKED_PIXELS;
1127 fix->visual = FB_VISUAL_DIRECTCOLOR;
1128 var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1129 var->blue.offset = 0;
1130 var->green.offset = 8;
1131 var->red.offset = 16;
1132 var->transp.offset = 24;
1133 break;
1134 default:
1135 break;
1138 var->xres = var->xres_virtual = xres;
1139 var->yres = var->yres_virtual = yres;
1140 var->bits_per_pixel = bpp;
1142 strcpy(fix->id, "stifb");
1143 info->fbops = &stifb_ops;
1144 info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
1145 info->screen_size = fix->smem_len;
1146 info->flags = FBINFO_DEFAULT;
1147 info->pseudo_palette = &fb->pseudo_palette;
1149 /* This has to be done !!! */
1150 if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
1151 goto out_err1;
1152 stifb_init_display(fb);
1154 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1155 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1156 fix->smem_start, fix->smem_start+fix->smem_len);
1157 goto out_err2;
1160 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1161 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1162 fix->mmio_start, fix->mmio_start+fix->mmio_len);
1163 goto out_err3;
1166 if (register_framebuffer(&fb->info) < 0)
1167 goto out_err4;
1169 sti->info = info; /* save for unregister_framebuffer() */
1171 printk(KERN_INFO
1172 "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1173 fb->info.node,
1174 fix->id,
1175 var->xres,
1176 var->yres,
1177 var->bits_per_pixel,
1178 sti->outptr.dev_name,
1179 fb->id,
1180 fix->mmio_start);
1182 return 0;
1185 out_err4:
1186 release_mem_region(fix->mmio_start, fix->mmio_len);
1187 out_err3:
1188 release_mem_region(fix->smem_start, fix->smem_len);
1189 out_err2:
1190 fb_dealloc_cmap(&info->cmap);
1191 out_err1:
1192 iounmap(info->screen_base);
1193 out_err0:
1194 kfree(fb);
1195 return -ENXIO;
1198 static int stifb_disabled __initdata;
1200 int __init
1201 stifb_setup(char *options);
1203 static int __init stifb_init(void)
1205 struct sti_struct *sti;
1206 struct sti_struct *def_sti;
1207 int i;
1209 #ifndef MODULE
1210 char *option = NULL;
1212 if (fb_get_options("stifb", &option))
1213 return -ENODEV;
1214 stifb_setup(option);
1215 #endif
1216 if (stifb_disabled) {
1217 printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1218 return -ENXIO;
1221 def_sti = sti_get_rom(0);
1222 if (def_sti) {
1223 for (i = 1; i <= MAX_STI_ROMS; i++) {
1224 sti = sti_get_rom(i);
1225 if (!sti)
1226 break;
1227 if (sti == def_sti) {
1228 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1229 break;
1234 for (i = 1; i <= MAX_STI_ROMS; i++) {
1235 sti = sti_get_rom(i);
1236 if (!sti)
1237 break;
1238 if (sti == def_sti)
1239 continue;
1240 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1242 return 0;
1246 * Cleanup
1249 static void __exit
1250 stifb_cleanup(void)
1252 struct sti_struct *sti;
1253 int i;
1255 for (i = 1; i <= MAX_STI_ROMS; i++) {
1256 sti = sti_get_rom(i);
1257 if (!sti)
1258 break;
1259 if (sti->info) {
1260 struct fb_info *info = sti->info;
1261 unregister_framebuffer(sti->info);
1262 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1263 release_mem_region(info->fix.smem_start, info->fix.smem_len);
1264 if (info->screen_base)
1265 iounmap(info->screen_base);
1266 fb_dealloc_cmap(&info->cmap);
1267 framebuffer_release(info);
1269 sti->info = NULL;
1273 int __init
1274 stifb_setup(char *options)
1276 int i;
1278 if (!options || !*options)
1279 return 1;
1281 if (strncmp(options, "off", 3) == 0) {
1282 stifb_disabled = 1;
1283 options += 3;
1286 if (strncmp(options, "bpp", 3) == 0) {
1287 options += 3;
1288 for (i = 0; i < MAX_STI_ROMS; i++) {
1289 if (*options++ != ':')
1290 break;
1291 stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1294 return 1;
1297 __setup("stifb=", stifb_setup);
1299 module_init(stifb_init);
1300 module_exit(stifb_cleanup);
1302 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1303 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1304 MODULE_LICENSE("GPL v2");