]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/video/stifb.c
Clean up duplicate includes in drivers/w1/
[mirror_ubuntu-artful-kernel.git] / drivers / video / stifb.c
CommitLineData
1da177e4
LT
1/*
2 * linux/drivers/video/stifb.c -
3 * Low level Frame buffer driver for HP workstations with
4 * STI (standard text interface) video firmware.
5 *
857600c7 6 * Copyright (C) 2001-2006 Helge Deller <deller@gmx.de>
1da177e4
LT
7 * Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
8 *
9 * Based on:
10 * - linux/drivers/video/artistfb.c -- Artist frame buffer driver
11 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
12 * - based on skeletonfb, which was
13 * Created 28 Dec 1997 by Geert Uytterhoeven
14 * - HP Xhp cfb-based X11 window driver for XFree86
15 * (c)Copyright 1992 Hewlett-Packard Co.
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
1da177e4
LT
57#include <linux/module.h>
58#include <linux/kernel.h>
59#include <linux/errno.h>
60#include <linux/string.h>
61#include <linux/mm.h>
62#include <linux/slab.h>
63#include <linux/delay.h>
64#include <linux/fb.h>
65#include <linux/init.h>
66#include <linux/ioport.h>
1da177e4
LT
67
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> */
5d6d1640
HD
74#define REGION_BASE(fb_info, index) \
75 F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index])
1da177e4
LT
76
77#define NGLEDEVDEPROM_CRT_REGION 1
78
daaeb6f8
HD
79#define NR_PALETTE 256
80
1da177e4
LT
81typedef 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;
daaeb6f8 110 u32 pseudo_palette[16];
1da177e4
LT
111};
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
daaeb6f8
HD
350#define GET_FIFO_SLOTS(fb, cnt, numslots) \
351{ while (cnt < numslots) \
1da177e4 352 cnt = READ_WORD(fb, REG_34); \
daaeb6f8 353 cnt -= numslots; \
1da177e4
LT
354}
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
857600c7 515 fb_memset((void*)fb->info.fix.smem_start, 0xff,
1da177e4
LT
516 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
1da177e4
LT
909static 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
daaeb6f8 916 if (regno >= NR_PALETTE)
1da177e4
LT
917 return 1;
918
919 red >>= 8;
920 green >>= 8;
921 blue >>= 8;
922
923 DEBUG_OFF();
924
925 START_IMAGE_COLORMAP_ACCESS(fb);
daaeb6f8
HD
926
927 if (unlikely(fb->info.var.grayscale)) {
1da177e4
LT
928 /* 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
daaeb6f8
HD
938 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;
1da177e4
LT
945 }
946
947 WRITE_IMAGE_COLOR(fb, regno, color);
daaeb6f8 948
1da177e4
LT
949 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;
daaeb6f8
HD
987 case S9000_ID_A1659A: /* fall through */
988 case S9000_ID_TIMBER:
989 case CRX24_OVERLAY_PLANES:
1da177e4
LT
990 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,
1da177e4
LT
1061 .fb_setcolreg = stifb_setcolreg,
1062 .fb_blank = stifb_blank,
1063 .fb_fillrect = cfb_fillrect,
1064 .fb_copyarea = cfb_copyarea,
1065 .fb_imageblit = cfb_imageblit,
1da177e4
LT
1066};
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
857600c7 1084 fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
1da177e4
LT
1085 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 */
1da177e4
LT
1093 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:
04a3f959
HD
1103 /* Visualize cards can run either in "double buffer" or
1104 "standard" mode. Depending on the mode, the card reports
1105 a different device name, e.g. "INTERNAL_EG_DX1024" in double
1106 buffer mode and "INTERNAL_EG_X1024" in standard mode.
1107 Since this driver only supports standard mode, we check
1108 if the device name contains the string "DX" and tell the
1109 user how to reconfigure the card. */
1110 if (strstr(sti->outptr.dev_name, "DX")) {
1111 printk(KERN_WARNING "WARNING: stifb framebuffer driver does not "
1112 "support '%s' in double-buffer mode.\n"
1113 KERN_WARNING "WARNING: Please disable the double-buffer mode "
1114 "in IPL menu (the PARISC-BIOS).\n",
1da177e4
LT
1115 sti->outptr.dev_name);
1116 goto out_err0;
1117 }
1118 /* fall though */
1119 case S9000_ID_ARTIST:
1120 case S9000_ID_HCRX:
1121 case S9000_ID_TIMBER:
1122 case S9000_ID_A1659A:
1123 case S9000_ID_A1439A:
1124 break;
1125 default:
1126 printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1127 sti->outptr.dev_name, fb->id);
1128 goto out_err0;
1129 }
1130
1131 /* default to 8 bpp on most graphic chips */
1132 bpp = 8;
1133 xres = sti_onscreen_x(fb->sti);
1134 yres = sti_onscreen_y(fb->sti);
1135
1136 ngleGetDeviceRomData(fb);
1137
1138 /* get (virtual) io region base addr */
1139 fix->mmio_start = REGION_BASE(fb,2);
1140 fix->mmio_len = 0x400000;
1141
1142 /* Reject any device not in the NGLE family */
1143 switch (fb->id) {
1144 case S9000_ID_A1659A: /* CRX/A1659A */
1145 break;
1146 case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */
1147 var->grayscale = 1;
1148 fb->id = S9000_ID_A1659A;
1149 break;
1150 case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */
1151 dev_name = fb->sti->outptr.dev_name;
1152 if (strstr(dev_name, "GRAYSCALE") ||
1153 strstr(dev_name, "Grayscale") ||
1154 strstr(dev_name, "grayscale"))
1155 var->grayscale = 1;
1156 break;
1157 case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */
1158 /* FIXME: TomCat supports two heads:
1159 * fb.iobase = REGION_BASE(fb_info,3);
857600c7 1160 * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx);
1da177e4
LT
1161 * for now we only support the left one ! */
1162 xres = fb->ngle_rom.x_size_visible;
1163 yres = fb->ngle_rom.y_size_visible;
1164 fb->id = S9000_ID_A1659A;
1165 break;
1166 case S9000_ID_A1439A: /* CRX24/A1439A */
1167 bpp = 32;
1168 break;
1169 case S9000_ID_HCRX: /* Hyperdrive/HCRX */
1170 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1171 if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1172 (fb->sti->regions_phys[2] & 0xfc000000))
5d6d1640 1173 sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1da177e4 1174 else
5d6d1640
HD
1175 sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1176
1da177e4
LT
1177 fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1178 if (IS_24_DEVICE(fb)) {
1179 if (bpp_pref == 8 || bpp_pref == 32)
1180 bpp = bpp_pref;
1181 else
1182 bpp = 32;
1183 } else
1184 bpp = 8;
1185 READ_WORD(fb, REG_15);
1186 SETUP_HW(fb);
1187 break;
1188 case CRT_ID_VISUALIZE_EG:
1189 case S9000_ID_ARTIST: /* Artist */
1190 break;
1191 default:
1192#ifdef FALLBACK_TO_1BPP
1193 printk(KERN_WARNING
1194 "stifb: Unsupported graphics card (id=0x%08x) "
1195 "- now trying 1bpp mode instead\n",
1196 fb->id);
1197 bpp = 1; /* default to 1 bpp */
1198 break;
1199#else
1200 printk(KERN_WARNING
1201 "stifb: Unsupported graphics card (id=0x%08x) "
1202 "- skipping.\n",
1203 fb->id);
1204 goto out_err0;
1205#endif
1206 }
1207
1208
1209 /* get framebuffer physical and virtual base addr & len (64bit ready) */
1210 fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1211 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1212
1213 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1214 if (!fix->line_length)
1215 fix->line_length = 2048; /* default */
1216
1217 /* limit fbsize to max visible screen size */
1218 if (fix->smem_len > yres*fix->line_length)
1219 fix->smem_len = yres*fix->line_length;
1220
1221 fix->accel = FB_ACCEL_NONE;
1222
1223 switch (bpp) {
1224 case 1:
1225 fix->type = FB_TYPE_PLANES; /* well, sort of */
1226 fix->visual = FB_VISUAL_MONO10;
1227 var->red.length = var->green.length = var->blue.length = 1;
1228 break;
1229 case 8:
1230 fix->type = FB_TYPE_PACKED_PIXELS;
1231 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1232 var->red.length = var->green.length = var->blue.length = 8;
1233 break;
1234 case 32:
1235 fix->type = FB_TYPE_PACKED_PIXELS;
daaeb6f8 1236 fix->visual = FB_VISUAL_DIRECTCOLOR;
1da177e4
LT
1237 var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1238 var->blue.offset = 0;
1239 var->green.offset = 8;
1240 var->red.offset = 16;
1241 var->transp.offset = 24;
1242 break;
1243 default:
1244 break;
1245 }
1246
1247 var->xres = var->xres_virtual = xres;
1248 var->yres = var->yres_virtual = yres;
1249 var->bits_per_pixel = bpp;
1250
1251 strcpy(fix->id, "stifb");
1252 info->fbops = &stifb_ops;
857600c7
HD
1253 info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
1254 info->screen_size = fix->smem_len;
1da177e4
LT
1255 info->flags = FBINFO_DEFAULT;
1256 info->pseudo_palette = &fb->pseudo_palette;
1257
1258 /* This has to been done !!! */
daaeb6f8 1259 fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
1da177e4
LT
1260 stifb_init_display(fb);
1261
1262 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1263 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1264 fix->smem_start, fix->smem_start+fix->smem_len);
1265 goto out_err1;
1266 }
1267
1268 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1269 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1270 fix->mmio_start, fix->mmio_start+fix->mmio_len);
1271 goto out_err2;
1272 }
1273
1274 if (register_framebuffer(&fb->info) < 0)
1275 goto out_err3;
1276
1277 sti->info = info; /* save for unregister_framebuffer() */
1278
1279 printk(KERN_INFO
1280 "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1281 fb->info.node,
1282 fix->id,
1283 var->xres,
1284 var->yres,
1285 var->bits_per_pixel,
1286 sti->outptr.dev_name,
1287 fb->id,
1288 fix->mmio_start);
1289
1290 return 0;
1291
1292
1293out_err3:
1294 release_mem_region(fix->mmio_start, fix->mmio_len);
1295out_err2:
1296 release_mem_region(fix->smem_start, fix->smem_len);
1297out_err1:
9cf2014a 1298 iounmap(info->screen_base);
1da177e4
LT
1299 fb_dealloc_cmap(&info->cmap);
1300out_err0:
1301 kfree(fb);
1302 return -ENXIO;
1303}
1304
1305static int stifb_disabled __initdata;
1306
1307int __init
1308stifb_setup(char *options);
1309
1310int __init
1311stifb_init(void)
1312{
1313 struct sti_struct *sti;
1314 struct sti_struct *def_sti;
1315 int i;
1316
1317#ifndef MODULE
1318 char *option = NULL;
1319
1320 if (fb_get_options("stifb", &option))
1321 return -ENODEV;
1322 stifb_setup(option);
1323#endif
1324 if (stifb_disabled) {
1325 printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1326 return -ENXIO;
1327 }
1328
1329 def_sti = sti_get_rom(0);
1330 if (def_sti) {
1331 for (i = 1; i <= MAX_STI_ROMS; i++) {
1332 sti = sti_get_rom(i);
1333 if (!sti)
1334 break;
1335 if (sti == def_sti) {
1336 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1337 break;
1338 }
1339 }
1340 }
1341
1342 for (i = 1; i <= MAX_STI_ROMS; i++) {
1343 sti = sti_get_rom(i);
1344 if (!sti)
1345 break;
1346 if (sti == def_sti)
1347 continue;
1348 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1349 }
1350 return 0;
1351}
1352
1353/*
1354 * Cleanup
1355 */
1356
1357static void __exit
1358stifb_cleanup(void)
1359{
1360 struct sti_struct *sti;
1361 int i;
1362
1363 for (i = 1; i <= MAX_STI_ROMS; i++) {
1364 sti = sti_get_rom(i);
1365 if (!sti)
1366 break;
1367 if (sti->info) {
1368 struct fb_info *info = sti->info;
1369 unregister_framebuffer(sti->info);
1370 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1371 release_mem_region(info->fix.smem_start, info->fix.smem_len);
9cf2014a
AL
1372 if (info->screen_base)
1373 iounmap(info->screen_base);
1da177e4
LT
1374 fb_dealloc_cmap(&info->cmap);
1375 kfree(info);
1376 }
1377 sti->info = NULL;
1378 }
1379}
1380
1381int __init
1382stifb_setup(char *options)
1383{
1384 int i;
1385
1386 if (!options || !*options)
9b41046c 1387 return 1;
1da177e4
LT
1388
1389 if (strncmp(options, "off", 3) == 0) {
1390 stifb_disabled = 1;
1391 options += 3;
1392 }
1393
1394 if (strncmp(options, "bpp", 3) == 0) {
1395 options += 3;
1396 for (i = 0; i < MAX_STI_ROMS; i++) {
1397 if (*options++ != ':')
1398 break;
1399 stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1400 }
1401 }
9b41046c 1402 return 1;
1da177e4
LT
1403}
1404
1405__setup("stifb=", stifb_setup);
1406
1407module_init(stifb_init);
1408module_exit(stifb_cleanup);
1409
1410MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1411MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1412MODULE_LICENSE("GPL v2");