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