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