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> | |
1da177e4 LT |
67 | |
68 | #include <asm/grfioctl.h> /* for HP-UX compatibility */ | |
69 | #include <asm/uaccess.h> | |
70 | ||
71 | #include "sticore.h" | |
72 | ||
73 | /* REGION_BASE(fb_info, index) returns the virtual address for region <index> */ | |
5d6d1640 HD |
74 | #define REGION_BASE(fb_info, index) \ |
75 | F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index]) | |
1da177e4 LT |
76 | |
77 | #define NGLEDEVDEPROM_CRT_REGION 1 | |
78 | ||
daaeb6f8 HD |
79 | #define NR_PALETTE 256 |
80 | ||
1da177e4 LT |
81 | typedef 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 | ||
94 | typedef 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 | ||
104 | struct stifb_info { | |
105 | struct fb_info info; | |
106 | unsigned int id; | |
107 | ngle_rom_t ngle_rom; | |
108 | struct sti_struct *sti; | |
109 | int deviceSpecificConfig; | |
daaeb6f8 | 110 | u32 pseudo_palette[16]; |
1da177e4 LT |
111 | }; |
112 | ||
113 | static int __initdata stifb_bpp_pref[MAX_STI_ROMS]; | |
114 | ||
115 | /* ------------------- chipset specific functions -------------------------- */ | |
116 | ||
117 | /* offsets to graphic-chip internal registers */ | |
118 | ||
119 | #define REG_1 0x000118 | |
120 | #define REG_2 0x000480 | |
121 | #define REG_3 0x0004a0 | |
122 | #define REG_4 0x000600 | |
123 | #define REG_6 0x000800 | |
124 | #define REG_8 0x000820 | |
125 | #define REG_9 0x000a04 | |
126 | #define REG_10 0x018000 | |
127 | #define REG_11 0x018004 | |
128 | #define REG_12 0x01800c | |
129 | #define REG_13 0x018018 | |
130 | #define REG_14 0x01801c | |
131 | #define REG_15 0x200000 | |
132 | #define REG_15b0 0x200000 | |
133 | #define REG_16b1 0x200005 | |
134 | #define REG_16b3 0x200007 | |
135 | #define REG_21 0x200218 | |
136 | #define REG_22 0x0005a0 | |
137 | #define REG_23 0x0005c0 | |
138 | #define REG_26 0x200118 | |
139 | #define REG_27 0x200308 | |
140 | #define REG_32 0x21003c | |
141 | #define REG_33 0x210040 | |
142 | #define REG_34 0x200008 | |
143 | #define REG_35 0x018010 | |
144 | #define REG_38 0x210020 | |
145 | #define REG_39 0x210120 | |
146 | #define REG_40 0x210130 | |
147 | #define REG_42 0x210028 | |
148 | #define REG_43 0x21002c | |
149 | #define REG_44 0x210030 | |
150 | #define REG_45 0x210034 | |
151 | ||
152 | #define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg)) | |
153 | #define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg)) | |
154 | ||
155 | ||
156 | #ifndef DEBUG_STIFB_REGS | |
157 | # define DEBUG_OFF() | |
158 | # define DEBUG_ON() | |
159 | # define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)) | |
160 | # define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg)) | |
161 | #else | |
162 | static int debug_on = 1; | |
163 | # define DEBUG_OFF() debug_on=0 | |
164 | # define DEBUG_ON() debug_on=1 | |
165 | # define WRITE_BYTE(value,fb,reg) do { if (debug_on) \ | |
166 | printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \ | |
167 | __FUNCTION__, reg, value, READ_BYTE(fb,reg)); \ | |
168 | gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0) | |
169 | # define WRITE_WORD(value,fb,reg) do { if (debug_on) \ | |
170 | printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \ | |
171 | __FUNCTION__, reg, value, READ_WORD(fb,reg)); \ | |
172 | gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0) | |
173 | #endif /* DEBUG_STIFB_REGS */ | |
174 | ||
175 | ||
176 | #define ENABLE 1 /* for enabling/disabling screen */ | |
177 | #define DISABLE 0 | |
178 | ||
179 | #define NGLE_LOCK(fb_info) do { } while (0) | |
180 | #define NGLE_UNLOCK(fb_info) do { } while (0) | |
181 | ||
182 | static void | |
183 | SETUP_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 | ||
195 | static void | |
196 | SETUP_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 | ||
232 | static void | |
233 | START_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 | ||
241 | static void | |
242 | WRITE_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 | ||
249 | static void | |
250 | FINISH_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 | ||
264 | static void | |
265 | SETUP_RAMDAC(struct stifb_info *fb) | |
266 | { | |
267 | SETUP_HW(fb); | |
268 | WRITE_WORD(0x04000000, fb, 0x1020); | |
269 | WRITE_WORD(0xff000000, fb, 0x1028); | |
270 | } | |
271 | ||
272 | static void | |
273 | CRX24_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 | |
285 | static void | |
286 | HCRX_SETUP_RAMDAC(struct stifb_info *fb) | |
287 | { | |
288 | WRITE_WORD(0xffffffff, fb, REG_32); | |
289 | } | |
290 | #endif | |
291 | ||
292 | static void | |
293 | CRX24_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 | ||
304 | static void | |
305 | ENABLE_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 | ||
313 | static void | |
314 | CRX24_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 | ||
323 | static void | |
324 | ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) | |
325 | { | |
326 | u32 DregsMiscVideo = REG_21; | |
327 | u32 DregsMiscCtl = REG_27; | |
328 | ||
329 | SETUP_HW(fb); | |
330 | if (enable) { | |
331 | WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo); | |
332 | WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl); | |
333 | } else { | |
334 | WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo); | |
335 | WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl); | |
336 | } | |
337 | } | |
338 | ||
339 | #define GET_ROMTABLE_INDEX(fb) \ | |
340 | (READ_BYTE(fb, REG_16b3) - 1) | |
341 | ||
342 | #define HYPER_CONFIG_PLANES_24 0x00000100 | |
343 | ||
344 | #define IS_24_DEVICE(fb) \ | |
345 | (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24) | |
346 | ||
347 | #define IS_888_DEVICE(fb) \ | |
348 | (!(IS_24_DEVICE(fb))) | |
349 | ||
daaeb6f8 HD |
350 | #define GET_FIFO_SLOTS(fb, cnt, numslots) \ |
351 | { while (cnt < numslots) \ | |
1da177e4 | 352 | cnt = READ_WORD(fb, REG_34); \ |
daaeb6f8 | 353 | cnt -= numslots; \ |
1da177e4 LT |
354 | } |
355 | ||
356 | #define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */ | |
357 | #define Otc04 2 /* Pixels in each longword transfer (4) */ | |
358 | #define Otc32 5 /* Pixels in each longword transfer (32) */ | |
359 | #define Ots08 3 /* Each pixel is size (8)d transfer (1) */ | |
360 | #define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */ | |
361 | #define AddrLong 5 /* FB address is Long aligned (pixel) */ | |
362 | #define BINovly 0x2 /* 8 bit overlay */ | |
363 | #define BINapp0I 0x0 /* Application Buffer 0, Indexed */ | |
364 | #define BINapp1I 0x1 /* Application Buffer 1, Indexed */ | |
365 | #define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */ | |
366 | #define BINattr 0xd /* Attribute Bitmap */ | |
367 | #define RopSrc 0x3 | |
368 | #define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */ | |
369 | #define BitmapExtent32 5 /* Each write hits (32) bits in depth */ | |
370 | #define DataDynamic 0 /* Data register reloaded by direct access */ | |
371 | #define MaskDynamic 1 /* Mask register reloaded by direct access */ | |
372 | #define MaskOtc 0 /* Mask contains Object Count valid bits */ | |
373 | ||
374 | #define MaskAddrOffset(offset) (offset) | |
375 | #define StaticReg(en) (en) | |
376 | #define BGx(en) (en) | |
377 | #define FGx(en) (en) | |
378 | ||
379 | #define BAJustPoint(offset) (offset) | |
380 | #define BAIndexBase(base) (base) | |
381 | #define BA(F,C,S,A,J,B,I) \ | |
382 | (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I)) | |
383 | ||
384 | #define IBOvals(R,M,X,S,D,L,B,F) \ | |
385 | (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F)) | |
386 | ||
387 | #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \ | |
388 | WRITE_WORD(val, fb, REG_14) | |
389 | ||
390 | #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \ | |
391 | WRITE_WORD(val, fb, REG_11) | |
392 | ||
393 | #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \ | |
394 | WRITE_WORD(val, fb, REG_12) | |
395 | ||
396 | #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \ | |
397 | WRITE_WORD(plnmsk32, fb, REG_13) | |
398 | ||
399 | #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \ | |
400 | WRITE_WORD(fg32, fb, REG_35) | |
401 | ||
402 | #define NGLE_SET_TRANSFERDATA(fb, val) \ | |
403 | WRITE_WORD(val, fb, REG_8) | |
404 | ||
405 | #define NGLE_SET_DSTXY(fb, val) \ | |
406 | WRITE_WORD(val, fb, REG_6) | |
407 | ||
408 | #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \ | |
409 | (u32) (fbaddrbase) + \ | |
410 | ( (unsigned int) ( (y) << 13 ) | \ | |
411 | (unsigned int) ( (x) << 2 ) ) \ | |
412 | ) | |
413 | ||
414 | #define NGLE_BINC_SET_DSTADDR(fb, addr) \ | |
415 | WRITE_WORD(addr, fb, REG_3) | |
416 | ||
417 | #define NGLE_BINC_SET_SRCADDR(fb, addr) \ | |
418 | WRITE_WORD(addr, fb, REG_2) | |
419 | ||
420 | #define NGLE_BINC_SET_DSTMASK(fb, mask) \ | |
421 | WRITE_WORD(mask, fb, REG_22) | |
422 | ||
423 | #define NGLE_BINC_WRITE32(fb, data32) \ | |
424 | WRITE_WORD(data32, fb, REG_23) | |
425 | ||
426 | #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \ | |
427 | WRITE_WORD((cmapBltCtlData32), fb, REG_38) | |
428 | ||
429 | #define SET_LENXY_START_RECFILL(fb, lenxy) \ | |
430 | WRITE_WORD(lenxy, fb, REG_9) | |
431 | ||
432 | static void | |
433 | HYPER_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 | ||
455 | static void | |
456 | SETUP_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 | ||
465 | static void | |
466 | SET_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 | ||
481 | static void | |
482 | FINISH_ATTR_ACCESS(struct stifb_info *fb) | |
483 | { | |
484 | SETUP_HW(fb); | |
485 | WRITE_WORD(0x00000000, fb, REG_12); | |
486 | } | |
487 | ||
488 | static void | |
489 | elkSetupPlanes(struct stifb_info *fb) | |
490 | { | |
491 | SETUP_RAMDAC(fb); | |
492 | SETUP_FB(fb); | |
493 | } | |
494 | ||
495 | static void | |
496 | ngleSetupAttrPlanes(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 | ||
505 | static void | |
506 | rattlerSetupPlanes(struct stifb_info *fb) | |
507 | { | |
62347218 HD |
508 | 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 | */ | |
1da177e4 LT |
514 | CRX24_SETUP_RAMDAC(fb); |
515 | ||
62347218 HD |
516 | /* 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; | |
521 | ||
522 | 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); | |
1da177e4 | 525 | |
1da177e4 LT |
526 | 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 */ | |
536 | typedef 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 | |
552 | static NgleLutBltCtl | |
553 | setNgleLutBltCtl(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 | ||
591 | static NgleLutBltCtl | |
592 | setHyperLutBltCtl(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 | ||
615 | static 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 | ||
649 | static void | |
650 | ngleDepth8_ClearImagePlanes(struct stifb_info *fb) | |
651 | { | |
652 | /* FIXME! */ | |
653 | } | |
654 | ||
655 | static void | |
656 | ngleDepth24_ClearImagePlanes(struct stifb_info *fb) | |
657 | { | |
658 | /* FIXME! */ | |
659 | } | |
660 | ||
661 | static void | |
662 | ngleResetAttrPlanes(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 | ||
713 | static void | |
714 | ngleClearOverlayPlanes(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 | ||
748 | static void | |
749 | hyperResetPlanes(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 | |
759 | controlPlaneReg = 0x00000F00; /* 0x00000800 should be enought, but lets clear all 4 bits */ | |
760 | else | |
761 | controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */ | |
762 | ||
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 | ||
805 | static void | |
806 | ngleGetDeviceRomData(struct stifb_info *fb) | |
807 | { | |
808 | #if 0 | |
809 | XXX: 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 */ | |
873 | static void __init | |
874 | SETUP_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 | ||
1da177e4 LT |
917 | static int |
918 | stifb_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 | ||
daaeb6f8 | 924 | if (regno >= NR_PALETTE) |
1da177e4 LT |
925 | return 1; |
926 | ||
927 | red >>= 8; | |
928 | green >>= 8; | |
929 | blue >>= 8; | |
930 | ||
931 | DEBUG_OFF(); | |
932 | ||
933 | START_IMAGE_COLORMAP_ACCESS(fb); | |
daaeb6f8 HD |
934 | |
935 | if (unlikely(fb->info.var.grayscale)) { | |
1da177e4 LT |
936 | /* 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 | ||
daaeb6f8 HD |
946 | 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; | |
1da177e4 LT |
953 | } |
954 | ||
955 | WRITE_IMAGE_COLOR(fb, regno, color); | |
daaeb6f8 | 956 | |
1da177e4 LT |
957 | 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 | ||
978 | static int | |
979 | stifb_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; | |
daaeb6f8 HD |
995 | case S9000_ID_A1659A: /* fall through */ |
996 | case S9000_ID_TIMBER: | |
997 | case CRX24_OVERLAY_PLANES: | |
1da177e4 LT |
998 | default: |
999 | ENABLE_DISABLE_DISPLAY(fb, enable); | |
1000 | break; | |
1001 | } | |
1002 | ||
1003 | SETUP_FB(fb); | |
1004 | return 0; | |
1005 | } | |
1006 | ||
1007 | static void __init | |
1008 | stifb_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 | ||
1067 | static struct fb_ops stifb_ops = { | |
1068 | .owner = THIS_MODULE, | |
1da177e4 LT |
1069 | .fb_setcolreg = stifb_setcolreg, |
1070 | .fb_blank = stifb_blank, | |
1071 | .fb_fillrect = cfb_fillrect, | |
1072 | .fb_copyarea = cfb_copyarea, | |
1073 | .fb_imageblit = cfb_imageblit, | |
1da177e4 LT |
1074 | }; |
1075 | ||
1076 | ||
1077 | /* | |
1078 | * Initialization | |
1079 | */ | |
1080 | ||
1081 | int __init | |
1082 | stifb_init_fb(struct sti_struct *sti, int bpp_pref) | |
1083 | { | |
1084 | struct fb_fix_screeninfo *fix; | |
1085 | struct fb_var_screeninfo *var; | |
1086 | struct stifb_info *fb; | |
1087 | struct fb_info *info; | |
1088 | unsigned long sti_rom_address; | |
1089 | char *dev_name; | |
1090 | int bpp, xres, yres; | |
1091 | ||
857600c7 | 1092 | fb = kzalloc(sizeof(*fb), GFP_ATOMIC); |
1da177e4 LT |
1093 | if (!fb) { |
1094 | printk(KERN_ERR "stifb: Could not allocate stifb structure\n"); | |
1095 | return -ENODEV; | |
1096 | } | |
1097 | ||
1098 | info = &fb->info; | |
1099 | ||
1100 | /* set struct to a known state */ | |
1da177e4 LT |
1101 | fix = &info->fix; |
1102 | var = &info->var; | |
1103 | ||
1104 | fb->sti = sti; | |
1105 | /* store upper 32bits of the graphics id */ | |
1106 | fb->id = fb->sti->graphics_id[0]; | |
1107 | ||
1108 | /* only supported cards are allowed */ | |
1109 | switch (fb->id) { | |
1110 | case CRT_ID_VISUALIZE_EG: | |
04a3f959 HD |
1111 | /* Visualize cards can run either in "double buffer" or |
1112 | "standard" mode. Depending on the mode, the card reports | |
1113 | a different device name, e.g. "INTERNAL_EG_DX1024" in double | |
1114 | buffer mode and "INTERNAL_EG_X1024" in standard mode. | |
1115 | Since this driver only supports standard mode, we check | |
1116 | if the device name contains the string "DX" and tell the | |
1117 | user how to reconfigure the card. */ | |
1118 | if (strstr(sti->outptr.dev_name, "DX")) { | |
1119 | printk(KERN_WARNING "WARNING: stifb framebuffer driver does not " | |
1120 | "support '%s' in double-buffer mode.\n" | |
1121 | KERN_WARNING "WARNING: Please disable the double-buffer mode " | |
1122 | "in IPL menu (the PARISC-BIOS).\n", | |
1da177e4 LT |
1123 | sti->outptr.dev_name); |
1124 | goto out_err0; | |
1125 | } | |
1126 | /* fall though */ | |
1127 | case S9000_ID_ARTIST: | |
1128 | case S9000_ID_HCRX: | |
1129 | case S9000_ID_TIMBER: | |
1130 | case S9000_ID_A1659A: | |
1131 | case S9000_ID_A1439A: | |
1132 | break; | |
1133 | default: | |
1134 | printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n", | |
1135 | sti->outptr.dev_name, fb->id); | |
1136 | goto out_err0; | |
1137 | } | |
1138 | ||
1139 | /* default to 8 bpp on most graphic chips */ | |
1140 | bpp = 8; | |
1141 | xres = sti_onscreen_x(fb->sti); | |
1142 | yres = sti_onscreen_y(fb->sti); | |
1143 | ||
1144 | ngleGetDeviceRomData(fb); | |
1145 | ||
1146 | /* get (virtual) io region base addr */ | |
1147 | fix->mmio_start = REGION_BASE(fb,2); | |
1148 | fix->mmio_len = 0x400000; | |
1149 | ||
1150 | /* Reject any device not in the NGLE family */ | |
1151 | switch (fb->id) { | |
1152 | case S9000_ID_A1659A: /* CRX/A1659A */ | |
1153 | break; | |
1154 | case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */ | |
1155 | var->grayscale = 1; | |
1156 | fb->id = S9000_ID_A1659A; | |
1157 | break; | |
1158 | case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */ | |
1159 | dev_name = fb->sti->outptr.dev_name; | |
1160 | if (strstr(dev_name, "GRAYSCALE") || | |
1161 | strstr(dev_name, "Grayscale") || | |
1162 | strstr(dev_name, "grayscale")) | |
1163 | var->grayscale = 1; | |
1164 | break; | |
1165 | case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */ | |
1166 | /* FIXME: TomCat supports two heads: | |
1167 | * fb.iobase = REGION_BASE(fb_info,3); | |
857600c7 | 1168 | * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx); |
1da177e4 LT |
1169 | * for now we only support the left one ! */ |
1170 | xres = fb->ngle_rom.x_size_visible; | |
1171 | yres = fb->ngle_rom.y_size_visible; | |
1172 | fb->id = S9000_ID_A1659A; | |
1173 | break; | |
1174 | case S9000_ID_A1439A: /* CRX24/A1439A */ | |
1175 | bpp = 32; | |
1176 | break; | |
1177 | case S9000_ID_HCRX: /* Hyperdrive/HCRX */ | |
1178 | memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom)); | |
1179 | if ((fb->sti->regions_phys[0] & 0xfc000000) == | |
1180 | (fb->sti->regions_phys[2] & 0xfc000000)) | |
5d6d1640 | 1181 | sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]); |
1da177e4 | 1182 | else |
5d6d1640 HD |
1183 | sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]); |
1184 | ||
1da177e4 LT |
1185 | fb->deviceSpecificConfig = gsc_readl(sti_rom_address); |
1186 | if (IS_24_DEVICE(fb)) { | |
1187 | if (bpp_pref == 8 || bpp_pref == 32) | |
1188 | bpp = bpp_pref; | |
1189 | else | |
1190 | bpp = 32; | |
1191 | } else | |
1192 | bpp = 8; | |
1193 | READ_WORD(fb, REG_15); | |
1194 | SETUP_HW(fb); | |
1195 | break; | |
1196 | case CRT_ID_VISUALIZE_EG: | |
1197 | case S9000_ID_ARTIST: /* Artist */ | |
1198 | break; | |
1199 | default: | |
1200 | #ifdef FALLBACK_TO_1BPP | |
1201 | printk(KERN_WARNING | |
1202 | "stifb: Unsupported graphics card (id=0x%08x) " | |
1203 | "- now trying 1bpp mode instead\n", | |
1204 | fb->id); | |
1205 | bpp = 1; /* default to 1 bpp */ | |
1206 | break; | |
1207 | #else | |
1208 | printk(KERN_WARNING | |
1209 | "stifb: Unsupported graphics card (id=0x%08x) " | |
1210 | "- skipping.\n", | |
1211 | fb->id); | |
1212 | goto out_err0; | |
1213 | #endif | |
1214 | } | |
1215 | ||
1216 | ||
1217 | /* get framebuffer physical and virtual base addr & len (64bit ready) */ | |
1218 | fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]); | |
1219 | fix->smem_len = fb->sti->regions[1].region_desc.length * 4096; | |
1220 | ||
1221 | fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8; | |
1222 | if (!fix->line_length) | |
1223 | fix->line_length = 2048; /* default */ | |
1224 | ||
1225 | /* limit fbsize to max visible screen size */ | |
1226 | if (fix->smem_len > yres*fix->line_length) | |
1227 | fix->smem_len = yres*fix->line_length; | |
1228 | ||
1229 | fix->accel = FB_ACCEL_NONE; | |
1230 | ||
1231 | switch (bpp) { | |
1232 | case 1: | |
1233 | fix->type = FB_TYPE_PLANES; /* well, sort of */ | |
1234 | fix->visual = FB_VISUAL_MONO10; | |
1235 | var->red.length = var->green.length = var->blue.length = 1; | |
1236 | break; | |
1237 | case 8: | |
1238 | fix->type = FB_TYPE_PACKED_PIXELS; | |
1239 | fix->visual = FB_VISUAL_PSEUDOCOLOR; | |
1240 | var->red.length = var->green.length = var->blue.length = 8; | |
1241 | break; | |
1242 | case 32: | |
1243 | fix->type = FB_TYPE_PACKED_PIXELS; | |
daaeb6f8 | 1244 | fix->visual = FB_VISUAL_DIRECTCOLOR; |
1da177e4 LT |
1245 | var->red.length = var->green.length = var->blue.length = var->transp.length = 8; |
1246 | var->blue.offset = 0; | |
1247 | var->green.offset = 8; | |
1248 | var->red.offset = 16; | |
1249 | var->transp.offset = 24; | |
1250 | break; | |
1251 | default: | |
1252 | break; | |
1253 | } | |
1254 | ||
1255 | var->xres = var->xres_virtual = xres; | |
1256 | var->yres = var->yres_virtual = yres; | |
1257 | var->bits_per_pixel = bpp; | |
1258 | ||
1259 | strcpy(fix->id, "stifb"); | |
1260 | info->fbops = &stifb_ops; | |
857600c7 HD |
1261 | info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len); |
1262 | info->screen_size = fix->smem_len; | |
1da177e4 LT |
1263 | info->flags = FBINFO_DEFAULT; |
1264 | info->pseudo_palette = &fb->pseudo_palette; | |
1265 | ||
1266 | /* This has to been done !!! */ | |
daaeb6f8 | 1267 | fb_alloc_cmap(&info->cmap, NR_PALETTE, 0); |
1da177e4 LT |
1268 | stifb_init_display(fb); |
1269 | ||
1270 | if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) { | |
1271 | printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n", | |
1272 | fix->smem_start, fix->smem_start+fix->smem_len); | |
1273 | goto out_err1; | |
1274 | } | |
1275 | ||
1276 | if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) { | |
1277 | printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n", | |
1278 | fix->mmio_start, fix->mmio_start+fix->mmio_len); | |
1279 | goto out_err2; | |
1280 | } | |
1281 | ||
1282 | if (register_framebuffer(&fb->info) < 0) | |
1283 | goto out_err3; | |
1284 | ||
1285 | sti->info = info; /* save for unregister_framebuffer() */ | |
1286 | ||
1287 | printk(KERN_INFO | |
1288 | "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n", | |
1289 | fb->info.node, | |
1290 | fix->id, | |
1291 | var->xres, | |
1292 | var->yres, | |
1293 | var->bits_per_pixel, | |
1294 | sti->outptr.dev_name, | |
1295 | fb->id, | |
1296 | fix->mmio_start); | |
1297 | ||
1298 | return 0; | |
1299 | ||
1300 | ||
1301 | out_err3: | |
1302 | release_mem_region(fix->mmio_start, fix->mmio_len); | |
1303 | out_err2: | |
1304 | release_mem_region(fix->smem_start, fix->smem_len); | |
1305 | out_err1: | |
9cf2014a | 1306 | iounmap(info->screen_base); |
1da177e4 LT |
1307 | fb_dealloc_cmap(&info->cmap); |
1308 | out_err0: | |
1309 | kfree(fb); | |
1310 | return -ENXIO; | |
1311 | } | |
1312 | ||
1313 | static int stifb_disabled __initdata; | |
1314 | ||
1315 | int __init | |
1316 | stifb_setup(char *options); | |
1317 | ||
1318 | int __init | |
1319 | stifb_init(void) | |
1320 | { | |
1321 | struct sti_struct *sti; | |
1322 | struct sti_struct *def_sti; | |
1323 | int i; | |
1324 | ||
1325 | #ifndef MODULE | |
1326 | char *option = NULL; | |
1327 | ||
1328 | if (fb_get_options("stifb", &option)) | |
1329 | return -ENODEV; | |
1330 | stifb_setup(option); | |
1331 | #endif | |
1332 | if (stifb_disabled) { | |
1333 | printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n"); | |
1334 | return -ENXIO; | |
1335 | } | |
1336 | ||
1337 | def_sti = sti_get_rom(0); | |
1338 | if (def_sti) { | |
1339 | for (i = 1; i <= MAX_STI_ROMS; i++) { | |
1340 | sti = sti_get_rom(i); | |
1341 | if (!sti) | |
1342 | break; | |
1343 | if (sti == def_sti) { | |
1344 | stifb_init_fb(sti, stifb_bpp_pref[i - 1]); | |
1345 | break; | |
1346 | } | |
1347 | } | |
1348 | } | |
1349 | ||
1350 | for (i = 1; i <= MAX_STI_ROMS; i++) { | |
1351 | sti = sti_get_rom(i); | |
1352 | if (!sti) | |
1353 | break; | |
1354 | if (sti == def_sti) | |
1355 | continue; | |
1356 | stifb_init_fb(sti, stifb_bpp_pref[i - 1]); | |
1357 | } | |
1358 | return 0; | |
1359 | } | |
1360 | ||
1361 | /* | |
1362 | * Cleanup | |
1363 | */ | |
1364 | ||
1365 | static void __exit | |
1366 | stifb_cleanup(void) | |
1367 | { | |
1368 | struct sti_struct *sti; | |
1369 | int i; | |
1370 | ||
1371 | for (i = 1; i <= MAX_STI_ROMS; i++) { | |
1372 | sti = sti_get_rom(i); | |
1373 | if (!sti) | |
1374 | break; | |
1375 | if (sti->info) { | |
1376 | struct fb_info *info = sti->info; | |
1377 | unregister_framebuffer(sti->info); | |
1378 | release_mem_region(info->fix.mmio_start, info->fix.mmio_len); | |
1379 | release_mem_region(info->fix.smem_start, info->fix.smem_len); | |
9cf2014a AL |
1380 | if (info->screen_base) |
1381 | iounmap(info->screen_base); | |
1da177e4 LT |
1382 | fb_dealloc_cmap(&info->cmap); |
1383 | kfree(info); | |
1384 | } | |
1385 | sti->info = NULL; | |
1386 | } | |
1387 | } | |
1388 | ||
1389 | int __init | |
1390 | stifb_setup(char *options) | |
1391 | { | |
1392 | int i; | |
1393 | ||
1394 | if (!options || !*options) | |
9b41046c | 1395 | return 1; |
1da177e4 LT |
1396 | |
1397 | if (strncmp(options, "off", 3) == 0) { | |
1398 | stifb_disabled = 1; | |
1399 | options += 3; | |
1400 | } | |
1401 | ||
1402 | if (strncmp(options, "bpp", 3) == 0) { | |
1403 | options += 3; | |
1404 | for (i = 0; i < MAX_STI_ROMS; i++) { | |
1405 | if (*options++ != ':') | |
1406 | break; | |
1407 | stifb_bpp_pref[i] = simple_strtoul(options, &options, 10); | |
1408 | } | |
1409 | } | |
9b41046c | 1410 | return 1; |
1da177e4 LT |
1411 | } |
1412 | ||
1413 | __setup("stifb=", stifb_setup); | |
1414 | ||
1415 | module_init(stifb_init); | |
1416 | module_exit(stifb_cleanup); | |
1417 | ||
1418 | MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>"); | |
1419 | MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines"); | |
1420 | MODULE_LICENSE("GPL v2"); |