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#include <linux/io.h>
68
69#include <asm/grfioctl.h>
70#include <linux/uaccess.h>
71
72#include "sticore.h"
73
74
75#define REGION_BASE(fb_info, index) \
76 F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index])
77
78#define NGLEDEVDEPROM_CRT_REGION 1
79
80#define NR_PALETTE 256
81
82typedef struct {
83 __s32 video_config_reg;
84 __s32 misc_video_start;
85 __s32 horiz_timing_fmt;
86 __s32 serr_timing_fmt;
87 __s32 vert_timing_fmt;
88 __s32 horiz_state;
89 __s32 vert_state;
90 __s32 vtg_state_elements;
91 __s32 pipeline_delay;
92 __s32 misc_video_end;
93} video_setup_t;
94
95typedef struct {
96 __s16 sizeof_ngle_data;
97 __s16 x_size_visible;
98 __s16 y_size_visible;
99 __s16 pad2[15];
100 __s16 cursor_pipeline_delay;
101 __s16 video_interleaves;
102 __s32 pad3[11];
103} ngle_rom_t;
104
105struct stifb_info {
106 struct fb_info info;
107 unsigned int id;
108 ngle_rom_t ngle_rom;
109 struct sti_struct *sti;
110 int deviceSpecificConfig;
111 u32 pseudo_palette[16];
112};
113
114static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
115
116
117
118
119
120#define REG_1 0x000118
121#define REG_2 0x000480
122#define REG_3 0x0004a0
123#define REG_4 0x000600
124#define REG_6 0x000800
125#define REG_7 0x000804
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_24 0x000808
141#define REG_25 0x000b00
142#define REG_26 0x200118
143#define REG_27 0x200308
144#define REG_32 0x21003c
145#define REG_33 0x210040
146#define REG_34 0x200008
147#define REG_35 0x018010
148#define REG_38 0x210020
149#define REG_39 0x210120
150#define REG_40 0x210130
151#define REG_42 0x210028
152#define REG_43 0x21002c
153#define REG_44 0x210030
154#define REG_45 0x210034
155
156#define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg))
157#define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg))
158
159
160#ifndef DEBUG_STIFB_REGS
161# define DEBUG_OFF()
162# define DEBUG_ON()
163# define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
164# define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
165#else
166 static int debug_on = 1;
167# define DEBUG_OFF() debug_on=0
168# define DEBUG_ON() debug_on=1
169# define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
170 printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
171 __func__, reg, value, READ_BYTE(fb,reg)); \
172 gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
173# define WRITE_WORD(value,fb,reg) do { if (debug_on) \
174 printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
175 __func__, reg, value, READ_WORD(fb,reg)); \
176 gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
177#endif
178
179
180#define ENABLE 1
181#define DISABLE 0
182
183#define NGLE_LOCK(fb_info) do { } while (0)
184#define NGLE_UNLOCK(fb_info) do { } while (0)
185
186static void
187SETUP_HW(struct stifb_info *fb)
188{
189 char stat;
190
191 do {
192 stat = READ_BYTE(fb, REG_15b0);
193 if (!stat)
194 stat = READ_BYTE(fb, REG_15b0);
195 } while (stat);
196}
197
198
199static void
200SETUP_FB(struct stifb_info *fb)
201{
202 unsigned int reg10_value = 0;
203
204 SETUP_HW(fb);
205 switch (fb->id)
206 {
207 case CRT_ID_VISUALIZE_EG:
208 case S9000_ID_ARTIST:
209 case S9000_ID_A1659A:
210 reg10_value = 0x13601000;
211 break;
212 case S9000_ID_A1439A:
213 if (fb->info.var.bits_per_pixel == 32)
214 reg10_value = 0xBBA0A000;
215 else
216 reg10_value = 0x13601000;
217 break;
218 case S9000_ID_HCRX:
219 if (fb->info.var.bits_per_pixel == 32)
220 reg10_value = 0xBBA0A000;
221 else
222 reg10_value = 0x13602000;
223 break;
224 case S9000_ID_TIMBER:
225 case CRX24_OVERLAY_PLANES:
226 reg10_value = 0x13602000;
227 break;
228 }
229 if (reg10_value)
230 WRITE_WORD(reg10_value, fb, REG_10);
231 WRITE_WORD(0x83000300, fb, REG_14);
232 SETUP_HW(fb);
233 WRITE_BYTE(1, fb, REG_16b1);
234}
235
236static void
237START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
238{
239 SETUP_HW(fb);
240 WRITE_WORD(0xBBE0F000, fb, REG_10);
241 WRITE_WORD(0x03000300, fb, REG_14);
242 WRITE_WORD(~0, fb, REG_13);
243}
244
245static void
246WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
247{
248 SETUP_HW(fb);
249 WRITE_WORD(((0x100+index)<<2), fb, REG_3);
250 WRITE_WORD(color, fb, REG_4);
251}
252
253static void
254FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
255{
256 WRITE_WORD(0x400, fb, REG_2);
257 if (fb->info.var.bits_per_pixel == 32) {
258 WRITE_WORD(0x83000100, fb, REG_1);
259 } else {
260 if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
261 WRITE_WORD(0x80000100, fb, REG_26);
262 else
263 WRITE_WORD(0x80000100, fb, REG_1);
264 }
265 SETUP_FB(fb);
266}
267
268static void
269SETUP_RAMDAC(struct stifb_info *fb)
270{
271 SETUP_HW(fb);
272 WRITE_WORD(0x04000000, fb, 0x1020);
273 WRITE_WORD(0xff000000, fb, 0x1028);
274}
275
276static void
277CRX24_SETUP_RAMDAC(struct stifb_info *fb)
278{
279 SETUP_HW(fb);
280 WRITE_WORD(0x04000000, fb, 0x1000);
281 WRITE_WORD(0x02000000, fb, 0x1004);
282 WRITE_WORD(0xff000000, fb, 0x1008);
283 WRITE_WORD(0x05000000, fb, 0x1000);
284 WRITE_WORD(0x02000000, fb, 0x1004);
285 WRITE_WORD(0x03000000, fb, 0x1008);
286}
287
288#if 0
289static void
290HCRX_SETUP_RAMDAC(struct stifb_info *fb)
291{
292 WRITE_WORD(0xffffffff, fb, REG_32);
293}
294#endif
295
296static void
297CRX24_SET_OVLY_MASK(struct stifb_info *fb)
298{
299 SETUP_HW(fb);
300 WRITE_WORD(0x13a02000, fb, REG_11);
301 WRITE_WORD(0x03000300, fb, REG_14);
302 WRITE_WORD(0x000017f0, fb, REG_3);
303 WRITE_WORD(0xffffffff, fb, REG_13);
304 WRITE_WORD(0xffffffff, fb, REG_22);
305 WRITE_WORD(0x00000000, fb, REG_23);
306}
307
308static void
309ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
310{
311 unsigned int value = enable ? 0x43000000 : 0x03000000;
312 SETUP_HW(fb);
313 WRITE_WORD(0x06000000, fb, 0x1030);
314 WRITE_WORD(value, fb, 0x1038);
315}
316
317static void
318CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
319{
320 unsigned int value = enable ? 0x10000000 : 0x30000000;
321 SETUP_HW(fb);
322 WRITE_WORD(0x01000000, fb, 0x1000);
323 WRITE_WORD(0x02000000, fb, 0x1004);
324 WRITE_WORD(value, fb, 0x1008);
325}
326
327static void
328ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
329{
330 u32 DregsMiscVideo = REG_21;
331 u32 DregsMiscCtl = REG_27;
332
333 SETUP_HW(fb);
334 if (enable) {
335 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
336 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl);
337 } else {
338 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
339 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl);
340 }
341}
342
343#define GET_ROMTABLE_INDEX(fb) \
344 (READ_BYTE(fb, REG_16b3) - 1)
345
346#define HYPER_CONFIG_PLANES_24 0x00000100
347
348#define IS_24_DEVICE(fb) \
349 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
350
351#define IS_888_DEVICE(fb) \
352 (!(IS_24_DEVICE(fb)))
353
354#define GET_FIFO_SLOTS(fb, cnt, numslots) \
355{ while (cnt < numslots) \
356 cnt = READ_WORD(fb, REG_34); \
357 cnt -= numslots; \
358}
359
360#define IndexedDcd 0
361#define Otc04 2
362#define Otc32 5
363#define Ots08 3
364#define OtsIndirect 6
365#define AddrLong 5
366#define BINovly 0x2
367#define BINapp0I 0x0
368#define BINapp1I 0x1
369#define BINapp0F8 0xa
370#define BINattr 0xd
371#define RopSrc 0x3
372#define BitmapExtent08 3
373#define BitmapExtent32 5
374#define DataDynamic 0
375#define MaskDynamic 1
376#define MaskOtc 0
377
378#define MaskAddrOffset(offset) (offset)
379#define StaticReg(en) (en)
380#define BGx(en) (en)
381#define FGx(en) (en)
382
383#define BAJustPoint(offset) (offset)
384#define BAIndexBase(base) (base)
385#define BA(F,C,S,A,J,B,I) \
386 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
387
388#define IBOvals(R,M,X,S,D,L,B,F) \
389 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
390
391#define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
392 WRITE_WORD(val, fb, REG_14)
393
394#define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
395 WRITE_WORD(val, fb, REG_11)
396
397#define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
398 WRITE_WORD(val, fb, REG_12)
399
400#define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
401 WRITE_WORD(plnmsk32, fb, REG_13)
402
403#define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
404 WRITE_WORD(fg32, fb, REG_35)
405
406#define NGLE_SET_TRANSFERDATA(fb, val) \
407 WRITE_WORD(val, fb, REG_8)
408
409#define NGLE_SET_DSTXY(fb, val) \
410 WRITE_WORD(val, fb, REG_6)
411
412#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
413 (u32) (fbaddrbase) + \
414 ( (unsigned int) ( (y) << 13 ) | \
415 (unsigned int) ( (x) << 2 ) ) \
416 )
417
418#define NGLE_BINC_SET_DSTADDR(fb, addr) \
419 WRITE_WORD(addr, fb, REG_3)
420
421#define NGLE_BINC_SET_SRCADDR(fb, addr) \
422 WRITE_WORD(addr, fb, REG_2)
423
424#define NGLE_BINC_SET_DSTMASK(fb, mask) \
425 WRITE_WORD(mask, fb, REG_22)
426
427#define NGLE_BINC_WRITE32(fb, data32) \
428 WRITE_WORD(data32, fb, REG_23)
429
430#define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
431 WRITE_WORD((cmapBltCtlData32), fb, REG_38)
432
433#define SET_LENXY_START_RECFILL(fb, lenxy) \
434 WRITE_WORD(lenxy, fb, REG_9)
435
436#define SETUP_COPYAREA(fb) \
437 WRITE_BYTE(0, fb, REG_16b1)
438
439static void
440HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
441{
442 u32 DregsHypMiscVideo = REG_33;
443 unsigned int value;
444 SETUP_HW(fb);
445 value = READ_WORD(fb, DregsHypMiscVideo);
446 if (enable)
447 value |= 0x0A000000;
448 else
449 value &= ~0x0A000000;
450 WRITE_WORD(value, fb, DregsHypMiscVideo);
451}
452
453
454
455#define BUFF0_CMAP0 0x00001e02
456#define BUFF1_CMAP0 0x02001e02
457#define BUFF1_CMAP3 0x0c001e02
458#define ARTIST_CMAP0 0x00000102
459#define HYPER_CMAP8 0x00000100
460#define HYPER_CMAP24 0x00000800
461
462static void
463SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
464{
465 SETUP_HW(fb);
466 WRITE_WORD(0x2EA0D000, fb, REG_11);
467 WRITE_WORD(0x23000302, fb, REG_14);
468 WRITE_WORD(BufferNumber, fb, REG_12);
469 WRITE_WORD(0xffffffff, fb, REG_8);
470}
471
472static void
473SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
474{
475
476
477
478
479
480
481
482 WRITE_WORD(0x00000000, fb, REG_6);
483 WRITE_WORD((width<<16) | height, fb, REG_9);
484 WRITE_WORD(0x05000000, fb, REG_6);
485 WRITE_WORD(0x00040001, fb, REG_9);
486}
487
488static void
489FINISH_ATTR_ACCESS(struct stifb_info *fb)
490{
491 SETUP_HW(fb);
492 WRITE_WORD(0x00000000, fb, REG_12);
493}
494
495static void
496elkSetupPlanes(struct stifb_info *fb)
497{
498 SETUP_RAMDAC(fb);
499 SETUP_FB(fb);
500}
501
502static void
503ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
504{
505 SETUP_ATTR_ACCESS(fb, BufferNumber);
506 SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
507 FINISH_ATTR_ACCESS(fb);
508 SETUP_FB(fb);
509}
510
511
512static void
513rattlerSetupPlanes(struct stifb_info *fb)
514{
515 int saved_id, y;
516
517
518
519
520
521 CRX24_SETUP_RAMDAC(fb);
522
523
524 saved_id = fb->id;
525 fb->id = CRX24_OVERLAY_PLANES;
526 SETUP_FB(fb);
527 fb->id = saved_id;
528
529 for (y = 0; y < fb->info.var.yres; ++y)
530 fb_memset(fb->info.screen_base + y * fb->info.fix.line_length,
531 0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8);
532
533 CRX24_SET_OVLY_MASK(fb);
534 SETUP_FB(fb);
535}
536
537
538#define HYPER_CMAP_TYPE 0
539#define NGLE_CMAP_INDEXED0_TYPE 0
540#define NGLE_CMAP_OVERLAY_TYPE 3
541
542
543typedef union
544{ u32 all;
545 struct
546 {
547 unsigned enable : 1;
548 unsigned waitBlank : 1;
549 unsigned reserved1 : 4;
550 unsigned lutOffset : 10;
551 unsigned lutType : 2;
552 unsigned reserved2 : 4;
553 unsigned length : 10;
554 } fields;
555} NgleLutBltCtl;
556
557
558#if 0
559static NgleLutBltCtl
560setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
561{
562 NgleLutBltCtl lutBltCtl;
563
564
565 lutBltCtl.all = 0x80000000;
566 lutBltCtl.fields.length = length;
567
568 switch (fb->id)
569 {
570 case S9000_ID_A1439A:
571 if (fb->var.bits_per_pixel == 8) {
572 lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
573 lutBltCtl.fields.lutOffset = 0;
574 } else {
575 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
576 lutBltCtl.fields.lutOffset = 0 * 256;
577 }
578 break;
579
580 case S9000_ID_ARTIST:
581 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
582 lutBltCtl.fields.lutOffset = 0 * 256;
583 break;
584
585 default:
586 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
587 lutBltCtl.fields.lutOffset = 0;
588 break;
589 }
590
591
592 lutBltCtl.fields.lutOffset += offsetWithinLut;
593
594 return lutBltCtl;
595}
596#endif
597
598static NgleLutBltCtl
599setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
600{
601 NgleLutBltCtl lutBltCtl;
602
603
604 lutBltCtl.all = 0x80000000;
605
606 lutBltCtl.fields.length = length;
607 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
608
609
610 if (fb->info.var.bits_per_pixel == 8)
611 lutBltCtl.fields.lutOffset = 2 * 256;
612 else
613 lutBltCtl.fields.lutOffset = 0 * 256;
614
615
616 lutBltCtl.fields.lutOffset += offsetWithinLut;
617
618 return lutBltCtl;
619}
620
621
622static void hyperUndoITE(struct stifb_info *fb)
623{
624 int nFreeFifoSlots = 0;
625 u32 fbAddr;
626
627 NGLE_LOCK(fb);
628
629 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
630 WRITE_WORD(0xffffffff, fb, REG_32);
631
632
633
634
635 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
636 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
637 BA(IndexedDcd, Otc04, Ots08, AddrLong,
638 BAJustPoint(0), BINovly, BAIndexBase(0)));
639 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
640 IBOvals(RopSrc, MaskAddrOffset(0),
641 BitmapExtent08, StaticReg(0),
642 DataDynamic, MaskOtc, BGx(0), FGx(0)));
643
644
645 fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
646 NGLE_BINC_SET_DSTADDR(fb, fbAddr);
647 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
648 NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
649
650
651 NGLE_BINC_WRITE32(fb, 0);
652
653 NGLE_UNLOCK(fb);
654}
655
656static void
657ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
658{
659
660}
661
662static void
663ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
664{
665
666}
667
668static void
669ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
670{
671 int nFreeFifoSlots = 0;
672 u32 packed_dst;
673 u32 packed_len;
674
675 NGLE_LOCK(fb);
676
677 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
678 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
679 BA(IndexedDcd, Otc32, OtsIndirect,
680 AddrLong, BAJustPoint(0),
681 BINattr, BAIndexBase(0)));
682 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
683 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
684
685 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
686 IBOvals(RopSrc, MaskAddrOffset(0),
687 BitmapExtent08, StaticReg(1),
688 DataDynamic, MaskOtc,
689 BGx(0), FGx(0)));
690 packed_dst = 0;
691 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
692 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
693 NGLE_SET_DSTXY(fb, packed_dst);
694 SET_LENXY_START_RECFILL(fb, packed_len);
695
696
697
698
699
700
701
702
703
704 if (fb->id == S9000_ID_A1659A) {
705
706 packed_dst = (1280 << 16);
707 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
708 NGLE_SET_DSTXY(fb, packed_dst);
709 packed_len = (4 << 16) | 1;
710 SET_LENXY_START_RECFILL(fb, packed_len);
711 }
712
713
714 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
715 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
716
717 NGLE_UNLOCK(fb);
718}
719
720static void
721ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
722{
723 int nFreeFifoSlots = 0;
724 u32 packed_dst;
725 u32 packed_len;
726
727 NGLE_LOCK(fb);
728
729
730 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
731 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
732 BA(IndexedDcd, Otc04, Ots08, AddrLong,
733 BAJustPoint(0), BINovly, BAIndexBase(0)));
734
735 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
736
737 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
738 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
739
740 packed_dst = 0;
741 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
742 NGLE_SET_DSTXY(fb, packed_dst);
743
744
745 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
746 IBOvals(RopSrc, MaskAddrOffset(0),
747 BitmapExtent08, StaticReg(0),
748 DataDynamic, MaskOtc, BGx(0), FGx(0)));
749
750 SET_LENXY_START_RECFILL(fb, packed_len);
751
752 NGLE_UNLOCK(fb);
753}
754
755static void
756hyperResetPlanes(struct stifb_info *fb, int enable)
757{
758 unsigned int controlPlaneReg;
759
760 NGLE_LOCK(fb);
761
762 if (IS_24_DEVICE(fb))
763 if (fb->info.var.bits_per_pixel == 32)
764 controlPlaneReg = 0x04000F00;
765 else
766 controlPlaneReg = 0x00000F00;
767 else
768 controlPlaneReg = 0x00000F00;
769
770 switch (enable) {
771 case ENABLE:
772
773 if (IS_24_DEVICE(fb))
774 ngleDepth24_ClearImagePlanes(fb);
775 else
776 ngleDepth8_ClearImagePlanes(fb);
777
778
779
780 ngleResetAttrPlanes(fb, controlPlaneReg);
781
782
783 ngleClearOverlayPlanes(fb, 0xff, 255);
784
785
786
787
788 hyperUndoITE(fb);
789 break;
790
791 case DISABLE:
792
793 if (IS_24_DEVICE(fb))
794 ngleDepth24_ClearImagePlanes(fb);
795 else
796 ngleDepth8_ClearImagePlanes(fb);
797 ngleResetAttrPlanes(fb, controlPlaneReg);
798 ngleClearOverlayPlanes(fb, 0xff, 0);
799 break;
800
801 case -1:
802 hyperUndoITE(fb);
803 ngleResetAttrPlanes(fb, controlPlaneReg);
804 break;
805 }
806
807 NGLE_UNLOCK(fb);
808}
809
810
811
812static void
813ngleGetDeviceRomData(struct stifb_info *fb)
814{
815#if 0
816XXX: FIXME: !!!
817 int *pBytePerLongDevDepData;
818 int *pRomTable;
819 NgleDevRomData *pPackedDevRomData;
820 int sizePackedDevRomData = sizeof(*pPackedDevRomData);
821 char *pCard8;
822 int i;
823 char *mapOrigin = NULL;
824
825 int romTableIdx;
826
827 pPackedDevRomData = fb->ngle_rom;
828
829 SETUP_HW(fb);
830 if (fb->id == S9000_ID_ARTIST) {
831 pPackedDevRomData->cursor_pipeline_delay = 4;
832 pPackedDevRomData->video_interleaves = 4;
833 } else {
834
835 pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
836
837
838 if (fb->id == S9000_ID_TOMCAT)
839 {
840
841 GET_ROMTABLE_INDEX(romTableIdx);
842 while (romTableIdx > 0)
843 {
844 pCard8 = (Card8 *) pPackedDevRomData;
845 pRomTable = pBytePerLongDevDepData;
846
847 for (i = 0; i < sizePackedDevRomData; i++)
848 {
849 *pCard8++ = (Card8) (*pRomTable++);
850 }
851
852 pBytePerLongDevDepData = (Card32 *)
853 ((Card8 *) pBytePerLongDevDepData +
854 pPackedDevRomData->sizeof_ngle_data);
855
856 romTableIdx--;
857 }
858 }
859
860 pCard8 = (Card8 *) pPackedDevRomData;
861
862
863 for (i = 0; i < sizePackedDevRomData; i++)
864 {
865 *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
866 }
867 }
868
869 SETUP_FB(fb);
870#endif
871}
872
873
874#define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
875#define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8
876#define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10
877#define HYPERBOWL_MODE2_8_24 15
878
879
880static void __init
881SETUP_HCRX(struct stifb_info *fb)
882{
883 int hyperbowl;
884 int nFreeFifoSlots = 0;
885
886 if (fb->id != S9000_ID_HCRX)
887 return;
888
889
890 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
891
892 if (IS_24_DEVICE(fb)) {
893 hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
894 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
895 HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
896
897
898 WRITE_WORD(hyperbowl, fb, REG_40);
899 WRITE_WORD(hyperbowl, fb, REG_40);
900
901 WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
902
903 WRITE_WORD(0x014c0148, fb, REG_42);
904 WRITE_WORD(0x404c4048, fb, REG_43);
905 WRITE_WORD(0x034c0348, fb, REG_44);
906 WRITE_WORD(0x444c4448, fb, REG_45);
907 } else {
908 hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
909
910
911 WRITE_WORD(hyperbowl, fb, REG_40);
912 WRITE_WORD(hyperbowl, fb, REG_40);
913
914 WRITE_WORD(0x00000000, fb, REG_42);
915 WRITE_WORD(0x00000000, fb, REG_43);
916 WRITE_WORD(0x00000000, fb, REG_44);
917 WRITE_WORD(0x444c4048, fb, REG_45);
918 }
919}
920
921
922
923
924static int
925stifb_setcolreg(u_int regno, u_int red, u_int green,
926 u_int blue, u_int transp, struct fb_info *info)
927{
928 struct stifb_info *fb = container_of(info, struct stifb_info, info);
929 u32 color;
930
931 if (regno >= NR_PALETTE)
932 return 1;
933
934 red >>= 8;
935 green >>= 8;
936 blue >>= 8;
937
938 DEBUG_OFF();
939
940 START_IMAGE_COLORMAP_ACCESS(fb);
941
942 if (unlikely(fb->info.var.grayscale)) {
943
944 color = ((red * 77) +
945 (green * 151) +
946 (blue * 28)) >> 8;
947 } else {
948 color = ((red << 16) |
949 (green << 8) |
950 (blue));
951 }
952
953 if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
954 struct fb_var_screeninfo *var = &fb->info.var;
955 if (regno < 16)
956 ((u32 *)fb->info.pseudo_palette)[regno] =
957 regno << var->red.offset |
958 regno << var->green.offset |
959 regno << var->blue.offset;
960 }
961
962 WRITE_IMAGE_COLOR(fb, regno, color);
963
964 if (fb->id == S9000_ID_HCRX) {
965 NgleLutBltCtl lutBltCtl;
966
967 lutBltCtl = setHyperLutBltCtl(fb,
968 0,
969 256);
970 NGLE_BINC_SET_SRCADDR(fb,
971 NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
972
973 START_COLORMAPLOAD(fb, lutBltCtl.all);
974 SETUP_FB(fb);
975 } else {
976
977 FINISH_IMAGE_COLORMAP_ACCESS(fb);
978 }
979
980 DEBUG_ON();
981
982 return 0;
983}
984
985static int
986stifb_blank(int blank_mode, struct fb_info *info)
987{
988 struct stifb_info *fb = container_of(info, struct stifb_info, info);
989 int enable = (blank_mode == 0) ? ENABLE : DISABLE;
990
991 switch (fb->id) {
992 case S9000_ID_A1439A:
993 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
994 break;
995 case CRT_ID_VISUALIZE_EG:
996 case S9000_ID_ARTIST:
997 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
998 break;
999 case S9000_ID_HCRX:
1000 HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
1001 break;
1002 case S9000_ID_A1659A:
1003 case S9000_ID_TIMBER:
1004 case CRX24_OVERLAY_PLANES:
1005 default:
1006 ENABLE_DISABLE_DISPLAY(fb, enable);
1007 break;
1008 }
1009
1010 SETUP_FB(fb);
1011 return 0;
1012}
1013
1014static void
1015stifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1016{
1017 struct stifb_info *fb = container_of(info, struct stifb_info, info);
1018
1019 SETUP_COPYAREA(fb);
1020
1021 SETUP_HW(fb);
1022 if (fb->info.var.bits_per_pixel == 32) {
1023 WRITE_WORD(0xBBA0A000, fb, REG_10);
1024
1025 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
1026 } else {
1027 WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
1028
1029 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
1030 }
1031
1032 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
1033 IBOvals(RopSrc, MaskAddrOffset(0),
1034 BitmapExtent08, StaticReg(1),
1035 DataDynamic, MaskOtc, BGx(0), FGx(0)));
1036
1037 WRITE_WORD(((area->sx << 16) | area->sy), fb, REG_24);
1038 WRITE_WORD(((area->width << 16) | area->height), fb, REG_7);
1039 WRITE_WORD(((area->dx << 16) | area->dy), fb, REG_25);
1040
1041 SETUP_FB(fb);
1042}
1043
1044#define ARTIST_VRAM_SIZE 0x000804
1045#define ARTIST_VRAM_SRC 0x000808
1046#define ARTIST_VRAM_SIZE_TRIGGER_WINFILL 0x000a04
1047#define ARTIST_VRAM_DEST_TRIGGER_BLOCKMOVE 0x000b00
1048#define ARTIST_SRC_BM_ACCESS 0x018008
1049#define ARTIST_FGCOLOR 0x018010
1050#define ARTIST_BGCOLOR 0x018014
1051#define ARTIST_BITMAP_OP 0x01801c
1052
1053static void
1054stifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
1055{
1056 struct stifb_info *fb = container_of(info, struct stifb_info, info);
1057
1058 if (rect->rop != ROP_COPY)
1059 return cfb_fillrect(info, rect);
1060
1061 SETUP_HW(fb);
1062
1063 if (fb->info.var.bits_per_pixel == 32) {
1064 WRITE_WORD(0xBBA0A000, fb, REG_10);
1065
1066 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
1067 } else {
1068 WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
1069
1070 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
1071 }
1072
1073 WRITE_WORD(0x03000300, fb, ARTIST_BITMAP_OP);
1074 WRITE_WORD(0x2ea01000, fb, ARTIST_SRC_BM_ACCESS);
1075 NGLE_QUICK_SET_DST_BM_ACCESS(fb, 0x2ea01000);
1076 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, rect->color);
1077 WRITE_WORD(0, fb, ARTIST_BGCOLOR);
1078
1079 NGLE_SET_DSTXY(fb, (rect->dx << 16) | (rect->dy));
1080 SET_LENXY_START_RECFILL(fb, (rect->width << 16) | (rect->height));
1081
1082 SETUP_FB(fb);
1083}
1084
1085static void __init
1086stifb_init_display(struct stifb_info *fb)
1087{
1088 int id = fb->id;
1089
1090 SETUP_FB(fb);
1091
1092
1093 SETUP_HCRX(fb);
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103 switch (id) {
1104 case S9000_ID_HCRX:
1105 hyperResetPlanes(fb, ENABLE);
1106 break;
1107 case S9000_ID_A1439A:
1108 rattlerSetupPlanes(fb);
1109 break;
1110 case S9000_ID_A1659A:
1111 case S9000_ID_ARTIST:
1112 case CRT_ID_VISUALIZE_EG:
1113 elkSetupPlanes(fb);
1114 break;
1115 }
1116
1117
1118 switch (id) {
1119 case S9000_ID_A1659A:
1120 case S9000_ID_A1439A:
1121 if (fb->info.var.bits_per_pixel == 32)
1122 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1123 else {
1124 ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
1125 }
1126 if (id == S9000_ID_A1439A)
1127 ngleClearOverlayPlanes(fb, 0xff, 0);
1128 break;
1129 case S9000_ID_ARTIST:
1130 case CRT_ID_VISUALIZE_EG:
1131 if (fb->info.var.bits_per_pixel == 32)
1132 ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
1133 else {
1134 ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
1135 }
1136 break;
1137 }
1138 stifb_blank(0, (struct fb_info *)fb);
1139
1140 SETUP_FB(fb);
1141}
1142
1143
1144
1145static const struct fb_ops stifb_ops = {
1146 .owner = THIS_MODULE,
1147 .fb_setcolreg = stifb_setcolreg,
1148 .fb_blank = stifb_blank,
1149 .fb_fillrect = stifb_fillrect,
1150 .fb_copyarea = stifb_copyarea,
1151 .fb_imageblit = cfb_imageblit,
1152};
1153
1154
1155
1156
1157
1158
1159static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
1160{
1161 struct fb_fix_screeninfo *fix;
1162 struct fb_var_screeninfo *var;
1163 struct stifb_info *fb;
1164 struct fb_info *info;
1165 unsigned long sti_rom_address;
1166 char *dev_name;
1167 int bpp, xres, yres;
1168
1169 fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
1170 if (!fb)
1171 return -ENOMEM;
1172
1173 info = &fb->info;
1174
1175
1176 fix = &info->fix;
1177 var = &info->var;
1178
1179 fb->sti = sti;
1180 dev_name = sti->sti_data->inq_outptr.dev_name;
1181
1182 fb->id = fb->sti->graphics_id[0];
1183
1184
1185 switch (fb->id) {
1186 case CRT_ID_VISUALIZE_EG:
1187
1188
1189
1190
1191
1192
1193
1194 if (strstr(dev_name, "DX")) {
1195 printk(KERN_WARNING
1196"WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
1197"WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
1198 dev_name);
1199 goto out_err0;
1200 }
1201 fallthrough;
1202 case S9000_ID_ARTIST:
1203 case S9000_ID_HCRX:
1204 case S9000_ID_TIMBER:
1205 case S9000_ID_A1659A:
1206 case S9000_ID_A1439A:
1207 break;
1208 default:
1209 printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
1210 dev_name, fb->id);
1211 goto out_err0;
1212 }
1213
1214
1215 bpp = 8;
1216 xres = sti_onscreen_x(fb->sti);
1217 yres = sti_onscreen_y(fb->sti);
1218
1219 ngleGetDeviceRomData(fb);
1220
1221
1222 fix->mmio_start = REGION_BASE(fb,2);
1223 fix->mmio_len = 0x400000;
1224
1225
1226 switch (fb->id) {
1227 case S9000_ID_A1659A:
1228 break;
1229 case S9000_ID_ELM:
1230 var->grayscale = 1;
1231 fb->id = S9000_ID_A1659A;
1232 break;
1233 case S9000_ID_TIMBER:
1234 if (strstr(dev_name, "GRAYSCALE") ||
1235 strstr(dev_name, "Grayscale") ||
1236 strstr(dev_name, "grayscale"))
1237 var->grayscale = 1;
1238 break;
1239 case S9000_ID_TOMCAT:
1240
1241
1242
1243
1244 xres = fb->ngle_rom.x_size_visible;
1245 yres = fb->ngle_rom.y_size_visible;
1246 fb->id = S9000_ID_A1659A;
1247 break;
1248 case S9000_ID_A1439A:
1249 bpp = 32;
1250 break;
1251 case S9000_ID_HCRX:
1252 memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
1253 if ((fb->sti->regions_phys[0] & 0xfc000000) ==
1254 (fb->sti->regions_phys[2] & 0xfc000000))
1255 sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
1256 else
1257 sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);
1258
1259 fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
1260 if (IS_24_DEVICE(fb)) {
1261 if (bpp_pref == 8 || bpp_pref == 32)
1262 bpp = bpp_pref;
1263 else
1264 bpp = 32;
1265 } else
1266 bpp = 8;
1267 READ_WORD(fb, REG_15);
1268 SETUP_HW(fb);
1269 break;
1270 case CRT_ID_VISUALIZE_EG:
1271 case S9000_ID_ARTIST:
1272 break;
1273 default:
1274#ifdef FALLBACK_TO_1BPP
1275 printk(KERN_WARNING
1276 "stifb: Unsupported graphics card (id=0x%08x) "
1277 "- now trying 1bpp mode instead\n",
1278 fb->id);
1279 bpp = 1;
1280 break;
1281#else
1282 printk(KERN_WARNING
1283 "stifb: Unsupported graphics card (id=0x%08x) "
1284 "- skipping.\n",
1285 fb->id);
1286 goto out_err0;
1287#endif
1288 }
1289
1290
1291
1292 fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
1293 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
1294
1295 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
1296 if (!fix->line_length)
1297 fix->line_length = 2048;
1298
1299
1300 if (fix->smem_len > yres*fix->line_length)
1301 fix->smem_len = yres*fix->line_length;
1302
1303 fix->accel = FB_ACCEL_NONE;
1304
1305 switch (bpp) {
1306 case 1:
1307 fix->type = FB_TYPE_PLANES;
1308 fix->visual = FB_VISUAL_MONO10;
1309 var->red.length = var->green.length = var->blue.length = 1;
1310 break;
1311 case 8:
1312 fix->type = FB_TYPE_PACKED_PIXELS;
1313 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1314 var->red.length = var->green.length = var->blue.length = 8;
1315 break;
1316 case 32:
1317 fix->type = FB_TYPE_PACKED_PIXELS;
1318 fix->visual = FB_VISUAL_DIRECTCOLOR;
1319 var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
1320 var->blue.offset = 0;
1321 var->green.offset = 8;
1322 var->red.offset = 16;
1323 var->transp.offset = 24;
1324 break;
1325 default:
1326 break;
1327 }
1328
1329 var->xres = var->xres_virtual = xres;
1330 var->yres = var->yres_virtual = yres;
1331 var->bits_per_pixel = bpp;
1332
1333 strcpy(fix->id, "stifb");
1334 info->fbops = &stifb_ops;
1335 info->screen_base = ioremap(REGION_BASE(fb,1), fix->smem_len);
1336 if (!info->screen_base) {
1337 printk(KERN_ERR "stifb: failed to map memory\n");
1338 goto out_err0;
1339 }
1340 info->screen_size = fix->smem_len;
1341 info->flags = FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
1342 info->pseudo_palette = &fb->pseudo_palette;
1343
1344
1345 if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
1346 goto out_err1;
1347 stifb_init_display(fb);
1348
1349 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
1350 printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
1351 fix->smem_start, fix->smem_start+fix->smem_len);
1352 goto out_err2;
1353 }
1354
1355 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
1356 printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
1357 fix->mmio_start, fix->mmio_start+fix->mmio_len);
1358 goto out_err3;
1359 }
1360
1361 if (register_framebuffer(&fb->info) < 0)
1362 goto out_err4;
1363
1364 sti->info = info;
1365
1366 fb_info(&fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
1367 fix->id,
1368 var->xres,
1369 var->yres,
1370 var->bits_per_pixel,
1371 dev_name,
1372 fb->id,
1373 fix->mmio_start);
1374
1375 return 0;
1376
1377
1378out_err4:
1379 release_mem_region(fix->mmio_start, fix->mmio_len);
1380out_err3:
1381 release_mem_region(fix->smem_start, fix->smem_len);
1382out_err2:
1383 fb_dealloc_cmap(&info->cmap);
1384out_err1:
1385 iounmap(info->screen_base);
1386out_err0:
1387 kfree(fb);
1388 return -ENXIO;
1389}
1390
1391static int stifb_disabled __initdata;
1392
1393int __init
1394stifb_setup(char *options);
1395
1396static int __init stifb_init(void)
1397{
1398 struct sti_struct *sti;
1399 struct sti_struct *def_sti;
1400 int i;
1401
1402#ifndef MODULE
1403 char *option = NULL;
1404
1405 if (fb_get_options("stifb", &option))
1406 return -ENODEV;
1407 stifb_setup(option);
1408#endif
1409 if (stifb_disabled) {
1410 printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
1411 return -ENXIO;
1412 }
1413
1414 def_sti = sti_get_rom(0);
1415 if (def_sti) {
1416 for (i = 1; i <= MAX_STI_ROMS; i++) {
1417 sti = sti_get_rom(i);
1418 if (!sti)
1419 break;
1420 if (sti == def_sti) {
1421 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1422 break;
1423 }
1424 }
1425 }
1426
1427 for (i = 1; i <= MAX_STI_ROMS; i++) {
1428 sti = sti_get_rom(i);
1429 if (!sti)
1430 break;
1431 if (sti == def_sti)
1432 continue;
1433 stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
1434 }
1435 return 0;
1436}
1437
1438
1439
1440
1441
1442static void __exit
1443stifb_cleanup(void)
1444{
1445 struct sti_struct *sti;
1446 int i;
1447
1448 for (i = 1; i <= MAX_STI_ROMS; i++) {
1449 sti = sti_get_rom(i);
1450 if (!sti)
1451 break;
1452 if (sti->info) {
1453 struct fb_info *info = sti->info;
1454 unregister_framebuffer(sti->info);
1455 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1456 release_mem_region(info->fix.smem_start, info->fix.smem_len);
1457 if (info->screen_base)
1458 iounmap(info->screen_base);
1459 fb_dealloc_cmap(&info->cmap);
1460 framebuffer_release(info);
1461 }
1462 sti->info = NULL;
1463 }
1464}
1465
1466int __init
1467stifb_setup(char *options)
1468{
1469 int i;
1470
1471 if (!options || !*options)
1472 return 1;
1473
1474 if (strncmp(options, "off", 3) == 0) {
1475 stifb_disabled = 1;
1476 options += 3;
1477 }
1478
1479 if (strncmp(options, "bpp", 3) == 0) {
1480 options += 3;
1481 for (i = 0; i < MAX_STI_ROMS; i++) {
1482 if (*options++ != ':')
1483 break;
1484 stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
1485 }
1486 }
1487 return 1;
1488}
1489
1490__setup("stifb=", stifb_setup);
1491
1492module_init(stifb_init);
1493module_exit(stifb_cleanup);
1494
1495MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1496MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1497MODULE_LICENSE("GPL v2");
1498