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