1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52#undef FALLBACK_TO_1BPP
53
54#undef DEBUG_STIFB_REGS
55
56
57#include <linux/module.h>
58#include <linux/kernel.h>
59#include <linux/errno.h>
60#include <linux/string.h>
61#include <linux/mm.h>
62#include <linux/slab.h>
63#include <linux/delay.h>
64#include <linux/fb.h>
65#include <linux/init.h>
66#include <linux/ioport.h>
67
68#include <asm/grfioctl.h>
69#include <asm/uaccess.h>
70
71#include "sticore.h"
72
73
74#define REGION_BASE(fb_info, index) \
75 F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index])
76
77#define NGLEDEVDEPROM_CRT_REGION 1
78
79#define NR_PALETTE 256
80
81typedef struct {
82 __s32 video_config_reg;
83 __s32 misc_video_start;
84 __s32 horiz_timing_fmt;
85 __s32 serr_timing_fmt;
86 __s32 vert_timing_fmt;
87 __s32 horiz_state;
88 __s32 vert_state;
89 __s32 vtg_state_elements;
90 __s32 pipeline_delay;
91 __s32 misc_video_end;
92} video_setup_t;
93
94typedef struct {
95 __s16 sizeof_ngle_data;
96 __s16 x_size_visible;
97 __s16 y_size_visible;
98 __s16 pad2[15];
99 __s16 cursor_pipeline_delay;
100 __s16 video_interleaves;
101 __s32 pad3[11];
102} ngle_rom_t;
103
104struct stifb_info {
105 struct fb_info info;
106 unsigned int id;
107 ngle_rom_t ngle_rom;
108 struct sti_struct *sti;
109 int deviceSpecificConfig;
110 u32 pseudo_palette[16];
111};
112
113static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
114
115
116
117
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 __func__, 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 __func__, reg, value, READ_WORD(fb,reg)); \
172 gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
173#endif
174
175
176#define ENABLE 1
177#define DISABLE 0
178
179#define NGLE_LOCK(fb_info) do { } while (0)
180#define NGLE_UNLOCK(fb_info) do { } while (0)
181
182static void
183SETUP_HW(struct stifb_info *fb)
184{
185 char stat;
186
187 do {
188 stat = READ_BYTE(fb, REG_15b0);
189 if (!stat)
190 stat = READ_BYTE(fb, REG_15b0);
191 } while (stat);
192}
193
194
195static void
196SETUP_FB(struct stifb_info *fb)
197{
198 unsigned int reg10_value = 0;
199
200 SETUP_HW(fb);
201 switch (fb->id)
202 {
203 case CRT_ID_VISUALIZE_EG:
204 case S9000_ID_ARTIST:
205 case S9000_ID_A1659A:
206 reg10_value = 0x13601000;
207 break;
208 case S9000_ID_A1439A:
209 if (fb->info.var.bits_per_pixel == 32)
210 reg10_value = 0xBBA0A000;
211 else
212 reg10_value = 0x13601000;
213 break;
214 case S9000_ID_HCRX:
215 if (fb->info.var.bits_per_pixel == 32)
216 reg10_value = 0xBBA0A000;
217 else
218 reg10_value = 0x13602000;
219 break;
220 case S9000_ID_TIMBER:
221 case CRX24_OVERLAY_PLANES:
222 reg10_value = 0x13602000;
223 break;
224 }
225 if (reg10_value)
226 WRITE_WORD(reg10_value, fb, REG_10);
227 WRITE_WORD(0x83000300, fb, REG_14);
228 SETUP_HW(fb);
229 WRITE_BYTE(1, fb, REG_16b1);
230}
231
232static void
233START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
234{
235 SETUP_HW(fb);
236 WRITE_WORD(0xBBE0F000, fb, REG_10);
237 WRITE_WORD(0x03000300, fb, REG_14);
238 WRITE_WORD(~0, fb, REG_13);
239}
240
241static void
242WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
243{
244 SETUP_HW(fb);
245 WRITE_WORD(((0x100+index)<<2), fb, REG_3);
246 WRITE_WORD(color, fb, REG_4);
247}
248
249static void
250FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
251{
252 WRITE_WORD(0x400, fb, REG_2);
253 if (fb->info.var.bits_per_pixel == 32) {
254 WRITE_WORD(0x83000100, fb, REG_1);
255 } else {
256 if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
257 WRITE_WORD(0x80000100, fb, REG_26);
258 else
259 WRITE_WORD(0x80000100, fb, REG_1);
260 }
261 SETUP_FB(fb);
262}
263
264static void
265SETUP_RAMDAC(struct stifb_info *fb)
266{
267 SETUP_HW(fb);
268 WRITE_WORD(0x04000000, fb, 0x1020);
269 WRITE_WORD(0xff000000, fb, 0x1028);
270}
271
272static void
273CRX24_SETUP_RAMDAC(struct stifb_info *fb)
274{
275 SETUP_HW(fb);
276 WRITE_WORD(0x04000000, fb, 0x1000);
277 WRITE_WORD(0x02000000, fb, 0x1004);
278 WRITE_WORD(0xff000000, fb, 0x1008);
279 WRITE_WORD(0x05000000, fb, 0x1000);
280 WRITE_WORD(0x02000000, fb, 0x1004);
281 WRITE_WORD(0x03000000, fb, 0x1008);
282}
283
284#if 0
285static void
286HCRX_SETUP_RAMDAC(struct stifb_info *fb)
287{
288 WRITE_WORD(0xffffffff, fb, REG_32);
289}
290#endif
291
292static void
293CRX24_SET_OVLY_MASK(struct stifb_info *fb)
294{
295 SETUP_HW(fb);
296 WRITE_WORD(0x13a02000, fb, REG_11);
297 WRITE_WORD(0x03000300, fb, REG_14);
298 WRITE_WORD(0x000017f0, fb, REG_3);
299 WRITE_WORD(0xffffffff, fb, REG_13);
300 WRITE_WORD(0xffffffff, fb, REG_22);
301 WRITE_WORD(0x00000000, fb, REG_23);
302}
303
304static void
305ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
306{
307 unsigned int value = enable ? 0x43000000 : 0x03000000;
308 SETUP_HW(fb);
309 WRITE_WORD(0x06000000, fb, 0x1030);
310 WRITE_WORD(value, fb, 0x1038);
311}
312
313static void
314CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
315{
316 unsigned int value = enable ? 0x10000000 : 0x30000000;
317 SETUP_HW(fb);
318 WRITE_WORD(0x01000000, fb, 0x1000);
319 WRITE_WORD(0x02000000, fb, 0x1004);
320 WRITE_WORD(value, fb, 0x1008);
321}
322
323static void
324ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
325{
326 u32 DregsMiscVideo = REG_21;
327 u32 DregsMiscCtl = REG_27;
328
329 SETUP_HW(fb);
330 if (enable) {
331 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
332 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl);
333 } else {
334 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
335 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl);
336 }
337}
338
339#define GET_ROMTABLE_INDEX(fb) \
340 (READ_BYTE(fb, REG_16b3) - 1)
341
342#define HYPER_CONFIG_PLANES_24 0x00000100
343
344#define IS_24_DEVICE(fb) \
345 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
346
347#define IS_888_DEVICE(fb) \
348 (!(IS_24_DEVICE(fb)))
349
350#define GET_FIFO_SLOTS(fb, cnt, numslots) \
351{ while (cnt < numslots) \
352 cnt = READ_WORD(fb, REG_34); \
353 cnt -= numslots; \
354}
355
356#define IndexedDcd 0
357#define Otc04 2
358#define Otc32 5
359#define Ots08 3
360#define OtsIndirect 6
361#define AddrLong 5
362#define BINovly 0x2
363#define BINapp0I 0x0
364#define BINapp1I 0x1
365#define BINapp0F8 0xa
366#define BINattr 0xd
367#define RopSrc 0x3
368#define BitmapExtent08 3
369#define BitmapExtent32 5
370#define DataDynamic 0
371#define MaskDynamic 1
372#define MaskOtc 0
373
374#define MaskAddrOffset(offset) (offset)
375#define StaticReg(en) (en)
376#define BGx(en) (en)
377#define FGx(en) (en)
378
379#define BAJustPoint(offset) (offset)
380#define BAIndexBase(base) (base)
381#define BA(F,C,S,A,J,B,I) \
382 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
383
384#define IBOvals(R,M,X,S,D,L,B,F) \
385 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
386
387#define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
388 WRITE_WORD(val, fb, REG_14)
389
390#define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
391 WRITE_WORD(val, fb, REG_11)
392
393#define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
394 WRITE_WORD(val, fb, REG_12)
395
396#define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
397 WRITE_WORD(plnmsk32, fb, REG_13)
398
399#define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
400 WRITE_WORD(fg32, fb, REG_35)
401
402#define NGLE_SET_TRANSFERDATA(fb, val) \
403 WRITE_WORD(val, fb, REG_8)
404
405#define NGLE_SET_DSTXY(fb, val) \
406 WRITE_WORD(val, fb, REG_6)
407
408#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
409 (u32) (fbaddrbase) + \
410 ( (unsigned int) ( (y) << 13 ) | \
411 (unsigned int) ( (x) << 2 ) ) \
412 )
413
414#define NGLE_BINC_SET_DSTADDR(fb, addr) \
415 WRITE_WORD(addr, fb, REG_3)
416
417#define NGLE_BINC_SET_SRCADDR(fb, addr) \
418 WRITE_WORD(addr, fb, REG_2)
419
420#define NGLE_BINC_SET_DSTMASK(fb, mask) \
421 WRITE_WORD(mask, fb, REG_22)
422
423#define NGLE_BINC_WRITE32(fb, data32) \
424 WRITE_WORD(data32, fb, REG_23)
425
426#define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
427 WRITE_WORD((cmapBltCtlData32), fb, REG_38)
428
429#define SET_LENXY_START_RECFILL(fb, lenxy) \
430 WRITE_WORD(lenxy, fb, REG_9)
431
432static void
433HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
434{
435 u32 DregsHypMiscVideo = REG_33;
436 unsigned int value;
437 SETUP_HW(fb);
438 value = READ_WORD(fb, DregsHypMiscVideo);
439 if (enable)
440 value |= 0x0A000000;
441 else
442 value &= ~0x0A000000;
443 WRITE_WORD(value, fb, DregsHypMiscVideo);
444}
445
446
447
448#define BUFF0_CMAP0 0x00001e02
449#define BUFF1_CMAP0 0x02001e02
450#define BUFF1_CMAP3 0x0c001e02
451#define ARTIST_CMAP0 0x00000102
452#define HYPER_CMAP8 0x00000100
453#define HYPER_CMAP24 0x00000800
454
455static void
456SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
457{
458 SETUP_HW(fb);
459 WRITE_WORD(0x2EA0D000, fb, REG_11);
460 WRITE_WORD(0x23000302, fb, REG_14);
461 WRITE_WORD(BufferNumber, fb, REG_12);
462 WRITE_WORD(0xffffffff, fb, REG_8);
463}
464
465static void
466SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
467{
468
469
470
471
472
473
474
475 WRITE_WORD(0x00000000, fb, REG_6);
476 WRITE_WORD((width<<16) | height, fb, REG_9);
477 WRITE_WORD(0x05000000, fb, REG_6);
478 WRITE_WORD(0x00040001, fb, REG_9);
479}
480
481static void
482FINISH_ATTR_ACCESS(struct stifb_info *fb)
483{
484 SETUP_HW(fb);
485 WRITE_WORD(0x00000000, fb, REG_12);
486}
487
488static void
489elkSetupPlanes(struct stifb_info *fb)
490{
491 SETUP_RAMDAC(fb);
492 SETUP_FB(fb);
493}
494
495static void
496ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
497{
498 SETUP_ATTR_ACCESS(fb, BufferNumber);
499 SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
500 FINISH_ATTR_ACCESS(fb);
501 SETUP_FB(fb);
502}
503
504
505static void
506rattlerSetupPlanes(struct stifb_info *fb)
507{
508 int saved_id, y;
509
510
511
512
513
514 CRX24_SETUP_RAMDAC(fb);
515
516
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);
525
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
536typedef union
537{ u32 all;
538 struct
539 {
540 unsigned enable : 1;
541 unsigned waitBlank : 1;
542 unsigned reserved1 : 4;
543 unsigned lutOffset : 10;
544 unsigned lutType : 2;
545 unsigned reserved2 : 4;
546 unsigned length : 10;
547 } fields;
548} NgleLutBltCtl;
549
550
551#if 0
552static NgleLutBltCtl
553setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
554{
555 NgleLutBltCtl lutBltCtl;
556
557
558 lutBltCtl.all = 0x80000000;
559 lutBltCtl.fields.length = length;
560
561 switch (fb->id)
562 {
563 case S9000_ID_A1439A:
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
585 lutBltCtl.fields.lutOffset += offsetWithinLut;
586
587 return lutBltCtl;
588}
589#endif
590
591static NgleLutBltCtl
592setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
593{
594 NgleLutBltCtl lutBltCtl;
595
596
597 lutBltCtl.all = 0x80000000;
598
599 lutBltCtl.fields.length = length;
600 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
601
602
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
609 lutBltCtl.fields.lutOffset += offsetWithinLut;
610
611 return lutBltCtl;
612}
613
614
615static void hyperUndoITE(struct stifb_info *fb)
616{
617 int nFreeFifoSlots = 0;
618 u32 fbAddr;
619
620 NGLE_LOCK(fb);
621
622 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
623 WRITE_WORD(0xffffffff, fb, REG_32);
624
625
626
627
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
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
644 NGLE_BINC_WRITE32(fb, 0);
645
646 NGLE_UNLOCK(fb);
647}
648
649static void
650ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
651{
652
653}
654
655static void
656ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
657{
658
659}
660
661static void
662ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
663{
664 int nFreeFifoSlots = 0;
665 u32 packed_dst;
666 u32 packed_len;
667
668 NGLE_LOCK(fb);
669
670 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
671 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
672 BA(IndexedDcd, Otc32, OtsIndirect,
673 AddrLong, BAJustPoint(0),
674 BINattr, BAIndexBase(0)));
675 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
676 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
677
678 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
679 IBOvals(RopSrc, MaskAddrOffset(0),
680 BitmapExtent08, StaticReg(1),
681 DataDynamic, MaskOtc,
682 BGx(0), FGx(0)));
683 packed_dst = 0;
684 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
685 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
686 NGLE_SET_DSTXY(fb, packed_dst);
687 SET_LENXY_START_RECFILL(fb, packed_len);
688
689
690
691
692
693
694
695
696
697 if (fb->id == S9000_ID_A1659A) {
698
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 }
705
706
707 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
708 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
709
710 NGLE_UNLOCK(fb);
711}
712
713static void
714ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
715{
716 int nFreeFifoSlots = 0;
717 u32 packed_dst;
718 u32 packed_len;
719
720 NGLE_LOCK(fb);
721
722
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);
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
738 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
739 IBOvals(RopSrc, MaskAddrOffset(0),
740 BitmapExtent08, StaticReg(0),
741 DataDynamic, MaskOtc, BGx(0), FGx(0)));
742
743 SET_LENXY_START_RECFILL(fb, packed_len);
744
745 NGLE_UNLOCK(fb);
746}
747
748static void
749hyperResetPlanes(struct stifb_info *fb, int enable)
750{
751 unsigned int controlPlaneReg;
752
753 NGLE_LOCK(fb);
754
755 if (IS_24_DEVICE(fb))
756 if (fb->info.var.bits_per_pixel == 32)
757 controlPlaneReg = 0x04000F00;
758 else
759 controlPlaneReg = 0x00000F00;
760 else
761 controlPlaneReg = 0x00000F00;
762
763 switch (enable) {
764 case ENABLE:
765
766 if (IS_24_DEVICE(fb))
767 ngleDepth24_ClearImagePlanes(fb);
768 else
769 ngleDepth8_ClearImagePlanes(fb);
770
771
772
773 ngleResetAttrPlanes(fb, controlPlaneReg);
774
775
776 ngleClearOverlayPlanes(fb, 0xff, 255);
777
778
779
780
781 hyperUndoITE(fb);
782 break;
783
784 case DISABLE:
785
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:
795 hyperUndoITE(fb);
796 ngleResetAttrPlanes(fb, controlPlaneReg);
797 break;
798 }
799
800 NGLE_UNLOCK(fb);
801}
802
803
804
805static void
806ngleGetDeviceRomData(struct stifb_info *fb)
807{
808#if 0
809XXX: FIXME: !!!
810 int *pBytePerLongDevDepData;
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
828 pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
829
830
831 if (fb->id == S9000_ID_TOMCAT)
832 {
833
834 GET_ROMTABLE_INDEX(romTableIdx);
835 while (romTableIdx > 0)
836 {
837 pCard8 = (Card8 *) pPackedDevRomData;
838 pRomTable = pBytePerLongDevDepData;
839
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
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
873static void __init
874SETUP_HCRX(struct stifb_info *fb)
875{
876 int hyperbowl;
877 int nFreeFifoSlots = 0;
878
879 if (fb->id != S9000_ID_HCRX)
880 return;
881
882
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
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);
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
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
916
917static int
918stifb_setcolreg(u_int regno, u_int red, u_int green,
919 u_int blue, u_int transp, struct fb_info *info)
920{
921 struct stifb_info *fb = (struct stifb_info *) info;
922 u32 color;
923
924 if (regno >= NR_PALETTE)
925 return 1;
926
927 red >>= 8;
928 green >>= 8;
929 blue >>= 8;
930
931 DEBUG_OFF();
932
933 START_IMAGE_COLORMAP_ACCESS(fb);
934
935 if (unlikely(fb->info.var.grayscale)) {
936
937 color = ((red * 77) +
938 (green * 151) +
939 (blue * 28)) >> 8;
940 } else {
941 color = ((red << 16) |
942 (green << 8) |
943 (blue));
944 }
945
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;
953 }
954
955 WRITE_IMAGE_COLOR(fb, regno, color);
956
957 if (fb->id == S9000_ID_HCRX) {
958 NgleLutBltCtl lutBltCtl;
959
960 lutBltCtl = setHyperLutBltCtl(fb,
961 0,
962 256);
963 NGLE_BINC_SET_SRCADDR(fb,
964 NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
965
966 START_COLORMAPLOAD(fb, lutBltCtl.all);
967 SETUP_FB(fb);
968 } else {
969
970 FINISH_IMAGE_COLORMAP_ACCESS(fb);
971 }
972
973 DEBUG_ON();
974
975 return 0;
976}
977
978static int
979stifb_blank(int blank_mode, struct fb_info *info)
980{
981 struct stifb_info *fb = (struct stifb_info *) info;
982 int enable = (blank_mode == 0) ? ENABLE : DISABLE;
983
984 switch (fb->id) {
985 case S9000_ID_A1439A:
986 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
987 break;
988 case CRT_ID_VISUALIZE_EG:
989 case S9000_ID_ARTIST:
990 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
991 break;
992 case S9000_ID_HCRX:
993 HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
994 break;
995 case S9000_ID_A1659A:
996 case S9000_ID_TIMBER:
997 case CRX24_OVERLAY_PLANES:
998 default:
999 ENABLE_DISABLE_DISPLAY(fb, enable);
1000 break;
1001 }
1002
1003 SETUP_FB(fb);
1004 return 0;
1005}
1006
1007static void __init
1008stifb_init_display(struct stifb_info *fb)
1009{
1010 int id = fb->id;
1011
1012 SETUP_FB(fb);
1013
1014
1015 SETUP_HCRX(fb);
1016
1017
1018
1019
1020
1021
1022
1023
1024
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
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);
1061
1062 SETUP_FB(fb);
1063}
1064
1065
1066
1067static struct fb_ops stifb_ops = {
1068 .owner = THIS_MODULE,
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,
1074};
1075
1076
1077
1078
1079
1080
1081static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1082{
1083 struct fb_fix_screeninfo *fix;
1084 struct fb_var_screeninfo *var;
1085 struct stifb_info *fb;
1086 struct fb_info *info;
1087 unsigned long sti_rom_address;
1088 char *dev_name;
1089 int bpp, xres, yres;
1090
1091 fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
1092 if (!fb) {
1093 printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
1094 return -ENODEV;
1095 }
1096
1097 info = &fb->info;
1098
1099
1100 fix = &info->fix;
1101 var = &info->var;
1102
1103 fb->sti = sti;
1104
1105 fb->id = fb->sti->graphics_id[0];
1106
1107
1108 switch (fb->id) {
1109 case CRT_ID_VISUALIZE_EG:
1110
1111
1112
1113
1114
1115
1116
1117 if (strstr(sti->outptr.dev_name, "DX")) {
1118 printk(KERN_WARNING
1119"WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
1120"WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
1121 sti->outptr.dev_name);
1122 goto out_err0;
1123 }
1124
1125 case S9000_ID_ARTIST:
1126 case S9000_ID_HCRX:
1127 case S9000_ID_TIMBER:
1128 case S9000_ID_A1659A:
1129 case S9000_ID_A1439A:
1130 break;
1131 default:
1132 printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1133 sti->outptr.dev_name, fb->id);
1134 goto out_err0;
1135 }
1136
1137
1138 bpp = 8;
1139 xres = sti_onscreen_x(fb->sti);
1140 yres = sti_onscreen_y(fb->sti);
1141
1142 ngleGetDeviceRomData(fb);
1143
1144
1145 fix->mmio_start = REGION_BASE(fb,2);
1146 fix->mmio_len = 0x400000;
1147
1148
1149 switch (fb->id) {
1150 case S9000_ID_A1659A:
1151 break;
1152 case S9000_ID_ELM:
1153 var->grayscale = 1;
1154 fb->id = S9000_ID_A1659A;
1155 break;
1156 case S9000_ID_TIMBER:
1157 dev_name = fb->sti->outptr.dev_name;
1158 if (strstr(dev_name, "GRAYSCALE") ||
1159 strstr(dev_name, "Grayscale") ||
1160 strstr(dev_name, "grayscale"))
1161 var->grayscale = 1;
1162 break;
1163 case S9000_ID_TOMCAT:
1164
1165
1166
1167
1168 xres = fb->ngle_rom.x_size_visible;
1169 yres = fb->ngle_rom.y_size_visible;
1170 fb->id = S9000_ID_A1659A;
1171 break;
1172 case S9000_ID_A1439A:
1173 bpp = 32;
1174 break;
1175 case S9000_ID_HCRX:
1176 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1177 if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1178 (fb->sti->regions_phys[2] & 0xfc000000))
1179 sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1180 else
1181 sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1182
1183 fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1184 if (IS_24_DEVICE(fb)) {
1185 if (bpp_pref == 8 || bpp_pref == 32)
1186 bpp = bpp_pref;
1187 else
1188 bpp = 32;
1189 } else
1190 bpp = 8;
1191 READ_WORD(fb, REG_15);
1192 SETUP_HW(fb);
1193 break;
1194 case CRT_ID_VISUALIZE_EG:
1195 case S9000_ID_ARTIST:
1196 break;
1197 default:
1198#ifdef FALLBACK_TO_1BPP
1199 printk(KERN_WARNING
1200 "stifb: Unsupported graphics card (id=0x%08x) "
1201 "- now trying 1bpp mode instead\n",
1202 fb->id);
1203 bpp = 1;
1204 break;
1205#else
1206 printk(KERN_WARNING
1207 "stifb: Unsupported graphics card (id=0x%08x) "
1208 "- skipping.\n",
1209 fb->id);
1210 goto out_err0;
1211#endif
1212 }
1213
1214
1215
1216 fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1217 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1218
1219 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1220 if (!fix->line_length)
1221 fix->line_length = 2048;
1222
1223
1224 if (fix->smem_len > yres*fix->line_length)
1225 fix->smem_len = yres*fix->line_length;
1226
1227 fix->accel = FB_ACCEL_NONE;
1228
1229 switch (bpp) {
1230 case 1:
1231 fix->type = FB_TYPE_PLANES;
1232 fix->visual = FB_VISUAL_MONO10;
1233 var->red.length = var->green.length = var->blue.length = 1;
1234 break;
1235 case 8:
1236 fix->type = FB_TYPE_PACKED_PIXELS;
1237 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1238 var->red.length = var->green.length = var->blue.length = 8;
1239 break;
1240 case 32:
1241 fix->type = FB_TYPE_PACKED_PIXELS;
1242 fix->visual = FB_VISUAL_DIRECTCOLOR;
1243 var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1244 var->blue.offset = 0;
1245 var->green.offset = 8;
1246 var->red.offset = 16;
1247 var->transp.offset = 24;
1248 break;
1249 default:
1250 break;
1251 }
1252
1253 var->xres = var->xres_virtual = xres;
1254 var->yres = var->yres_virtual = yres;
1255 var->bits_per_pixel = bpp;
1256
1257 strcpy(fix->id, "stifb");
1258 info->fbops = &stifb_ops;
1259 info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
1260 info->screen_size = fix->smem_len;
1261 info->flags = FBINFO_DEFAULT;
1262 info->pseudo_palette = &fb->pseudo_palette;
1263
1264
1265 if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
1266 goto out_err1;
1267 stifb_init_display(fb);
1268
1269 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1270 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1271 fix->smem_start, fix->smem_start+fix->smem_len);
1272 goto out_err2;
1273 }
1274
1275 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1276 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1277 fix->mmio_start, fix->mmio_start+fix->mmio_len);
1278 goto out_err3;
1279 }
1280
1281 if (register_framebuffer(&fb->info) < 0)
1282 goto out_err4;
1283
1284 sti->info = info;
1285
1286 printk(KERN_INFO
1287 "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1288 fb->info.node,
1289 fix->id,
1290 var->xres,
1291 var->yres,
1292 var->bits_per_pixel,
1293 sti->outptr.dev_name,
1294 fb->id,
1295 fix->mmio_start);
1296
1297 return 0;
1298
1299
1300out_err4:
1301 release_mem_region(fix->mmio_start, fix->mmio_len);
1302out_err3:
1303 release_mem_region(fix->smem_start, fix->smem_len);
1304out_err2:
1305 fb_dealloc_cmap(&info->cmap);
1306out_err1:
1307 iounmap(info->screen_base);
1308out_err0:
1309 kfree(fb);
1310 return -ENXIO;
1311}
1312
1313static int stifb_disabled __initdata;
1314
1315int __init
1316stifb_setup(char *options);
1317
1318static int __init stifb_init(void)
1319{
1320 struct sti_struct *sti;
1321 struct sti_struct *def_sti;
1322 int i;
1323
1324#ifndef MODULE
1325 char *option = NULL;
1326
1327 if (fb_get_options("stifb", &option))
1328 return -ENODEV;
1329 stifb_setup(option);
1330#endif
1331 if (stifb_disabled) {
1332 printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1333 return -ENXIO;
1334 }
1335
1336 def_sti = sti_get_rom(0);
1337 if (def_sti) {
1338 for (i = 1; i <= MAX_STI_ROMS; i++) {
1339 sti = sti_get_rom(i);
1340 if (!sti)
1341 break;
1342 if (sti == def_sti) {
1343 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1344 break;
1345 }
1346 }
1347 }
1348
1349 for (i = 1; i <= MAX_STI_ROMS; i++) {
1350 sti = sti_get_rom(i);
1351 if (!sti)
1352 break;
1353 if (sti == def_sti)
1354 continue;
1355 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1356 }
1357 return 0;
1358}
1359
1360
1361
1362
1363
1364static void __exit
1365stifb_cleanup(void)
1366{
1367 struct sti_struct *sti;
1368 int i;
1369
1370 for (i = 1; i <= MAX_STI_ROMS; i++) {
1371 sti = sti_get_rom(i);
1372 if (!sti)
1373 break;
1374 if (sti->info) {
1375 struct fb_info *info = sti->info;
1376 unregister_framebuffer(sti->info);
1377 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1378 release_mem_region(info->fix.smem_start, info->fix.smem_len);
1379 if (info->screen_base)
1380 iounmap(info->screen_base);
1381 fb_dealloc_cmap(&info->cmap);
1382 framebuffer_release(info);
1383 }
1384 sti->info = NULL;
1385 }
1386}
1387
1388int __init
1389stifb_setup(char *options)
1390{
1391 int i;
1392
1393 if (!options || !*options)
1394 return 1;
1395
1396 if (strncmp(options, "off", 3) == 0) {
1397 stifb_disabled = 1;
1398 options += 3;
1399 }
1400
1401 if (strncmp(options, "bpp", 3) == 0) {
1402 options += 3;
1403 for (i = 0; i < MAX_STI_ROMS; i++) {
1404 if (*options++ != ':')
1405 break;
1406 stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1407 }
1408 }
1409 return 1;
1410}
1411
1412__setup("stifb=", stifb_setup);
1413
1414module_init(stifb_init);
1415module_exit(stifb_cleanup);
1416
1417MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1418MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1419MODULE_LICENSE("GPL v2");
1420