blob: 56d71d6e9a724df370757a58a34a22a38ff1bc1a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/video/stifb.c -
3 * Low level Frame buffer driver for HP workstations with
4 * STI (standard text interface) video firmware.
5 *
Helge Dellerdaaeb6f2006-01-10 20:48:04 -05006 * Copyright (C) 2001-2005 Helge Deller <deller@gmx.de>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * 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.
16 *
17 *
18 * The following graphics display devices (NGLE family) are supported by this driver:
19 *
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)
35 *
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.
39 */
40
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)
46 */
47
48
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
53
54#undef DEBUG_STIFB_REGS /* debug sti register accesses */
55
56
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>
62#include <linux/mm.h>
63#include <linux/slab.h>
64#include <linux/delay.h>
65#include <linux/fb.h>
66#include <linux/init.h>
67#include <linux/ioport.h>
68#include <linux/pci.h>
69
70#include <asm/grfioctl.h> /* for HP-UX compatibility */
71#include <asm/uaccess.h>
72
73#include "sticore.h"
74
75/* REGION_BASE(fb_info, index) returns the virtual address for region <index> */
Helge Deller5d6d1642006-01-10 20:48:03 -050076#define REGION_BASE(fb_info, index) \
77 F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index])
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79#define NGLEDEVDEPROM_CRT_REGION 1
80
Helge Dellerdaaeb6f2006-01-10 20:48:04 -050081#define NR_PALETTE 256
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083typedef struct {
84 __s32 video_config_reg;
85 __s32 misc_video_start;
86 __s32 horiz_timing_fmt;
87 __s32 serr_timing_fmt;
88 __s32 vert_timing_fmt;
89 __s32 horiz_state;
90 __s32 vert_state;
91 __s32 vtg_state_elements;
92 __s32 pipeline_delay;
93 __s32 misc_video_end;
94} video_setup_t;
95
96typedef struct {
97 __s16 sizeof_ngle_data;
98 __s16 x_size_visible; /* visible screen dim in pixels */
99 __s16 y_size_visible;
100 __s16 pad2[15];
101 __s16 cursor_pipeline_delay;
102 __s16 video_interleaves;
103 __s32 pad3[11];
104} ngle_rom_t;
105
106struct stifb_info {
107 struct fb_info info;
108 unsigned int id;
109 ngle_rom_t ngle_rom;
110 struct sti_struct *sti;
111 int deviceSpecificConfig;
Helge Dellerdaaeb6f2006-01-10 20:48:04 -0500112 u32 pseudo_palette[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113};
114
115static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
116
117/* ------------------- chipset specific functions -------------------------- */
118
119/* offsets to graphic-chip internal registers */
120
121#define REG_1 0x000118
122#define REG_2 0x000480
123#define REG_3 0x0004a0
124#define REG_4 0x000600
125#define REG_6 0x000800
126#define REG_8 0x000820
127#define REG_9 0x000a04
128#define REG_10 0x018000
129#define REG_11 0x018004
130#define REG_12 0x01800c
131#define REG_13 0x018018
132#define REG_14 0x01801c
133#define REG_15 0x200000
134#define REG_15b0 0x200000
135#define REG_16b1 0x200005
136#define REG_16b3 0x200007
137#define REG_21 0x200218
138#define REG_22 0x0005a0
139#define REG_23 0x0005c0
140#define REG_26 0x200118
141#define REG_27 0x200308
142#define REG_32 0x21003c
143#define REG_33 0x210040
144#define REG_34 0x200008
145#define REG_35 0x018010
146#define REG_38 0x210020
147#define REG_39 0x210120
148#define REG_40 0x210130
149#define REG_42 0x210028
150#define REG_43 0x21002c
151#define REG_44 0x210030
152#define REG_45 0x210034
153
154#define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg))
155#define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg))
156
157
158#ifndef DEBUG_STIFB_REGS
159# define DEBUG_OFF()
160# define DEBUG_ON()
161# define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
162# define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
163#else
164 static int debug_on = 1;
165# define DEBUG_OFF() debug_on=0
166# define DEBUG_ON() debug_on=1
167# define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
168 printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
169 __FUNCTION__, reg, value, READ_BYTE(fb,reg)); \
170 gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
171# define WRITE_WORD(value,fb,reg) do { if (debug_on) \
172 printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
173 __FUNCTION__, reg, value, READ_WORD(fb,reg)); \
174 gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
175#endif /* DEBUG_STIFB_REGS */
176
177
178#define ENABLE 1 /* for enabling/disabling screen */
179#define DISABLE 0
180
181#define NGLE_LOCK(fb_info) do { } while (0)
182#define NGLE_UNLOCK(fb_info) do { } while (0)
183
184static void
185SETUP_HW(struct stifb_info *fb)
186{
187 char stat;
188
189 do {
190 stat = READ_BYTE(fb, REG_15b0);
191 if (!stat)
192 stat = READ_BYTE(fb, REG_15b0);
193 } while (stat);
194}
195
196
197static void
198SETUP_FB(struct stifb_info *fb)
199{
200 unsigned int reg10_value = 0;
201
202 SETUP_HW(fb);
203 switch (fb->id)
204 {
205 case CRT_ID_VISUALIZE_EG:
206 case S9000_ID_ARTIST:
207 case S9000_ID_A1659A:
208 reg10_value = 0x13601000;
209 break;
210 case S9000_ID_A1439A:
211 if (fb->info.var.bits_per_pixel == 32)
212 reg10_value = 0xBBA0A000;
213 else
214 reg10_value = 0x13601000;
215 break;
216 case S9000_ID_HCRX:
217 if (fb->info.var.bits_per_pixel == 32)
218 reg10_value = 0xBBA0A000;
219 else
220 reg10_value = 0x13602000;
221 break;
222 case S9000_ID_TIMBER:
223 case CRX24_OVERLAY_PLANES:
224 reg10_value = 0x13602000;
225 break;
226 }
227 if (reg10_value)
228 WRITE_WORD(reg10_value, fb, REG_10);
229 WRITE_WORD(0x83000300, fb, REG_14);
230 SETUP_HW(fb);
231 WRITE_BYTE(1, fb, REG_16b1);
232}
233
234static void
235START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
236{
237 SETUP_HW(fb);
238 WRITE_WORD(0xBBE0F000, fb, REG_10);
239 WRITE_WORD(0x03000300, fb, REG_14);
240 WRITE_WORD(~0, fb, REG_13);
241}
242
243static void
244WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
245{
246 SETUP_HW(fb);
247 WRITE_WORD(((0x100+index)<<2), fb, REG_3);
248 WRITE_WORD(color, fb, REG_4);
249}
250
251static void
252FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
253{
254 WRITE_WORD(0x400, fb, REG_2);
255 if (fb->info.var.bits_per_pixel == 32) {
256 WRITE_WORD(0x83000100, fb, REG_1);
257 } else {
258 if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
259 WRITE_WORD(0x80000100, fb, REG_26);
260 else
261 WRITE_WORD(0x80000100, fb, REG_1);
262 }
263 SETUP_FB(fb);
264}
265
266static void
267SETUP_RAMDAC(struct stifb_info *fb)
268{
269 SETUP_HW(fb);
270 WRITE_WORD(0x04000000, fb, 0x1020);
271 WRITE_WORD(0xff000000, fb, 0x1028);
272}
273
274static void
275CRX24_SETUP_RAMDAC(struct stifb_info *fb)
276{
277 SETUP_HW(fb);
278 WRITE_WORD(0x04000000, fb, 0x1000);
279 WRITE_WORD(0x02000000, fb, 0x1004);
280 WRITE_WORD(0xff000000, fb, 0x1008);
281 WRITE_WORD(0x05000000, fb, 0x1000);
282 WRITE_WORD(0x02000000, fb, 0x1004);
283 WRITE_WORD(0x03000000, fb, 0x1008);
284}
285
286#if 0
287static void
288HCRX_SETUP_RAMDAC(struct stifb_info *fb)
289{
290 WRITE_WORD(0xffffffff, fb, REG_32);
291}
292#endif
293
294static void
295CRX24_SET_OVLY_MASK(struct stifb_info *fb)
296{
297 SETUP_HW(fb);
298 WRITE_WORD(0x13a02000, fb, REG_11);
299 WRITE_WORD(0x03000300, fb, REG_14);
300 WRITE_WORD(0x000017f0, fb, REG_3);
301 WRITE_WORD(0xffffffff, fb, REG_13);
302 WRITE_WORD(0xffffffff, fb, REG_22);
303 WRITE_WORD(0x00000000, fb, REG_23);
304}
305
306static void
307ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
308{
309 unsigned int value = enable ? 0x43000000 : 0x03000000;
310 SETUP_HW(fb);
311 WRITE_WORD(0x06000000, fb, 0x1030);
312 WRITE_WORD(value, fb, 0x1038);
313}
314
315static void
316CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
317{
318 unsigned int value = enable ? 0x10000000 : 0x30000000;
319 SETUP_HW(fb);
320 WRITE_WORD(0x01000000, fb, 0x1000);
321 WRITE_WORD(0x02000000, fb, 0x1004);
322 WRITE_WORD(value, fb, 0x1008);
323}
324
325static void
326ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
327{
328 u32 DregsMiscVideo = REG_21;
329 u32 DregsMiscCtl = REG_27;
330
331 SETUP_HW(fb);
332 if (enable) {
333 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
334 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl);
335 } else {
336 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
337 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl);
338 }
339}
340
341#define GET_ROMTABLE_INDEX(fb) \
342 (READ_BYTE(fb, REG_16b3) - 1)
343
344#define HYPER_CONFIG_PLANES_24 0x00000100
345
346#define IS_24_DEVICE(fb) \
347 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
348
349#define IS_888_DEVICE(fb) \
350 (!(IS_24_DEVICE(fb)))
351
Helge Dellerdaaeb6f2006-01-10 20:48:04 -0500352#define GET_FIFO_SLOTS(fb, cnt, numslots) \
353{ while (cnt < numslots) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 cnt = READ_WORD(fb, REG_34); \
Helge Dellerdaaeb6f2006-01-10 20:48:04 -0500355 cnt -= numslots; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356}
357
358#define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
359#define Otc04 2 /* Pixels in each longword transfer (4) */
360#define Otc32 5 /* Pixels in each longword transfer (32) */
361#define Ots08 3 /* Each pixel is size (8)d transfer (1) */
362#define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */
363#define AddrLong 5 /* FB address is Long aligned (pixel) */
364#define BINovly 0x2 /* 8 bit overlay */
365#define BINapp0I 0x0 /* Application Buffer 0, Indexed */
366#define BINapp1I 0x1 /* Application Buffer 1, Indexed */
367#define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */
368#define BINattr 0xd /* Attribute Bitmap */
369#define RopSrc 0x3
370#define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */
371#define BitmapExtent32 5 /* Each write hits (32) bits in depth */
372#define DataDynamic 0 /* Data register reloaded by direct access */
373#define MaskDynamic 1 /* Mask register reloaded by direct access */
374#define MaskOtc 0 /* Mask contains Object Count valid bits */
375
376#define MaskAddrOffset(offset) (offset)
377#define StaticReg(en) (en)
378#define BGx(en) (en)
379#define FGx(en) (en)
380
381#define BAJustPoint(offset) (offset)
382#define BAIndexBase(base) (base)
383#define BA(F,C,S,A,J,B,I) \
384 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
385
386#define IBOvals(R,M,X,S,D,L,B,F) \
387 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
388
389#define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
390 WRITE_WORD(val, fb, REG_14)
391
392#define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
393 WRITE_WORD(val, fb, REG_11)
394
395#define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
396 WRITE_WORD(val, fb, REG_12)
397
398#define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
399 WRITE_WORD(plnmsk32, fb, REG_13)
400
401#define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
402 WRITE_WORD(fg32, fb, REG_35)
403
404#define NGLE_SET_TRANSFERDATA(fb, val) \
405 WRITE_WORD(val, fb, REG_8)
406
407#define NGLE_SET_DSTXY(fb, val) \
408 WRITE_WORD(val, fb, REG_6)
409
410#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
411 (u32) (fbaddrbase) + \
412 ( (unsigned int) ( (y) << 13 ) | \
413 (unsigned int) ( (x) << 2 ) ) \
414 )
415
416#define NGLE_BINC_SET_DSTADDR(fb, addr) \
417 WRITE_WORD(addr, fb, REG_3)
418
419#define NGLE_BINC_SET_SRCADDR(fb, addr) \
420 WRITE_WORD(addr, fb, REG_2)
421
422#define NGLE_BINC_SET_DSTMASK(fb, mask) \
423 WRITE_WORD(mask, fb, REG_22)
424
425#define NGLE_BINC_WRITE32(fb, data32) \
426 WRITE_WORD(data32, fb, REG_23)
427
428#define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
429 WRITE_WORD((cmapBltCtlData32), fb, REG_38)
430
431#define SET_LENXY_START_RECFILL(fb, lenxy) \
432 WRITE_WORD(lenxy, fb, REG_9)
433
434static void
435HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
436{
437 u32 DregsHypMiscVideo = REG_33;
438 unsigned int value;
439 SETUP_HW(fb);
440 value = READ_WORD(fb, DregsHypMiscVideo);
441 if (enable)
442 value |= 0x0A000000;
443 else
444 value &= ~0x0A000000;
445 WRITE_WORD(value, fb, DregsHypMiscVideo);
446}
447
448
449/* BufferNumbers used by SETUP_ATTR_ACCESS() */
450#define BUFF0_CMAP0 0x00001e02
451#define BUFF1_CMAP0 0x02001e02
452#define BUFF1_CMAP3 0x0c001e02
453#define ARTIST_CMAP0 0x00000102
454#define HYPER_CMAP8 0x00000100
455#define HYPER_CMAP24 0x00000800
456
457static void
458SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
459{
460 SETUP_HW(fb);
461 WRITE_WORD(0x2EA0D000, fb, REG_11);
462 WRITE_WORD(0x23000302, fb, REG_14);
463 WRITE_WORD(BufferNumber, fb, REG_12);
464 WRITE_WORD(0xffffffff, fb, REG_8);
465}
466
467static void
468SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
469{
470 /* REG_6 seems to have special values when run on a
471 RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
472 INTERNAL_EG_X1024). The values are:
473 0x2f0: internal (LCD) & external display enabled
474 0x2a0: external display only
475 0x000: zero on standard artist graphic cards
476 */
477 WRITE_WORD(0x00000000, fb, REG_6);
478 WRITE_WORD((width<<16) | height, fb, REG_9);
479 WRITE_WORD(0x05000000, fb, REG_6);
480 WRITE_WORD(0x00040001, fb, REG_9);
481}
482
483static void
484FINISH_ATTR_ACCESS(struct stifb_info *fb)
485{
486 SETUP_HW(fb);
487 WRITE_WORD(0x00000000, fb, REG_12);
488}
489
490static void
491elkSetupPlanes(struct stifb_info *fb)
492{
493 SETUP_RAMDAC(fb);
494 SETUP_FB(fb);
495}
496
497static void
498ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
499{
500 SETUP_ATTR_ACCESS(fb, BufferNumber);
501 SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
502 FINISH_ATTR_ACCESS(fb);
503 SETUP_FB(fb);
504}
505
506
507static void
508rattlerSetupPlanes(struct stifb_info *fb)
509{
510 CRX24_SETUP_RAMDAC(fb);
511
512 /* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */
513 WRITE_WORD(0x83000300, fb, REG_14);
514 SETUP_HW(fb);
515 WRITE_BYTE(1, fb, REG_16b1);
516
517 fb_memset(fb->info.fix.smem_start, 0xff,
518 fb->info.var.yres*fb->info.fix.line_length);
519
520 CRX24_SET_OVLY_MASK(fb);
521 SETUP_FB(fb);
522}
523
524
525#define HYPER_CMAP_TYPE 0
526#define NGLE_CMAP_INDEXED0_TYPE 0
527#define NGLE_CMAP_OVERLAY_TYPE 3
528
529/* typedef of LUT (Colormap) BLT Control Register */
530typedef union /* Note assumption that fields are packed left-to-right */
531{ u32 all;
532 struct
533 {
534 unsigned enable : 1;
535 unsigned waitBlank : 1;
536 unsigned reserved1 : 4;
537 unsigned lutOffset : 10; /* Within destination LUT */
538 unsigned lutType : 2; /* Cursor, image, overlay */
539 unsigned reserved2 : 4;
540 unsigned length : 10;
541 } fields;
542} NgleLutBltCtl;
543
544
545#if 0
546static NgleLutBltCtl
547setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
548{
549 NgleLutBltCtl lutBltCtl;
550
551 /* set enable, zero reserved fields */
552 lutBltCtl.all = 0x80000000;
553 lutBltCtl.fields.length = length;
554
555 switch (fb->id)
556 {
557 case S9000_ID_A1439A: /* CRX24 */
558 if (fb->var.bits_per_pixel == 8) {
559 lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
560 lutBltCtl.fields.lutOffset = 0;
561 } else {
562 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
563 lutBltCtl.fields.lutOffset = 0 * 256;
564 }
565 break;
566
567 case S9000_ID_ARTIST:
568 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
569 lutBltCtl.fields.lutOffset = 0 * 256;
570 break;
571
572 default:
573 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
574 lutBltCtl.fields.lutOffset = 0;
575 break;
576 }
577
578 /* Offset points to start of LUT. Adjust for within LUT */
579 lutBltCtl.fields.lutOffset += offsetWithinLut;
580
581 return lutBltCtl;
582}
583#endif
584
585static NgleLutBltCtl
586setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
587{
588 NgleLutBltCtl lutBltCtl;
589
590 /* set enable, zero reserved fields */
591 lutBltCtl.all = 0x80000000;
592
593 lutBltCtl.fields.length = length;
594 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
595
596 /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
597 if (fb->info.var.bits_per_pixel == 8)
598 lutBltCtl.fields.lutOffset = 2 * 256;
599 else
600 lutBltCtl.fields.lutOffset = 0 * 256;
601
602 /* Offset points to start of LUT. Adjust for within LUT */
603 lutBltCtl.fields.lutOffset += offsetWithinLut;
604
605 return lutBltCtl;
606}
607
608
609static void hyperUndoITE(struct stifb_info *fb)
610{
611 int nFreeFifoSlots = 0;
612 u32 fbAddr;
613
614 NGLE_LOCK(fb);
615
616 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
617 WRITE_WORD(0xffffffff, fb, REG_32);
618
619 /* Write overlay transparency mask so only entry 255 is transparent */
620
621 /* Hardware setup for full-depth write to "magic" location */
622 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
623 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
624 BA(IndexedDcd, Otc04, Ots08, AddrLong,
625 BAJustPoint(0), BINovly, BAIndexBase(0)));
626 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
627 IBOvals(RopSrc, MaskAddrOffset(0),
628 BitmapExtent08, StaticReg(0),
629 DataDynamic, MaskOtc, BGx(0), FGx(0)));
630
631 /* Now prepare to write to the "magic" location */
632 fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
633 NGLE_BINC_SET_DSTADDR(fb, fbAddr);
634 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
635 NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
636
637 /* Finally, write a zero to clear the mask */
638 NGLE_BINC_WRITE32(fb, 0);
639
640 NGLE_UNLOCK(fb);
641}
642
643static void
644ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
645{
646 /* FIXME! */
647}
648
649static void
650ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
651{
652 /* FIXME! */
653}
654
655static void
656ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
657{
658 int nFreeFifoSlots = 0;
659 u32 packed_dst;
660 u32 packed_len;
661
662 NGLE_LOCK(fb);
663
664 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
665 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
666 BA(IndexedDcd, Otc32, OtsIndirect,
667 AddrLong, BAJustPoint(0),
668 BINattr, BAIndexBase(0)));
669 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
670 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
671
672 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
673 IBOvals(RopSrc, MaskAddrOffset(0),
674 BitmapExtent08, StaticReg(1),
675 DataDynamic, MaskOtc,
676 BGx(0), FGx(0)));
677 packed_dst = 0;
678 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
679 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
680 NGLE_SET_DSTXY(fb, packed_dst);
681 SET_LENXY_START_RECFILL(fb, packed_len);
682
683 /*
684 * In order to work around an ELK hardware problem (Buffy doesn't
685 * always flush it's buffers when writing to the attribute
686 * planes), at least 4 pixels must be written to the attribute
687 * planes starting at (X == 1280) and (Y != to the last Y written
688 * by BIF):
689 */
690
691 if (fb->id == S9000_ID_A1659A) { /* ELK_DEVICE_ID */
692 /* It's safe to use scanline zero: */
693 packed_dst = (1280 << 16);
694 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
695 NGLE_SET_DSTXY(fb, packed_dst);
696 packed_len = (4 << 16) | 1;
697 SET_LENXY_START_RECFILL(fb, packed_len);
698 } /* ELK Hardware Kludge */
699
700 /**** Finally, set the Control Plane Register back to zero: ****/
701 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
702 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
703
704 NGLE_UNLOCK(fb);
705}
706
707static void
708ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
709{
710 int nFreeFifoSlots = 0;
711 u32 packed_dst;
712 u32 packed_len;
713
714 NGLE_LOCK(fb);
715
716 /* Hardware setup */
717 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
718 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
719 BA(IndexedDcd, Otc04, Ots08, AddrLong,
720 BAJustPoint(0), BINovly, BAIndexBase(0)));
721
722 NGLE_SET_TRANSFERDATA(fb, 0xffffffff); /* Write foreground color */
723
724 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
725 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
726
727 packed_dst = 0;
728 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
729 NGLE_SET_DSTXY(fb, packed_dst);
730
731 /* Write zeroes to overlay planes */
732 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
733 IBOvals(RopSrc, MaskAddrOffset(0),
734 BitmapExtent08, StaticReg(0),
735 DataDynamic, MaskOtc, BGx(0), FGx(0)));
736
737 SET_LENXY_START_RECFILL(fb, packed_len);
738
739 NGLE_UNLOCK(fb);
740}
741
742static void
743hyperResetPlanes(struct stifb_info *fb, int enable)
744{
745 unsigned int controlPlaneReg;
746
747 NGLE_LOCK(fb);
748
749 if (IS_24_DEVICE(fb))
750 if (fb->info.var.bits_per_pixel == 32)
751 controlPlaneReg = 0x04000F00;
752 else
753 controlPlaneReg = 0x00000F00; /* 0x00000800 should be enought, but lets clear all 4 bits */
754 else
755 controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
756
757 switch (enable) {
758 case ENABLE:
759 /* clear screen */
760 if (IS_24_DEVICE(fb))
761 ngleDepth24_ClearImagePlanes(fb);
762 else
763 ngleDepth8_ClearImagePlanes(fb);
764
765 /* Paint attribute planes for default case.
766 * On Hyperdrive, this means all windows using overlay cmap 0. */
767 ngleResetAttrPlanes(fb, controlPlaneReg);
768
769 /* clear overlay planes */
770 ngleClearOverlayPlanes(fb, 0xff, 255);
771
772 /**************************************************
773 ** Also need to counteract ITE settings
774 **************************************************/
775 hyperUndoITE(fb);
776 break;
777
778 case DISABLE:
779 /* clear screen */
780 if (IS_24_DEVICE(fb))
781 ngleDepth24_ClearImagePlanes(fb);
782 else
783 ngleDepth8_ClearImagePlanes(fb);
784 ngleResetAttrPlanes(fb, controlPlaneReg);
785 ngleClearOverlayPlanes(fb, 0xff, 0);
786 break;
787
788 case -1: /* RESET */
789 hyperUndoITE(fb);
790 ngleResetAttrPlanes(fb, controlPlaneReg);
791 break;
792 }
793
794 NGLE_UNLOCK(fb);
795}
796
797/* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
798
799static void
800ngleGetDeviceRomData(struct stifb_info *fb)
801{
802#if 0
803XXX: FIXME: !!!
804 int *pBytePerLongDevDepData;/* data byte == LSB */
805 int *pRomTable;
806 NgleDevRomData *pPackedDevRomData;
807 int sizePackedDevRomData = sizeof(*pPackedDevRomData);
808 char *pCard8;
809 int i;
810 char *mapOrigin = NULL;
811
812 int romTableIdx;
813
814 pPackedDevRomData = fb->ngle_rom;
815
816 SETUP_HW(fb);
817 if (fb->id == S9000_ID_ARTIST) {
818 pPackedDevRomData->cursor_pipeline_delay = 4;
819 pPackedDevRomData->video_interleaves = 4;
820 } else {
821 /* Get pointer to unpacked byte/long data in ROM */
822 pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
823
824 /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
825 if (fb->id == S9000_ID_TOMCAT)
826 {
827 /* jump to the correct ROM table */
828 GET_ROMTABLE_INDEX(romTableIdx);
829 while (romTableIdx > 0)
830 {
831 pCard8 = (Card8 *) pPackedDevRomData;
832 pRomTable = pBytePerLongDevDepData;
833 /* Pack every fourth byte from ROM into structure */
834 for (i = 0; i < sizePackedDevRomData; i++)
835 {
836 *pCard8++ = (Card8) (*pRomTable++);
837 }
838
839 pBytePerLongDevDepData = (Card32 *)
840 ((Card8 *) pBytePerLongDevDepData +
841 pPackedDevRomData->sizeof_ngle_data);
842
843 romTableIdx--;
844 }
845 }
846
847 pCard8 = (Card8 *) pPackedDevRomData;
848
849 /* Pack every fourth byte from ROM into structure */
850 for (i = 0; i < sizePackedDevRomData; i++)
851 {
852 *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
853 }
854 }
855
856 SETUP_FB(fb);
857#endif
858}
859
860
861#define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
862#define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8
863#define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10
864#define HYPERBOWL_MODE2_8_24 15
865
866/* HCRX specific boot-time initialization */
867static void __init
868SETUP_HCRX(struct stifb_info *fb)
869{
870 int hyperbowl;
871 int nFreeFifoSlots = 0;
872
873 if (fb->id != S9000_ID_HCRX)
874 return;
875
876 /* Initialize Hyperbowl registers */
877 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
878
879 if (IS_24_DEVICE(fb)) {
880 hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
881 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
882 HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
883
884 /* First write to Hyperbowl must happen twice (bug) */
885 WRITE_WORD(hyperbowl, fb, REG_40);
886 WRITE_WORD(hyperbowl, fb, REG_40);
887
888 WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
889
890 WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
891 WRITE_WORD(0x404c4048, fb, REG_43);
892 WRITE_WORD(0x034c0348, fb, REG_44);
893 WRITE_WORD(0x444c4448, fb, REG_45);
894 } else {
895 hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
896
897 /* First write to Hyperbowl must happen twice (bug) */
898 WRITE_WORD(hyperbowl, fb, REG_40);
899 WRITE_WORD(hyperbowl, fb, REG_40);
900
901 WRITE_WORD(0x00000000, fb, REG_42);
902 WRITE_WORD(0x00000000, fb, REG_43);
903 WRITE_WORD(0x00000000, fb, REG_44);
904 WRITE_WORD(0x444c4048, fb, REG_45);
905 }
906}
907
908
909/* ------------------- driver specific functions --------------------------- */
910
911#define TMPBUFLEN 2048
912
913static ssize_t
914stifb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
915{
916 unsigned long p = *ppos;
917 struct inode *inode = file->f_dentry->d_inode;
918 int fbidx = iminor(inode);
919 struct fb_info *info = registered_fb[fbidx];
920 char tmpbuf[TMPBUFLEN];
921
922 if (!info || ! info->screen_base)
923 return -ENODEV;
924
925 if (p >= info->fix.smem_len)
926 return 0;
927 if (count >= info->fix.smem_len)
928 count = info->fix.smem_len;
929 if (count + p > info->fix.smem_len)
930 count = info->fix.smem_len - p;
931 if (count > sizeof(tmpbuf))
932 count = sizeof(tmpbuf);
933 if (count) {
934 char *base_addr;
935
936 base_addr = info->screen_base;
937 memcpy_fromio(&tmpbuf, base_addr+p, count);
938 count -= copy_to_user(buf, &tmpbuf, count);
939 if (!count)
940 return -EFAULT;
941 *ppos += count;
942 }
943 return count;
944}
945
946static ssize_t
947stifb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
948{
949 struct inode *inode = file->f_dentry->d_inode;
950 int fbidx = iminor(inode);
951 struct fb_info *info = registered_fb[fbidx];
952 unsigned long p = *ppos;
953 size_t c;
954 int err;
955 char tmpbuf[TMPBUFLEN];
956
957 if (!info || !info->screen_base)
958 return -ENODEV;
959
960 if (p > info->fix.smem_len)
961 return -ENOSPC;
962 if (count >= info->fix.smem_len)
963 count = info->fix.smem_len;
964 err = 0;
965 if (count + p > info->fix.smem_len) {
966 count = info->fix.smem_len - p;
967 err = -ENOSPC;
968 }
969
970 p += (unsigned long)info->screen_base;
971 c = count;
972 while (c) {
973 int len = c > sizeof(tmpbuf) ? sizeof(tmpbuf) : c;
974 err = -EFAULT;
975 if (copy_from_user(&tmpbuf, buf, len))
976 break;
977 memcpy_toio(p, &tmpbuf, len);
978 c -= len;
979 p += len;
980 buf += len;
981 *ppos += len;
982 }
983 if (count-c)
984 return (count-c);
985 return err;
986}
987
988static int
989stifb_setcolreg(u_int regno, u_int red, u_int green,
990 u_int blue, u_int transp, struct fb_info *info)
991{
992 struct stifb_info *fb = (struct stifb_info *) info;
993 u32 color;
994
Helge Dellerdaaeb6f2006-01-10 20:48:04 -0500995 if (regno >= NR_PALETTE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 return 1;
997
998 red >>= 8;
999 green >>= 8;
1000 blue >>= 8;
1001
1002 DEBUG_OFF();
1003
1004 START_IMAGE_COLORMAP_ACCESS(fb);
Helge Dellerdaaeb6f2006-01-10 20:48:04 -05001005
1006 if (unlikely(fb->info.var.grayscale)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 /* gray = 0.30*R + 0.59*G + 0.11*B */
1008 color = ((red * 77) +
1009 (green * 151) +
1010 (blue * 28)) >> 8;
1011 } else {
1012 color = ((red << 16) |
1013 (green << 8) |
1014 (blue));
1015 }
1016
Helge Dellerdaaeb6f2006-01-10 20:48:04 -05001017 if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
1018 struct fb_var_screeninfo *var = &fb->info.var;
1019 if (regno < 16)
1020 ((u32 *)fb->info.pseudo_palette)[regno] =
1021 regno << var->red.offset |
1022 regno << var->green.offset |
1023 regno << var->blue.offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 }
1025
1026 WRITE_IMAGE_COLOR(fb, regno, color);
Helge Dellerdaaeb6f2006-01-10 20:48:04 -05001027
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 if (fb->id == S9000_ID_HCRX) {
1029 NgleLutBltCtl lutBltCtl;
1030
1031 lutBltCtl = setHyperLutBltCtl(fb,
1032 0, /* Offset w/i LUT */
1033 256); /* Load entire LUT */
1034 NGLE_BINC_SET_SRCADDR(fb,
1035 NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
1036 /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
1037 START_COLORMAPLOAD(fb, lutBltCtl.all);
1038 SETUP_FB(fb);
1039 } else {
1040 /* cleanup colormap hardware */
1041 FINISH_IMAGE_COLORMAP_ACCESS(fb);
1042 }
1043
1044 DEBUG_ON();
1045
1046 return 0;
1047}
1048
1049static int
1050stifb_blank(int blank_mode, struct fb_info *info)
1051{
1052 struct stifb_info *fb = (struct stifb_info *) info;
1053 int enable = (blank_mode == 0) ? ENABLE : DISABLE;
1054
1055 switch (fb->id) {
1056 case S9000_ID_A1439A:
1057 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
1058 break;
1059 case CRT_ID_VISUALIZE_EG:
1060 case S9000_ID_ARTIST:
1061 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
1062 break;
1063 case S9000_ID_HCRX:
1064 HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
1065 break;
Helge Dellerdaaeb6f2006-01-10 20:48:04 -05001066 case S9000_ID_A1659A: /* fall through */
1067 case S9000_ID_TIMBER:
1068 case CRX24_OVERLAY_PLANES:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 default:
1070 ENABLE_DISABLE_DISPLAY(fb, enable);
1071 break;
1072 }
1073
1074 SETUP_FB(fb);
1075 return 0;
1076}
1077
1078static void __init
1079stifb_init_display(struct stifb_info *fb)
1080{
1081 int id = fb->id;
1082
1083 SETUP_FB(fb);
1084
1085 /* HCRX specific initialization */
1086 SETUP_HCRX(fb);
1087
1088 /*
1089 if (id == S9000_ID_HCRX)
1090 hyperInitSprite(fb);
1091 else
1092 ngleInitSprite(fb);
1093 */
1094
1095 /* Initialize the image planes. */
1096 switch (id) {
1097 case S9000_ID_HCRX:
1098 hyperResetPlanes(fb, ENABLE);
1099 break;
1100 case S9000_ID_A1439A:
1101 rattlerSetupPlanes(fb);
1102 break;
1103 case S9000_ID_A1659A:
1104 case S9000_ID_ARTIST:
1105 case CRT_ID_VISUALIZE_EG:
1106 elkSetupPlanes(fb);
1107 break;
1108 }
1109
1110 /* Clear attribute planes on non HCRX devices. */
1111 switch (id) {
1112 case S9000_ID_A1659A:
1113 case S9000_ID_A1439A:
1114 if (fb->info.var.bits_per_pixel == 32)
1115 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1116 else {
1117 ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1118 }
1119 if (id == S9000_ID_A1439A)
1120 ngleClearOverlayPlanes(fb, 0xff, 0);
1121 break;
1122 case S9000_ID_ARTIST:
1123 case CRT_ID_VISUALIZE_EG:
1124 if (fb->info.var.bits_per_pixel == 32)
1125 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1126 else {
1127 ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1128 }
1129 break;
1130 }
1131 stifb_blank(0, (struct fb_info *)fb); /* 0=enable screen */
1132
1133 SETUP_FB(fb);
1134}
1135
1136/* ------------ Interfaces to hardware functions ------------ */
1137
1138static struct fb_ops stifb_ops = {
1139 .owner = THIS_MODULE,
1140 .fb_read = stifb_read,
1141 .fb_write = stifb_write,
1142 .fb_setcolreg = stifb_setcolreg,
1143 .fb_blank = stifb_blank,
1144 .fb_fillrect = cfb_fillrect,
1145 .fb_copyarea = cfb_copyarea,
1146 .fb_imageblit = cfb_imageblit,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147};
1148
1149
1150/*
1151 * Initialization
1152 */
1153
1154int __init
1155stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1156{
1157 struct fb_fix_screeninfo *fix;
1158 struct fb_var_screeninfo *var;
1159 struct stifb_info *fb;
1160 struct fb_info *info;
1161 unsigned long sti_rom_address;
1162 char *dev_name;
1163 int bpp, xres, yres;
1164
1165 fb = kmalloc(sizeof(*fb), GFP_ATOMIC);
1166 if (!fb) {
1167 printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
1168 return -ENODEV;
1169 }
1170
1171 info = &fb->info;
1172
1173 /* set struct to a known state */
1174 memset(fb, 0, sizeof(*fb));
1175 fix = &info->fix;
1176 var = &info->var;
1177
1178 fb->sti = sti;
1179 /* store upper 32bits of the graphics id */
1180 fb->id = fb->sti->graphics_id[0];
1181
1182 /* only supported cards are allowed */
1183 switch (fb->id) {
1184 case CRT_ID_VISUALIZE_EG:
1185 /* look for a double buffering device like e.g. the
1186 "INTERNAL_EG_DX1024" in the RDI precisionbook laptop
1187 which won't work. The same device in non-double
1188 buffering mode returns "INTERNAL_EG_X1024". */
1189 if (strstr(sti->outptr.dev_name, "EG_DX")) {
1190 printk(KERN_WARNING
1191 "stifb: ignoring '%s'. Disable double buffering in IPL menu.\n",
1192 sti->outptr.dev_name);
1193 goto out_err0;
1194 }
1195 /* fall though */
1196 case S9000_ID_ARTIST:
1197 case S9000_ID_HCRX:
1198 case S9000_ID_TIMBER:
1199 case S9000_ID_A1659A:
1200 case S9000_ID_A1439A:
1201 break;
1202 default:
1203 printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1204 sti->outptr.dev_name, fb->id);
1205 goto out_err0;
1206 }
1207
1208 /* default to 8 bpp on most graphic chips */
1209 bpp = 8;
1210 xres = sti_onscreen_x(fb->sti);
1211 yres = sti_onscreen_y(fb->sti);
1212
1213 ngleGetDeviceRomData(fb);
1214
1215 /* get (virtual) io region base addr */
1216 fix->mmio_start = REGION_BASE(fb,2);
1217 fix->mmio_len = 0x400000;
1218
1219 /* Reject any device not in the NGLE family */
1220 switch (fb->id) {
1221 case S9000_ID_A1659A: /* CRX/A1659A */
1222 break;
1223 case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */
1224 var->grayscale = 1;
1225 fb->id = S9000_ID_A1659A;
1226 break;
1227 case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */
1228 dev_name = fb->sti->outptr.dev_name;
1229 if (strstr(dev_name, "GRAYSCALE") ||
1230 strstr(dev_name, "Grayscale") ||
1231 strstr(dev_name, "grayscale"))
1232 var->grayscale = 1;
1233 break;
1234 case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */
1235 /* FIXME: TomCat supports two heads:
1236 * fb.iobase = REGION_BASE(fb_info,3);
1237 * fb.screen_base = (void*) REGION_BASE(fb_info,2);
1238 * for now we only support the left one ! */
1239 xres = fb->ngle_rom.x_size_visible;
1240 yres = fb->ngle_rom.y_size_visible;
1241 fb->id = S9000_ID_A1659A;
1242 break;
1243 case S9000_ID_A1439A: /* CRX24/A1439A */
1244 bpp = 32;
1245 break;
1246 case S9000_ID_HCRX: /* Hyperdrive/HCRX */
1247 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1248 if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1249 (fb->sti->regions_phys[2] & 0xfc000000))
Helge Deller5d6d1642006-01-10 20:48:03 -05001250 sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 else
Helge Deller5d6d1642006-01-10 20:48:03 -05001252 sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1253
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1255 if (IS_24_DEVICE(fb)) {
1256 if (bpp_pref == 8 || bpp_pref == 32)
1257 bpp = bpp_pref;
1258 else
1259 bpp = 32;
1260 } else
1261 bpp = 8;
1262 READ_WORD(fb, REG_15);
1263 SETUP_HW(fb);
1264 break;
1265 case CRT_ID_VISUALIZE_EG:
1266 case S9000_ID_ARTIST: /* Artist */
1267 break;
1268 default:
1269#ifdef FALLBACK_TO_1BPP
1270 printk(KERN_WARNING
1271 "stifb: Unsupported graphics card (id=0x%08x) "
1272 "- now trying 1bpp mode instead\n",
1273 fb->id);
1274 bpp = 1; /* default to 1 bpp */
1275 break;
1276#else
1277 printk(KERN_WARNING
1278 "stifb: Unsupported graphics card (id=0x%08x) "
1279 "- skipping.\n",
1280 fb->id);
1281 goto out_err0;
1282#endif
1283 }
1284
1285
1286 /* get framebuffer physical and virtual base addr & len (64bit ready) */
1287 fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1288 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1289
1290 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1291 if (!fix->line_length)
1292 fix->line_length = 2048; /* default */
1293
1294 /* limit fbsize to max visible screen size */
1295 if (fix->smem_len > yres*fix->line_length)
1296 fix->smem_len = yres*fix->line_length;
1297
1298 fix->accel = FB_ACCEL_NONE;
1299
1300 switch (bpp) {
1301 case 1:
1302 fix->type = FB_TYPE_PLANES; /* well, sort of */
1303 fix->visual = FB_VISUAL_MONO10;
1304 var->red.length = var->green.length = var->blue.length = 1;
1305 break;
1306 case 8:
1307 fix->type = FB_TYPE_PACKED_PIXELS;
1308 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1309 var->red.length = var->green.length = var->blue.length = 8;
1310 break;
1311 case 32:
1312 fix->type = FB_TYPE_PACKED_PIXELS;
Helge Dellerdaaeb6f2006-01-10 20:48:04 -05001313 fix->visual = FB_VISUAL_DIRECTCOLOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1315 var->blue.offset = 0;
1316 var->green.offset = 8;
1317 var->red.offset = 16;
1318 var->transp.offset = 24;
1319 break;
1320 default:
1321 break;
1322 }
1323
1324 var->xres = var->xres_virtual = xres;
1325 var->yres = var->yres_virtual = yres;
1326 var->bits_per_pixel = bpp;
1327
1328 strcpy(fix->id, "stifb");
1329 info->fbops = &stifb_ops;
1330 info->screen_base = (void*) REGION_BASE(fb,1);
1331 info->flags = FBINFO_DEFAULT;
1332 info->pseudo_palette = &fb->pseudo_palette;
1333
1334 /* This has to been done !!! */
Helge Dellerdaaeb6f2006-01-10 20:48:04 -05001335 fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 stifb_init_display(fb);
1337
1338 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1339 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1340 fix->smem_start, fix->smem_start+fix->smem_len);
1341 goto out_err1;
1342 }
1343
1344 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1345 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1346 fix->mmio_start, fix->mmio_start+fix->mmio_len);
1347 goto out_err2;
1348 }
1349
1350 if (register_framebuffer(&fb->info) < 0)
1351 goto out_err3;
1352
1353 sti->info = info; /* save for unregister_framebuffer() */
1354
1355 printk(KERN_INFO
1356 "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1357 fb->info.node,
1358 fix->id,
1359 var->xres,
1360 var->yres,
1361 var->bits_per_pixel,
1362 sti->outptr.dev_name,
1363 fb->id,
1364 fix->mmio_start);
1365
1366 return 0;
1367
1368
1369out_err3:
1370 release_mem_region(fix->mmio_start, fix->mmio_len);
1371out_err2:
1372 release_mem_region(fix->smem_start, fix->smem_len);
1373out_err1:
1374 fb_dealloc_cmap(&info->cmap);
1375out_err0:
1376 kfree(fb);
1377 return -ENXIO;
1378}
1379
1380static int stifb_disabled __initdata;
1381
1382int __init
1383stifb_setup(char *options);
1384
1385int __init
1386stifb_init(void)
1387{
1388 struct sti_struct *sti;
1389 struct sti_struct *def_sti;
1390 int i;
1391
1392#ifndef MODULE
1393 char *option = NULL;
1394
1395 if (fb_get_options("stifb", &option))
1396 return -ENODEV;
1397 stifb_setup(option);
1398#endif
1399 if (stifb_disabled) {
1400 printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1401 return -ENXIO;
1402 }
1403
1404 def_sti = sti_get_rom(0);
1405 if (def_sti) {
1406 for (i = 1; i <= MAX_STI_ROMS; i++) {
1407 sti = sti_get_rom(i);
1408 if (!sti)
1409 break;
1410 if (sti == def_sti) {
1411 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1412 break;
1413 }
1414 }
1415 }
1416
1417 for (i = 1; i <= MAX_STI_ROMS; i++) {
1418 sti = sti_get_rom(i);
1419 if (!sti)
1420 break;
1421 if (sti == def_sti)
1422 continue;
1423 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1424 }
1425 return 0;
1426}
1427
1428/*
1429 * Cleanup
1430 */
1431
1432static void __exit
1433stifb_cleanup(void)
1434{
1435 struct sti_struct *sti;
1436 int i;
1437
1438 for (i = 1; i <= MAX_STI_ROMS; i++) {
1439 sti = sti_get_rom(i);
1440 if (!sti)
1441 break;
1442 if (sti->info) {
1443 struct fb_info *info = sti->info;
1444 unregister_framebuffer(sti->info);
1445 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1446 release_mem_region(info->fix.smem_start, info->fix.smem_len);
1447 fb_dealloc_cmap(&info->cmap);
1448 kfree(info);
1449 }
1450 sti->info = NULL;
1451 }
1452}
1453
1454int __init
1455stifb_setup(char *options)
1456{
1457 int i;
1458
1459 if (!options || !*options)
1460 return 0;
1461
1462 if (strncmp(options, "off", 3) == 0) {
1463 stifb_disabled = 1;
1464 options += 3;
1465 }
1466
1467 if (strncmp(options, "bpp", 3) == 0) {
1468 options += 3;
1469 for (i = 0; i < MAX_STI_ROMS; i++) {
1470 if (*options++ != ':')
1471 break;
1472 stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1473 }
1474 }
1475 return 0;
1476}
1477
1478__setup("stifb=", stifb_setup);
1479
1480module_init(stifb_init);
1481module_exit(stifb_cleanup);
1482
1483MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1484MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1485MODULE_LICENSE("GPL v2");