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