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