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