0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 #undef FALLBACK_TO_1BPP
0053
0054 #undef DEBUG_STIFB_REGS
0055
0056
0057 #include <linux/module.h>
0058 #include <linux/kernel.h>
0059 #include <linux/errno.h>
0060 #include <linux/string.h>
0061 #include <linux/mm.h>
0062 #include <linux/slab.h>
0063 #include <linux/delay.h>
0064 #include <linux/fb.h>
0065 #include <linux/init.h>
0066 #include <linux/ioport.h>
0067 #include <linux/io.h>
0068
0069 #include <asm/grfioctl.h> /* for HP-UX compatibility */
0070 #include <linux/uaccess.h>
0071
0072 #include "sticore.h"
0073
0074
0075 #define REGION_BASE(fb_info, index) \
0076 F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index])
0077
0078 #define NGLEDEVDEPROM_CRT_REGION 1
0079
0080 #define NR_PALETTE 256
0081
0082 typedef struct {
0083 __s32 video_config_reg;
0084 __s32 misc_video_start;
0085 __s32 horiz_timing_fmt;
0086 __s32 serr_timing_fmt;
0087 __s32 vert_timing_fmt;
0088 __s32 horiz_state;
0089 __s32 vert_state;
0090 __s32 vtg_state_elements;
0091 __s32 pipeline_delay;
0092 __s32 misc_video_end;
0093 } video_setup_t;
0094
0095 typedef struct {
0096 __s16 sizeof_ngle_data;
0097 __s16 x_size_visible;
0098 __s16 y_size_visible;
0099 __s16 pad2[15];
0100 __s16 cursor_pipeline_delay;
0101 __s16 video_interleaves;
0102 __s32 pad3[11];
0103 } ngle_rom_t;
0104
0105 struct stifb_info {
0106 struct fb_info info;
0107 unsigned int id;
0108 ngle_rom_t ngle_rom;
0109 struct sti_struct *sti;
0110 int deviceSpecificConfig;
0111 u32 pseudo_palette[16];
0112 };
0113
0114 static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
0115
0116
0117
0118
0119
0120 #define REG_1 0x000118
0121 #define REG_2 0x000480
0122 #define REG_3 0x0004a0
0123 #define REG_4 0x000600
0124 #define REG_6 0x000800
0125 #define REG_7 0x000804
0126 #define REG_8 0x000820
0127 #define REG_9 0x000a04
0128 #define REG_10 0x018000
0129 #define REG_11 0x018004
0130 #define REG_12 0x01800c
0131 #define REG_13 0x018018
0132 #define REG_14 0x01801c
0133 #define REG_15 0x200000
0134 #define REG_15b0 0x200000
0135 #define REG_16b1 0x200005
0136 #define REG_16b3 0x200007
0137 #define REG_21 0x200218
0138 #define REG_22 0x0005a0
0139 #define REG_23 0x0005c0
0140 #define REG_24 0x000808
0141 #define REG_25 0x000b00
0142 #define REG_26 0x200118
0143 #define REG_27 0x200308
0144 #define REG_32 0x21003c
0145 #define REG_33 0x210040
0146 #define REG_34 0x200008
0147 #define REG_35 0x018010
0148 #define REG_38 0x210020
0149 #define REG_39 0x210120
0150 #define REG_40 0x210130
0151 #define REG_42 0x210028
0152 #define REG_43 0x21002c
0153 #define REG_44 0x210030
0154 #define REG_45 0x210034
0155
0156 #define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg))
0157 #define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg))
0158
0159
0160 #ifndef DEBUG_STIFB_REGS
0161 # define DEBUG_OFF()
0162 # define DEBUG_ON()
0163 # define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
0164 # define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
0165 #else
0166 static int debug_on = 1;
0167 # define DEBUG_OFF() debug_on=0
0168 # define DEBUG_ON() debug_on=1
0169 # define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
0170 printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
0171 __func__, reg, value, READ_BYTE(fb,reg)); \
0172 gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
0173 # define WRITE_WORD(value,fb,reg) do { if (debug_on) \
0174 printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
0175 __func__, reg, value, READ_WORD(fb,reg)); \
0176 gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
0177 #endif
0178
0179
0180 #define ENABLE 1
0181 #define DISABLE 0
0182
0183 #define NGLE_LOCK(fb_info) do { } while (0)
0184 #define NGLE_UNLOCK(fb_info) do { } while (0)
0185
0186 static void
0187 SETUP_HW(struct stifb_info *fb)
0188 {
0189 char stat;
0190
0191 do {
0192 stat = READ_BYTE(fb, REG_15b0);
0193 if (!stat)
0194 stat = READ_BYTE(fb, REG_15b0);
0195 } while (stat);
0196 }
0197
0198
0199 static void
0200 SETUP_FB(struct stifb_info *fb)
0201 {
0202 unsigned int reg10_value = 0;
0203
0204 SETUP_HW(fb);
0205 switch (fb->id)
0206 {
0207 case CRT_ID_VISUALIZE_EG:
0208 case S9000_ID_ARTIST:
0209 case S9000_ID_A1659A:
0210 reg10_value = 0x13601000;
0211 break;
0212 case S9000_ID_A1439A:
0213 if (fb->info.var.bits_per_pixel == 32)
0214 reg10_value = 0xBBA0A000;
0215 else
0216 reg10_value = 0x13601000;
0217 break;
0218 case S9000_ID_HCRX:
0219 if (fb->info.var.bits_per_pixel == 32)
0220 reg10_value = 0xBBA0A000;
0221 else
0222 reg10_value = 0x13602000;
0223 break;
0224 case S9000_ID_TIMBER:
0225 case CRX24_OVERLAY_PLANES:
0226 reg10_value = 0x13602000;
0227 break;
0228 }
0229 if (reg10_value)
0230 WRITE_WORD(reg10_value, fb, REG_10);
0231 WRITE_WORD(0x83000300, fb, REG_14);
0232 SETUP_HW(fb);
0233 WRITE_BYTE(1, fb, REG_16b1);
0234 }
0235
0236 static void
0237 START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
0238 {
0239 SETUP_HW(fb);
0240 WRITE_WORD(0xBBE0F000, fb, REG_10);
0241 WRITE_WORD(0x03000300, fb, REG_14);
0242 WRITE_WORD(~0, fb, REG_13);
0243 }
0244
0245 static void
0246 WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
0247 {
0248 SETUP_HW(fb);
0249 WRITE_WORD(((0x100+index)<<2), fb, REG_3);
0250 WRITE_WORD(color, fb, REG_4);
0251 }
0252
0253 static void
0254 FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
0255 {
0256 WRITE_WORD(0x400, fb, REG_2);
0257 if (fb->info.var.bits_per_pixel == 32) {
0258 WRITE_WORD(0x83000100, fb, REG_1);
0259 } else {
0260 if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
0261 WRITE_WORD(0x80000100, fb, REG_26);
0262 else
0263 WRITE_WORD(0x80000100, fb, REG_1);
0264 }
0265 SETUP_FB(fb);
0266 }
0267
0268 static void
0269 SETUP_RAMDAC(struct stifb_info *fb)
0270 {
0271 SETUP_HW(fb);
0272 WRITE_WORD(0x04000000, fb, 0x1020);
0273 WRITE_WORD(0xff000000, fb, 0x1028);
0274 }
0275
0276 static void
0277 CRX24_SETUP_RAMDAC(struct stifb_info *fb)
0278 {
0279 SETUP_HW(fb);
0280 WRITE_WORD(0x04000000, fb, 0x1000);
0281 WRITE_WORD(0x02000000, fb, 0x1004);
0282 WRITE_WORD(0xff000000, fb, 0x1008);
0283 WRITE_WORD(0x05000000, fb, 0x1000);
0284 WRITE_WORD(0x02000000, fb, 0x1004);
0285 WRITE_WORD(0x03000000, fb, 0x1008);
0286 }
0287
0288 #if 0
0289 static void
0290 HCRX_SETUP_RAMDAC(struct stifb_info *fb)
0291 {
0292 WRITE_WORD(0xffffffff, fb, REG_32);
0293 }
0294 #endif
0295
0296 static void
0297 CRX24_SET_OVLY_MASK(struct stifb_info *fb)
0298 {
0299 SETUP_HW(fb);
0300 WRITE_WORD(0x13a02000, fb, REG_11);
0301 WRITE_WORD(0x03000300, fb, REG_14);
0302 WRITE_WORD(0x000017f0, fb, REG_3);
0303 WRITE_WORD(0xffffffff, fb, REG_13);
0304 WRITE_WORD(0xffffffff, fb, REG_22);
0305 WRITE_WORD(0x00000000, fb, REG_23);
0306 }
0307
0308 static void
0309 ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
0310 {
0311 unsigned int value = enable ? 0x43000000 : 0x03000000;
0312 SETUP_HW(fb);
0313 WRITE_WORD(0x06000000, fb, 0x1030);
0314 WRITE_WORD(value, fb, 0x1038);
0315 }
0316
0317 static void
0318 CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
0319 {
0320 unsigned int value = enable ? 0x10000000 : 0x30000000;
0321 SETUP_HW(fb);
0322 WRITE_WORD(0x01000000, fb, 0x1000);
0323 WRITE_WORD(0x02000000, fb, 0x1004);
0324 WRITE_WORD(value, fb, 0x1008);
0325 }
0326
0327 static void
0328 ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
0329 {
0330 u32 DregsMiscVideo = REG_21;
0331 u32 DregsMiscCtl = REG_27;
0332
0333 SETUP_HW(fb);
0334 if (enable) {
0335 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
0336 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl);
0337 } else {
0338 WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
0339 WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl);
0340 }
0341 }
0342
0343 #define GET_ROMTABLE_INDEX(fb) \
0344 (READ_BYTE(fb, REG_16b3) - 1)
0345
0346 #define HYPER_CONFIG_PLANES_24 0x00000100
0347
0348 #define IS_24_DEVICE(fb) \
0349 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
0350
0351 #define IS_888_DEVICE(fb) \
0352 (!(IS_24_DEVICE(fb)))
0353
0354 #define GET_FIFO_SLOTS(fb, cnt, numslots) \
0355 { while (cnt < numslots) \
0356 cnt = READ_WORD(fb, REG_34); \
0357 cnt -= numslots; \
0358 }
0359
0360 #define IndexedDcd 0
0361 #define Otc04 2
0362 #define Otc32 5
0363 #define Ots08 3
0364 #define OtsIndirect 6
0365 #define AddrLong 5
0366 #define BINovly 0x2
0367 #define BINapp0I 0x0
0368 #define BINapp1I 0x1
0369 #define BINapp0F8 0xa
0370 #define BINattr 0xd
0371 #define RopSrc 0x3
0372 #define BitmapExtent08 3
0373 #define BitmapExtent32 5
0374 #define DataDynamic 0
0375 #define MaskDynamic 1
0376 #define MaskOtc 0
0377
0378 #define MaskAddrOffset(offset) (offset)
0379 #define StaticReg(en) (en)
0380 #define BGx(en) (en)
0381 #define FGx(en) (en)
0382
0383 #define BAJustPoint(offset) (offset)
0384 #define BAIndexBase(base) (base)
0385 #define BA(F,C,S,A,J,B,I) \
0386 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
0387
0388 #define IBOvals(R,M,X,S,D,L,B,F) \
0389 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
0390
0391 #define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
0392 WRITE_WORD(val, fb, REG_14)
0393
0394 #define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
0395 WRITE_WORD(val, fb, REG_11)
0396
0397 #define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
0398 WRITE_WORD(val, fb, REG_12)
0399
0400 #define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
0401 WRITE_WORD(plnmsk32, fb, REG_13)
0402
0403 #define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
0404 WRITE_WORD(fg32, fb, REG_35)
0405
0406 #define NGLE_SET_TRANSFERDATA(fb, val) \
0407 WRITE_WORD(val, fb, REG_8)
0408
0409 #define NGLE_SET_DSTXY(fb, val) \
0410 WRITE_WORD(val, fb, REG_6)
0411
0412 #define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
0413 (u32) (fbaddrbase) + \
0414 ( (unsigned int) ( (y) << 13 ) | \
0415 (unsigned int) ( (x) << 2 ) ) \
0416 )
0417
0418 #define NGLE_BINC_SET_DSTADDR(fb, addr) \
0419 WRITE_WORD(addr, fb, REG_3)
0420
0421 #define NGLE_BINC_SET_SRCADDR(fb, addr) \
0422 WRITE_WORD(addr, fb, REG_2)
0423
0424 #define NGLE_BINC_SET_DSTMASK(fb, mask) \
0425 WRITE_WORD(mask, fb, REG_22)
0426
0427 #define NGLE_BINC_WRITE32(fb, data32) \
0428 WRITE_WORD(data32, fb, REG_23)
0429
0430 #define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
0431 WRITE_WORD((cmapBltCtlData32), fb, REG_38)
0432
0433 #define SET_LENXY_START_RECFILL(fb, lenxy) \
0434 WRITE_WORD(lenxy, fb, REG_9)
0435
0436 #define SETUP_COPYAREA(fb) \
0437 WRITE_BYTE(0, fb, REG_16b1)
0438
0439 static void
0440 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
0441 {
0442 u32 DregsHypMiscVideo = REG_33;
0443 unsigned int value;
0444 SETUP_HW(fb);
0445 value = READ_WORD(fb, DregsHypMiscVideo);
0446 if (enable)
0447 value |= 0x0A000000;
0448 else
0449 value &= ~0x0A000000;
0450 WRITE_WORD(value, fb, DregsHypMiscVideo);
0451 }
0452
0453
0454
0455 #define BUFF0_CMAP0 0x00001e02
0456 #define BUFF1_CMAP0 0x02001e02
0457 #define BUFF1_CMAP3 0x0c001e02
0458 #define ARTIST_CMAP0 0x00000102
0459 #define HYPER_CMAP8 0x00000100
0460 #define HYPER_CMAP24 0x00000800
0461
0462 static void
0463 SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
0464 {
0465 SETUP_HW(fb);
0466 WRITE_WORD(0x2EA0D000, fb, REG_11);
0467 WRITE_WORD(0x23000302, fb, REG_14);
0468 WRITE_WORD(BufferNumber, fb, REG_12);
0469 WRITE_WORD(0xffffffff, fb, REG_8);
0470 }
0471
0472 static void
0473 SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
0474 {
0475
0476
0477
0478
0479
0480
0481
0482 WRITE_WORD(0x00000000, fb, REG_6);
0483 WRITE_WORD((width<<16) | height, fb, REG_9);
0484 WRITE_WORD(0x05000000, fb, REG_6);
0485 WRITE_WORD(0x00040001, fb, REG_9);
0486 }
0487
0488 static void
0489 FINISH_ATTR_ACCESS(struct stifb_info *fb)
0490 {
0491 SETUP_HW(fb);
0492 WRITE_WORD(0x00000000, fb, REG_12);
0493 }
0494
0495 static void
0496 elkSetupPlanes(struct stifb_info *fb)
0497 {
0498 SETUP_RAMDAC(fb);
0499 SETUP_FB(fb);
0500 }
0501
0502 static void
0503 ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
0504 {
0505 SETUP_ATTR_ACCESS(fb, BufferNumber);
0506 SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
0507 FINISH_ATTR_ACCESS(fb);
0508 SETUP_FB(fb);
0509 }
0510
0511
0512 static void
0513 rattlerSetupPlanes(struct stifb_info *fb)
0514 {
0515 int saved_id, y;
0516
0517
0518
0519
0520
0521 CRX24_SETUP_RAMDAC(fb);
0522
0523
0524 saved_id = fb->id;
0525 fb->id = CRX24_OVERLAY_PLANES;
0526 SETUP_FB(fb);
0527 fb->id = saved_id;
0528
0529 for (y = 0; y < fb->info.var.yres; ++y)
0530 fb_memset(fb->info.screen_base + y * fb->info.fix.line_length,
0531 0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8);
0532
0533 CRX24_SET_OVLY_MASK(fb);
0534 SETUP_FB(fb);
0535 }
0536
0537
0538 #define HYPER_CMAP_TYPE 0
0539 #define NGLE_CMAP_INDEXED0_TYPE 0
0540 #define NGLE_CMAP_OVERLAY_TYPE 3
0541
0542
0543 typedef union
0544 { u32 all;
0545 struct
0546 {
0547 unsigned enable : 1;
0548 unsigned waitBlank : 1;
0549 unsigned reserved1 : 4;
0550 unsigned lutOffset : 10;
0551 unsigned lutType : 2;
0552 unsigned reserved2 : 4;
0553 unsigned length : 10;
0554 } fields;
0555 } NgleLutBltCtl;
0556
0557
0558 #if 0
0559 static NgleLutBltCtl
0560 setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
0561 {
0562 NgleLutBltCtl lutBltCtl;
0563
0564
0565 lutBltCtl.all = 0x80000000;
0566 lutBltCtl.fields.length = length;
0567
0568 switch (fb->id)
0569 {
0570 case S9000_ID_A1439A:
0571 if (fb->var.bits_per_pixel == 8) {
0572 lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
0573 lutBltCtl.fields.lutOffset = 0;
0574 } else {
0575 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
0576 lutBltCtl.fields.lutOffset = 0 * 256;
0577 }
0578 break;
0579
0580 case S9000_ID_ARTIST:
0581 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
0582 lutBltCtl.fields.lutOffset = 0 * 256;
0583 break;
0584
0585 default:
0586 lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
0587 lutBltCtl.fields.lutOffset = 0;
0588 break;
0589 }
0590
0591
0592 lutBltCtl.fields.lutOffset += offsetWithinLut;
0593
0594 return lutBltCtl;
0595 }
0596 #endif
0597
0598 static NgleLutBltCtl
0599 setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
0600 {
0601 NgleLutBltCtl lutBltCtl;
0602
0603
0604 lutBltCtl.all = 0x80000000;
0605
0606 lutBltCtl.fields.length = length;
0607 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
0608
0609
0610 if (fb->info.var.bits_per_pixel == 8)
0611 lutBltCtl.fields.lutOffset = 2 * 256;
0612 else
0613 lutBltCtl.fields.lutOffset = 0 * 256;
0614
0615
0616 lutBltCtl.fields.lutOffset += offsetWithinLut;
0617
0618 return lutBltCtl;
0619 }
0620
0621
0622 static void hyperUndoITE(struct stifb_info *fb)
0623 {
0624 int nFreeFifoSlots = 0;
0625 u32 fbAddr;
0626
0627 NGLE_LOCK(fb);
0628
0629 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
0630 WRITE_WORD(0xffffffff, fb, REG_32);
0631
0632
0633
0634
0635 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
0636 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
0637 BA(IndexedDcd, Otc04, Ots08, AddrLong,
0638 BAJustPoint(0), BINovly, BAIndexBase(0)));
0639 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
0640 IBOvals(RopSrc, MaskAddrOffset(0),
0641 BitmapExtent08, StaticReg(0),
0642 DataDynamic, MaskOtc, BGx(0), FGx(0)));
0643
0644
0645 fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
0646 NGLE_BINC_SET_DSTADDR(fb, fbAddr);
0647 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
0648 NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
0649
0650
0651 NGLE_BINC_WRITE32(fb, 0);
0652
0653 NGLE_UNLOCK(fb);
0654 }
0655
0656 static void
0657 ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
0658 {
0659
0660 }
0661
0662 static void
0663 ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
0664 {
0665
0666 }
0667
0668 static void
0669 ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
0670 {
0671 int nFreeFifoSlots = 0;
0672 u32 packed_dst;
0673 u32 packed_len;
0674
0675 NGLE_LOCK(fb);
0676
0677 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
0678 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
0679 BA(IndexedDcd, Otc32, OtsIndirect,
0680 AddrLong, BAJustPoint(0),
0681 BINattr, BAIndexBase(0)));
0682 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
0683 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
0684
0685 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
0686 IBOvals(RopSrc, MaskAddrOffset(0),
0687 BitmapExtent08, StaticReg(1),
0688 DataDynamic, MaskOtc,
0689 BGx(0), FGx(0)));
0690 packed_dst = 0;
0691 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
0692 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
0693 NGLE_SET_DSTXY(fb, packed_dst);
0694 SET_LENXY_START_RECFILL(fb, packed_len);
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704 if (fb->id == S9000_ID_A1659A) {
0705
0706 packed_dst = (1280 << 16);
0707 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
0708 NGLE_SET_DSTXY(fb, packed_dst);
0709 packed_len = (4 << 16) | 1;
0710 SET_LENXY_START_RECFILL(fb, packed_len);
0711 }
0712
0713
0714 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
0715 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
0716
0717 NGLE_UNLOCK(fb);
0718 }
0719
0720 static void
0721 ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
0722 {
0723 int nFreeFifoSlots = 0;
0724 u32 packed_dst;
0725 u32 packed_len;
0726
0727 NGLE_LOCK(fb);
0728
0729
0730 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
0731 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
0732 BA(IndexedDcd, Otc04, Ots08, AddrLong,
0733 BAJustPoint(0), BINovly, BAIndexBase(0)));
0734
0735 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
0736
0737 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
0738 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
0739
0740 packed_dst = 0;
0741 packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
0742 NGLE_SET_DSTXY(fb, packed_dst);
0743
0744
0745 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
0746 IBOvals(RopSrc, MaskAddrOffset(0),
0747 BitmapExtent08, StaticReg(0),
0748 DataDynamic, MaskOtc, BGx(0), FGx(0)));
0749
0750 SET_LENXY_START_RECFILL(fb, packed_len);
0751
0752 NGLE_UNLOCK(fb);
0753 }
0754
0755 static void
0756 hyperResetPlanes(struct stifb_info *fb, int enable)
0757 {
0758 unsigned int controlPlaneReg;
0759
0760 NGLE_LOCK(fb);
0761
0762 if (IS_24_DEVICE(fb))
0763 if (fb->info.var.bits_per_pixel == 32)
0764 controlPlaneReg = 0x04000F00;
0765 else
0766 controlPlaneReg = 0x00000F00;
0767 else
0768 controlPlaneReg = 0x00000F00;
0769
0770 switch (enable) {
0771 case ENABLE:
0772
0773 if (IS_24_DEVICE(fb))
0774 ngleDepth24_ClearImagePlanes(fb);
0775 else
0776 ngleDepth8_ClearImagePlanes(fb);
0777
0778
0779
0780 ngleResetAttrPlanes(fb, controlPlaneReg);
0781
0782
0783 ngleClearOverlayPlanes(fb, 0xff, 255);
0784
0785
0786
0787
0788 hyperUndoITE(fb);
0789 break;
0790
0791 case DISABLE:
0792
0793 if (IS_24_DEVICE(fb))
0794 ngleDepth24_ClearImagePlanes(fb);
0795 else
0796 ngleDepth8_ClearImagePlanes(fb);
0797 ngleResetAttrPlanes(fb, controlPlaneReg);
0798 ngleClearOverlayPlanes(fb, 0xff, 0);
0799 break;
0800
0801 case -1:
0802 hyperUndoITE(fb);
0803 ngleResetAttrPlanes(fb, controlPlaneReg);
0804 break;
0805 }
0806
0807 NGLE_UNLOCK(fb);
0808 }
0809
0810
0811
0812 static void
0813 ngleGetDeviceRomData(struct stifb_info *fb)
0814 {
0815 #if 0
0816 XXX: FIXME: !!!
0817 int *pBytePerLongDevDepData;
0818 int *pRomTable;
0819 NgleDevRomData *pPackedDevRomData;
0820 int sizePackedDevRomData = sizeof(*pPackedDevRomData);
0821 char *pCard8;
0822 int i;
0823 char *mapOrigin = NULL;
0824
0825 int romTableIdx;
0826
0827 pPackedDevRomData = fb->ngle_rom;
0828
0829 SETUP_HW(fb);
0830 if (fb->id == S9000_ID_ARTIST) {
0831 pPackedDevRomData->cursor_pipeline_delay = 4;
0832 pPackedDevRomData->video_interleaves = 4;
0833 } else {
0834
0835 pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
0836
0837
0838 if (fb->id == S9000_ID_TOMCAT)
0839 {
0840
0841 GET_ROMTABLE_INDEX(romTableIdx);
0842 while (romTableIdx > 0)
0843 {
0844 pCard8 = (Card8 *) pPackedDevRomData;
0845 pRomTable = pBytePerLongDevDepData;
0846
0847 for (i = 0; i < sizePackedDevRomData; i++)
0848 {
0849 *pCard8++ = (Card8) (*pRomTable++);
0850 }
0851
0852 pBytePerLongDevDepData = (Card32 *)
0853 ((Card8 *) pBytePerLongDevDepData +
0854 pPackedDevRomData->sizeof_ngle_data);
0855
0856 romTableIdx--;
0857 }
0858 }
0859
0860 pCard8 = (Card8 *) pPackedDevRomData;
0861
0862
0863 for (i = 0; i < sizePackedDevRomData; i++)
0864 {
0865 *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
0866 }
0867 }
0868
0869 SETUP_FB(fb);
0870 #endif
0871 }
0872
0873
0874 #define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
0875 #define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8
0876 #define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10
0877 #define HYPERBOWL_MODE2_8_24 15
0878
0879
0880 static void __init
0881 SETUP_HCRX(struct stifb_info *fb)
0882 {
0883 int hyperbowl;
0884 int nFreeFifoSlots = 0;
0885
0886 if (fb->id != S9000_ID_HCRX)
0887 return;
0888
0889
0890 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
0891
0892 if (IS_24_DEVICE(fb)) {
0893 hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
0894 HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
0895 HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
0896
0897
0898 WRITE_WORD(hyperbowl, fb, REG_40);
0899 WRITE_WORD(hyperbowl, fb, REG_40);
0900
0901 WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
0902
0903 WRITE_WORD(0x014c0148, fb, REG_42);
0904 WRITE_WORD(0x404c4048, fb, REG_43);
0905 WRITE_WORD(0x034c0348, fb, REG_44);
0906 WRITE_WORD(0x444c4448, fb, REG_45);
0907 } else {
0908 hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
0909
0910
0911 WRITE_WORD(hyperbowl, fb, REG_40);
0912 WRITE_WORD(hyperbowl, fb, REG_40);
0913
0914 WRITE_WORD(0x00000000, fb, REG_42);
0915 WRITE_WORD(0x00000000, fb, REG_43);
0916 WRITE_WORD(0x00000000, fb, REG_44);
0917 WRITE_WORD(0x444c4048, fb, REG_45);
0918 }
0919 }
0920
0921
0922
0923
0924 static int
0925 stifb_setcolreg(u_int regno, u_int red, u_int green,
0926 u_int blue, u_int transp, struct fb_info *info)
0927 {
0928 struct stifb_info *fb = container_of(info, struct stifb_info, info);
0929 u32 color;
0930
0931 if (regno >= NR_PALETTE)
0932 return 1;
0933
0934 red >>= 8;
0935 green >>= 8;
0936 blue >>= 8;
0937
0938 DEBUG_OFF();
0939
0940 START_IMAGE_COLORMAP_ACCESS(fb);
0941
0942 if (unlikely(fb->info.var.grayscale)) {
0943
0944 color = ((red * 77) +
0945 (green * 151) +
0946 (blue * 28)) >> 8;
0947 } else {
0948 color = ((red << 16) |
0949 (green << 8) |
0950 (blue));
0951 }
0952
0953 if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
0954 struct fb_var_screeninfo *var = &fb->info.var;
0955 if (regno < 16)
0956 ((u32 *)fb->info.pseudo_palette)[regno] =
0957 regno << var->red.offset |
0958 regno << var->green.offset |
0959 regno << var->blue.offset;
0960 }
0961
0962 WRITE_IMAGE_COLOR(fb, regno, color);
0963
0964 if (fb->id == S9000_ID_HCRX) {
0965 NgleLutBltCtl lutBltCtl;
0966
0967 lutBltCtl = setHyperLutBltCtl(fb,
0968 0,
0969 256);
0970 NGLE_BINC_SET_SRCADDR(fb,
0971 NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
0972
0973 START_COLORMAPLOAD(fb, lutBltCtl.all);
0974 SETUP_FB(fb);
0975 } else {
0976
0977 FINISH_IMAGE_COLORMAP_ACCESS(fb);
0978 }
0979
0980 DEBUG_ON();
0981
0982 return 0;
0983 }
0984
0985 static int
0986 stifb_blank(int blank_mode, struct fb_info *info)
0987 {
0988 struct stifb_info *fb = container_of(info, struct stifb_info, info);
0989 int enable = (blank_mode == 0) ? ENABLE : DISABLE;
0990
0991 switch (fb->id) {
0992 case S9000_ID_A1439A:
0993 CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
0994 break;
0995 case CRT_ID_VISUALIZE_EG:
0996 case S9000_ID_ARTIST:
0997 ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
0998 break;
0999 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
1014 static void
1015 stifb_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
1053 static void
1054 stifb_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
1085 static void __init
1086 stifb_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
1145 static 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
1159 static 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
1362 sti->info = info;
1363 if (register_framebuffer(&fb->info) < 0)
1364 goto out_err4;
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
1378 out_err4:
1379 release_mem_region(fix->mmio_start, fix->mmio_len);
1380 out_err3:
1381 release_mem_region(fix->smem_start, fix->smem_len);
1382 out_err2:
1383 fb_dealloc_cmap(&info->cmap);
1384 out_err1:
1385 iounmap(info->screen_base);
1386 out_err0:
1387 kfree(fb);
1388 return -ENXIO;
1389 }
1390
1391 static int stifb_disabled __initdata;
1392
1393 int __init
1394 stifb_setup(char *options);
1395
1396 static 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
1442 static void __exit
1443 stifb_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
1466 int __init
1467 stifb_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
1492 module_init(stifb_init);
1493 module_exit(stifb_cleanup);
1494
1495 MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
1496 MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
1497 MODULE_LICENSE("GPL v2");