Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  drivers/video/imsttfb.c -- frame buffer device for IMS TwinTurbo
0003  *
0004  *  This file is derived from the powermac console "imstt" driver:
0005  *  Copyright (C) 1997 Sigurdur Asgeirsson
0006  *  With additional hacking by Jeffrey Kuskin (jsk@mojave.stanford.edu)
0007  *  Modified by Danilo Beuche 1998
0008  *  Some register values added by Damien Doligez, INRIA Rocquencourt
0009  *  Various cleanups by Paul Mundt (lethal@chaoticdreams.org)
0010  *
0011  *  This file was written by Ryan Nielsen (ran@krazynet.com)
0012  *  Most of the frame buffer device stuff was copied from atyfb.c
0013  *
0014  *  This file is subject to the terms and conditions of the GNU General Public
0015  *  License. See the file COPYING in the main directory of this archive for
0016  *  more details.
0017  */
0018 
0019 #include <linux/module.h>
0020 #include <linux/kernel.h>
0021 #include <linux/errno.h>
0022 #include <linux/string.h>
0023 #include <linux/mm.h>
0024 #include <linux/vmalloc.h>
0025 #include <linux/delay.h>
0026 #include <linux/interrupt.h>
0027 #include <linux/fb.h>
0028 #include <linux/init.h>
0029 #include <linux/pci.h>
0030 #include <asm/io.h>
0031 #include <linux/uaccess.h>
0032 
0033 #if defined(CONFIG_PPC_PMAC)
0034 #include <linux/nvram.h>
0035 #include "macmodes.h"
0036 #endif
0037 
0038 #ifndef __powerpc__
0039 #define eieio()     /* Enforce In-order Execution of I/O */
0040 #endif
0041 
0042 /* TwinTurbo (Cosmo) registers */
0043 enum {
0044     S1SA    =  0, /* 0x00 */
0045     S2SA    =  1, /* 0x04 */
0046     SP  =  2, /* 0x08 */
0047     DSA =  3, /* 0x0C */
0048     CNT =  4, /* 0x10 */
0049     DP_OCTL =  5, /* 0x14 */
0050     CLR =  6, /* 0x18 */
0051     BI  =  8, /* 0x20 */
0052     MBC =  9, /* 0x24 */
0053     BLTCTL  = 10, /* 0x28 */
0054 
0055     /* Scan Timing Generator Registers */
0056     HES = 12, /* 0x30 */
0057     HEB = 13, /* 0x34 */
0058     HSB = 14, /* 0x38 */
0059     HT  = 15, /* 0x3C */
0060     VES = 16, /* 0x40 */
0061     VEB = 17, /* 0x44 */
0062     VSB = 18, /* 0x48 */
0063     VT  = 19, /* 0x4C */
0064     HCIV    = 20, /* 0x50 */
0065     VCIV    = 21, /* 0x54 */
0066     TCDR    = 22, /* 0x58 */
0067     VIL = 23, /* 0x5C */
0068     STGCTL  = 24, /* 0x60 */
0069 
0070     /* Screen Refresh Generator Registers */
0071     SSR = 25, /* 0x64 */
0072     HRIR    = 26, /* 0x68 */
0073     SPR = 27, /* 0x6C */
0074     CMR = 28, /* 0x70 */
0075     SRGCTL  = 29, /* 0x74 */
0076 
0077     /* RAM Refresh Generator Registers */
0078     RRCIV   = 30, /* 0x78 */
0079     RRSC    = 31, /* 0x7C */
0080     RRCR    = 34, /* 0x88 */
0081 
0082     /* System Registers */
0083     GIOE    = 32, /* 0x80 */
0084     GIO = 33, /* 0x84 */
0085     SCR = 35, /* 0x8C */
0086     SSTATUS = 36, /* 0x90 */
0087     PRC = 37, /* 0x94 */
0088 
0089 #if 0   
0090     /* PCI Registers */
0091     DVID    = 0x00000000L,
0092     SC  = 0x00000004L,
0093     CCR = 0x00000008L,
0094     OG  = 0x0000000CL,
0095     BARM    = 0x00000010L,
0096     BARER   = 0x00000030L,
0097 #endif
0098 };
0099 
0100 /* IBM 624 RAMDAC Direct Registers */
0101 enum {
0102     PADDRW  = 0x00,
0103     PDATA   = 0x04,
0104     PPMASK  = 0x08,
0105     PADDRR  = 0x0c,
0106     PIDXLO  = 0x10, 
0107     PIDXHI  = 0x14, 
0108     PIDXDATA= 0x18,
0109     PIDXCTL = 0x1c
0110 };
0111 
0112 /* IBM 624 RAMDAC Indirect Registers */
0113 enum {
0114     CLKCTL      = 0x02, /* (0x01) Miscellaneous Clock Control */
0115     SYNCCTL     = 0x03, /* (0x00) Sync Control */
0116     HSYNCPOS    = 0x04, /* (0x00) Horizontal Sync Position */
0117     PWRMNGMT    = 0x05, /* (0x00) Power Management */
0118     DACOP       = 0x06, /* (0x02) DAC Operation */
0119     PALETCTL    = 0x07, /* (0x00) Palette Control */
0120     SYSCLKCTL   = 0x08, /* (0x01) System Clock Control */
0121     PIXFMT      = 0x0a, /* () Pixel Format  [bpp >> 3 + 2] */
0122     BPP8        = 0x0b, /* () 8 Bits/Pixel Control */
0123     BPP16       = 0x0c, /* () 16 Bits/Pixel Control  [bit 1=1 for 565] */
0124     BPP24       = 0x0d, /* () 24 Bits/Pixel Control */
0125     BPP32       = 0x0e, /* () 32 Bits/Pixel Control */
0126     PIXCTL1     = 0x10, /* (0x05) Pixel PLL Control 1 */
0127     PIXCTL2     = 0x11, /* (0x00) Pixel PLL Control 2 */
0128     SYSCLKN     = 0x15, /* () System Clock N (System PLL Reference Divider) */
0129     SYSCLKM     = 0x16, /* () System Clock M (System PLL VCO Divider) */
0130     SYSCLKP     = 0x17, /* () System Clock P */
0131     SYSCLKC     = 0x18, /* () System Clock C */
0132     /*
0133      * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
0134      * c is charge pump bias which depends on the VCO frequency  
0135      */
0136     PIXM0       = 0x20, /* () Pixel M 0 */
0137     PIXN0       = 0x21, /* () Pixel N 0 */
0138     PIXP0       = 0x22, /* () Pixel P 0 */
0139     PIXC0       = 0x23, /* () Pixel C 0 */
0140     CURSCTL     = 0x30, /* (0x00) Cursor Control */
0141     CURSXLO     = 0x31, /* () Cursor X position, low 8 bits */
0142     CURSXHI     = 0x32, /* () Cursor X position, high 8 bits */
0143     CURSYLO     = 0x33, /* () Cursor Y position, low 8 bits */
0144     CURSYHI     = 0x34, /* () Cursor Y position, high 8 bits */
0145     CURSHOTX    = 0x35, /* () Cursor Hot Spot X */
0146     CURSHOTY    = 0x36, /* () Cursor Hot Spot Y */
0147     CURSACCTL   = 0x37, /* () Advanced Cursor Control Enable */
0148     CURSACATTR  = 0x38, /* () Advanced Cursor Attribute */
0149     CURS1R      = 0x40, /* () Cursor 1 Red */
0150     CURS1G      = 0x41, /* () Cursor 1 Green */
0151     CURS1B      = 0x42, /* () Cursor 1 Blue */
0152     CURS2R      = 0x43, /* () Cursor 2 Red */
0153     CURS2G      = 0x44, /* () Cursor 2 Green */
0154     CURS2B      = 0x45, /* () Cursor 2 Blue */
0155     CURS3R      = 0x46, /* () Cursor 3 Red */
0156     CURS3G      = 0x47, /* () Cursor 3 Green */
0157     CURS3B      = 0x48, /* () Cursor 3 Blue */
0158     BORDR       = 0x60, /* () Border Color Red */
0159     BORDG       = 0x61, /* () Border Color Green */
0160     BORDB       = 0x62, /* () Border Color Blue */
0161     MISCTL1     = 0x70, /* (0x00) Miscellaneous Control 1 */
0162     MISCTL2     = 0x71, /* (0x00) Miscellaneous Control 2 */
0163     MISCTL3     = 0x72, /* (0x00) Miscellaneous Control 3 */
0164     KEYCTL      = 0x78  /* (0x00) Key Control/DB Operation */
0165 };
0166 
0167 /* TI TVP 3030 RAMDAC Direct Registers */
0168 enum {
0169     TVPADDRW = 0x00,    /* 0  Palette/Cursor RAM Write Address/Index */
0170     TVPPDATA = 0x04,    /* 1  Palette Data RAM Data */
0171     TVPPMASK = 0x08,    /* 2  Pixel Read-Mask */
0172     TVPPADRR = 0x0c,    /* 3  Palette/Cursor RAM Read Address */
0173     TVPCADRW = 0x10,    /* 4  Cursor/Overscan Color Write Address */
0174     TVPCDATA = 0x14,    /* 5  Cursor/Overscan Color Data */
0175                 /* 6  reserved */
0176     TVPCADRR = 0x1c,    /* 7  Cursor/Overscan Color Read Address */
0177                 /* 8  reserved */
0178     TVPDCCTL = 0x24,    /* 9  Direct Cursor Control */
0179     TVPIDATA = 0x28,    /* 10 Index Data */
0180     TVPCRDAT = 0x2c,    /* 11 Cursor RAM Data */
0181     TVPCXPOL = 0x30,    /* 12 Cursor-Position X LSB */
0182     TVPCXPOH = 0x34,    /* 13 Cursor-Position X MSB */
0183     TVPCYPOL = 0x38,    /* 14 Cursor-Position Y LSB */
0184     TVPCYPOH = 0x3c,    /* 15 Cursor-Position Y MSB */
0185 };
0186 
0187 /* TI TVP 3030 RAMDAC Indirect Registers */
0188 enum {
0189     TVPIRREV = 0x01,    /* Silicon Revision [RO] */
0190     TVPIRICC = 0x06,    /* Indirect Cursor Control  (0x00) */
0191     TVPIRBRC = 0x07,    /* Byte Router Control  (0xe4) */
0192     TVPIRLAC = 0x0f,    /* Latch Control        (0x06) */
0193     TVPIRTCC = 0x18,    /* True Color Control   (0x80) */
0194     TVPIRMXC = 0x19,    /* Multiplex Control        (0x98) */
0195     TVPIRCLS = 0x1a,    /* Clock Selection      (0x07) */
0196     TVPIRPPG = 0x1c,    /* Palette Page     (0x00) */
0197     TVPIRGEC = 0x1d,    /* General Control      (0x00) */
0198     TVPIRMIC = 0x1e,    /* Miscellaneous Control    (0x00) */
0199     TVPIRPLA = 0x2c,    /* PLL Address */
0200     TVPIRPPD = 0x2d,    /* Pixel Clock PLL Data */
0201     TVPIRMPD = 0x2e,    /* Memory Clock PLL Data */
0202     TVPIRLPD = 0x2f,    /* Loop Clock PLL Data */
0203     TVPIRCKL = 0x30,    /* Color-Key Overlay Low */
0204     TVPIRCKH = 0x31,    /* Color-Key Overlay High */
0205     TVPIRCRL = 0x32,    /* Color-Key Red Low */
0206     TVPIRCRH = 0x33,    /* Color-Key Red High */
0207     TVPIRCGL = 0x34,    /* Color-Key Green Low */
0208     TVPIRCGH = 0x35,    /* Color-Key Green High */
0209     TVPIRCBL = 0x36,    /* Color-Key Blue Low */
0210     TVPIRCBH = 0x37,    /* Color-Key Blue High */
0211     TVPIRCKC = 0x38,    /* Color-Key Control        (0x00) */
0212     TVPIRMLC = 0x39,    /* MCLK/Loop Clock Control  (0x18) */
0213     TVPIRSEN = 0x3a,    /* Sense Test           (0x00) */
0214     TVPIRTMD = 0x3b,    /* Test Mode Data */
0215     TVPIRRML = 0x3c,    /* CRC Remainder LSB [RO] */
0216     TVPIRRMM = 0x3d,    /* CRC Remainder MSB [RO] */
0217     TVPIRRMS = 0x3e,    /* CRC  Bit Select [WO] */
0218     TVPIRDID = 0x3f,    /* Device ID [RO]       (0x30) */
0219     TVPIRRES = 0xff     /* Software Reset [WO] */
0220 };
0221 
0222 struct initvalues {
0223     __u8 addr, value;
0224 };
0225 
0226 static struct initvalues ibm_initregs[] = {
0227     { CLKCTL,   0x21 },
0228     { SYNCCTL,  0x00 },
0229     { HSYNCPOS, 0x00 },
0230     { PWRMNGMT, 0x00 },
0231     { DACOP,    0x02 },
0232     { PALETCTL, 0x00 },
0233     { SYSCLKCTL,    0x01 },
0234 
0235     /*
0236      * Note that colors in X are correct only if all video data is
0237      * passed through the palette in the DAC.  That is, "indirect
0238      * color" must be configured.  This is the case for the IBM DAC
0239      * used in the 2MB and 4MB cards, at least.
0240      */
0241     { BPP8,     0x00 },
0242     { BPP16,    0x01 },
0243     { BPP24,    0x00 },
0244     { BPP32,    0x00 },
0245 
0246     { PIXCTL1,  0x05 },
0247     { PIXCTL2,  0x00 },
0248     { SYSCLKN,  0x08 },
0249     { SYSCLKM,  0x4f },
0250     { SYSCLKP,  0x00 },
0251     { SYSCLKC,  0x00 },
0252     { CURSCTL,  0x00 },
0253     { CURSACCTL,    0x01 },
0254     { CURSACATTR,   0xa8 },
0255     { CURS1R,   0xff },
0256     { CURS1G,   0xff },
0257     { CURS1B,   0xff },
0258     { CURS2R,   0xff },
0259     { CURS2G,   0xff },
0260     { CURS2B,   0xff },
0261     { CURS3R,   0xff },
0262     { CURS3G,   0xff },
0263     { CURS3B,   0xff },
0264     { BORDR,    0xff },
0265     { BORDG,    0xff },
0266     { BORDB,    0xff },
0267     { MISCTL1,  0x01 },
0268     { MISCTL2,  0x45 },
0269     { MISCTL3,  0x00 },
0270     { KEYCTL,   0x00 }
0271 };
0272 
0273 static struct initvalues tvp_initregs[] = {
0274     { TVPIRICC, 0x00 },
0275     { TVPIRBRC, 0xe4 },
0276     { TVPIRLAC, 0x06 },
0277     { TVPIRTCC, 0x80 },
0278     { TVPIRMXC, 0x4d },
0279     { TVPIRCLS, 0x05 },
0280     { TVPIRPPG, 0x00 },
0281     { TVPIRGEC, 0x00 },
0282     { TVPIRMIC, 0x08 },
0283     { TVPIRCKL, 0xff },
0284     { TVPIRCKH, 0xff },
0285     { TVPIRCRL, 0xff },
0286     { TVPIRCRH, 0xff },
0287     { TVPIRCGL, 0xff },
0288     { TVPIRCGH, 0xff },
0289     { TVPIRCBL, 0xff },
0290     { TVPIRCBH, 0xff },
0291     { TVPIRCKC, 0x00 },
0292     { TVPIRPLA, 0x00 },
0293     { TVPIRPPD, 0xc0 },
0294     { TVPIRPPD, 0xd5 },
0295     { TVPIRPPD, 0xea },
0296     { TVPIRPLA, 0x00 },
0297     { TVPIRMPD, 0xb9 },
0298     { TVPIRMPD, 0x3a },
0299     { TVPIRMPD, 0xb1 },
0300     { TVPIRPLA, 0x00 },
0301     { TVPIRLPD, 0xc1 },
0302     { TVPIRLPD, 0x3d },
0303     { TVPIRLPD, 0xf3 },
0304 };
0305 
0306 struct imstt_regvals {
0307     __u32 pitch;
0308     __u16 hes, heb, hsb, ht, ves, veb, vsb, vt, vil;
0309     __u8 pclk_m, pclk_n, pclk_p;
0310     /* Values of the tvp which change depending on colormode x resolution */
0311     __u8 mlc[3];    /* Memory Loop Config 0x39 */
0312     __u8 lckl_p[3]; /* P value of LCKL PLL */
0313 };
0314 
0315 struct imstt_par {
0316     struct imstt_regvals init;
0317     __u32 __iomem *dc_regs;
0318     unsigned long cmap_regs_phys;
0319     __u8 *cmap_regs;
0320     __u32 ramdac;
0321     __u32 palette[16];
0322 };
0323  
0324 enum {
0325     IBM = 0,
0326     TVP = 1
0327 };
0328 
0329 #define INIT_BPP        8
0330 #define INIT_XRES       640
0331 #define INIT_YRES       480
0332 
0333 static int inverse = 0;
0334 static char fontname[40] __initdata = { 0 };
0335 #if defined(CONFIG_PPC_PMAC)
0336 static signed char init_vmode = -1, init_cmode = -1;
0337 #endif
0338 
0339 static struct imstt_regvals tvp_reg_init_2 = {
0340     512,
0341     0x0002, 0x0006, 0x0026, 0x0028, 0x0003, 0x0016, 0x0196, 0x0197, 0x0196,
0342     0xec, 0x2a, 0xf3,
0343     { 0x3c, 0x3b, 0x39 }, { 0xf3, 0xf3, 0xf3 }
0344 };
0345 
0346 static struct imstt_regvals tvp_reg_init_6 = {
0347     640,
0348     0x0004, 0x0009, 0x0031, 0x0036, 0x0003, 0x002a, 0x020a, 0x020d, 0x020a,
0349     0xef, 0x2e, 0xb2,
0350     { 0x39, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 }
0351 };
0352 
0353 static struct imstt_regvals tvp_reg_init_12 = {
0354     800,
0355     0x0005, 0x000e, 0x0040, 0x0042, 0x0003, 0x018, 0x270, 0x271, 0x270,
0356     0xf6, 0x2e, 0xf2,
0357     { 0x3a, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 }
0358 };
0359 
0360 static struct imstt_regvals tvp_reg_init_13 = {
0361     832,
0362     0x0004, 0x0011, 0x0045, 0x0048, 0x0003, 0x002a, 0x029a, 0x029b, 0x0000,
0363     0xfe, 0x3e, 0xf1,
0364     { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
0365 };
0366 
0367 static struct imstt_regvals tvp_reg_init_17 = {
0368     1024,
0369     0x0006, 0x0210, 0x0250, 0x0053, 0x1003, 0x0021, 0x0321, 0x0324, 0x0000,
0370     0xfc, 0x3a, 0xf1,
0371     { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
0372 };
0373 
0374 static struct imstt_regvals tvp_reg_init_18 = {
0375     1152,
0376     0x0009, 0x0011, 0x059, 0x5b, 0x0003, 0x0031, 0x0397, 0x039a, 0x0000, 
0377     0xfd, 0x3a, 0xf1,
0378     { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
0379 };
0380 
0381 static struct imstt_regvals tvp_reg_init_19 = {
0382     1280,
0383     0x0009, 0x0016, 0x0066, 0x0069, 0x0003, 0x0027, 0x03e7, 0x03e8, 0x03e7,
0384     0xf7, 0x36, 0xf0,
0385     { 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 }
0386 };
0387 
0388 static struct imstt_regvals tvp_reg_init_20 = {
0389     1280,
0390     0x0009, 0x0018, 0x0068, 0x006a, 0x0003, 0x0029, 0x0429, 0x042a, 0x0000,
0391     0xf0, 0x2d, 0xf0,
0392     { 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 }
0393 };
0394 
0395 /*
0396  * PCI driver prototypes
0397  */
0398 static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
0399 static void imsttfb_remove(struct pci_dev *pdev);
0400 
0401 /*
0402  * Register access
0403  */
0404 static inline u32 read_reg_le32(volatile u32 __iomem *base, int regindex)
0405 {
0406 #ifdef __powerpc__
0407     return in_le32(base + regindex);
0408 #else
0409     return readl(base + regindex);
0410 #endif
0411 }
0412 
0413 static inline void write_reg_le32(volatile u32 __iomem *base, int regindex, u32 val)
0414 {
0415 #ifdef __powerpc__
0416     out_le32(base + regindex, val);
0417 #else
0418     writel(val, base + regindex);
0419 #endif
0420 }
0421 
0422 static __u32
0423 getclkMHz(struct imstt_par *par)
0424 {
0425     __u32 clk_m, clk_n, clk_p;
0426 
0427     clk_m = par->init.pclk_m;
0428     clk_n = par->init.pclk_n;
0429     clk_p = par->init.pclk_p;
0430 
0431     return 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1));
0432 }
0433 
0434 static void
0435 setclkMHz(struct imstt_par *par, __u32 MHz)
0436 {
0437     __u32 clk_m, clk_n, x, stage, spilled;
0438 
0439     clk_m = clk_n = 0;
0440     stage = spilled = 0;
0441     for (;;) {
0442         switch (stage) {
0443             case 0:
0444                 clk_m++;
0445                 break;
0446             case 1:
0447                 clk_n++;
0448                 break;
0449         }
0450         x = 20 * (clk_m + 1) / (clk_n + 1);
0451         if (x == MHz)
0452             break;
0453         if (x > MHz) {
0454             spilled = 1;
0455             stage = 1;
0456         } else if (spilled && x < MHz) {
0457             stage = 0;
0458         }
0459     }
0460 
0461     par->init.pclk_m = clk_m;
0462     par->init.pclk_n = clk_n;
0463     par->init.pclk_p = 0;
0464 }
0465 
0466 static struct imstt_regvals *
0467 compute_imstt_regvals_ibm(struct imstt_par *par, int xres, int yres)
0468 {
0469     struct imstt_regvals *init = &par->init;
0470     __u32 MHz, hes, heb, veb, htp, vtp;
0471 
0472     switch (xres) {
0473         case 640:
0474             hes = 0x0008; heb = 0x0012; veb = 0x002a; htp = 10; vtp = 2;
0475             MHz = 30 /* .25 */ ;
0476             break;
0477         case 832:
0478             hes = 0x0005; heb = 0x0020; veb = 0x0028; htp = 8; vtp = 3;
0479             MHz = 57 /* .27_ */ ;
0480             break;
0481         case 1024:
0482             hes = 0x000a; heb = 0x001c; veb = 0x0020; htp = 8; vtp = 3;
0483             MHz = 80;
0484             break;
0485         case 1152:
0486             hes = 0x0012; heb = 0x0022; veb = 0x0031; htp = 4; vtp = 3;
0487             MHz = 101 /* .6_ */ ;
0488             break;
0489         case 1280:
0490             hes = 0x0012; heb = 0x002f; veb = 0x0029; htp = 4; vtp = 1;
0491             MHz = yres == 960 ? 126 : 135;
0492             break;
0493         case 1600:
0494             hes = 0x0018; heb = 0x0040; veb = 0x002a; htp = 4; vtp = 3;
0495             MHz = 200;
0496             break;
0497         default:
0498             return NULL;
0499     }
0500 
0501     setclkMHz(par, MHz);
0502 
0503     init->hes = hes;
0504     init->heb = heb;
0505     init->hsb = init->heb + (xres >> 3);
0506     init->ht = init->hsb + htp;
0507     init->ves = 0x0003;
0508     init->veb = veb;
0509     init->vsb = init->veb + yres;
0510     init->vt = init->vsb + vtp;
0511     init->vil = init->vsb;
0512 
0513     init->pitch = xres;
0514     return init;
0515 }
0516 
0517 static struct imstt_regvals *
0518 compute_imstt_regvals_tvp(struct imstt_par *par, int xres, int yres)
0519 {
0520     struct imstt_regvals *init;
0521 
0522     switch (xres) {
0523         case 512:
0524             init = &tvp_reg_init_2;
0525             break;
0526         case 640:
0527             init = &tvp_reg_init_6;
0528             break;
0529         case 800:
0530             init = &tvp_reg_init_12;
0531             break;
0532         case 832:
0533             init = &tvp_reg_init_13;
0534             break;
0535         case 1024:
0536             init = &tvp_reg_init_17;
0537             break;
0538         case 1152:
0539             init = &tvp_reg_init_18;
0540             break;
0541         case 1280:
0542             init = yres == 960 ? &tvp_reg_init_19 : &tvp_reg_init_20;
0543             break;
0544         default:
0545             return NULL;
0546     }
0547     par->init = *init;
0548     return init;
0549 }
0550 
0551 static struct imstt_regvals *
0552 compute_imstt_regvals (struct imstt_par *par, u_int xres, u_int yres)
0553 {
0554     if (par->ramdac == IBM)
0555         return compute_imstt_regvals_ibm(par, xres, yres);
0556     else
0557         return compute_imstt_regvals_tvp(par, xres, yres);
0558 }
0559 
0560 static void
0561 set_imstt_regvals_ibm (struct imstt_par *par, u_int bpp)
0562 {
0563     struct imstt_regvals *init = &par->init;
0564     __u8 pformat = (bpp >> 3) + 2;
0565 
0566     par->cmap_regs[PIDXHI] = 0;     eieio();
0567     par->cmap_regs[PIDXLO] = PIXM0;     eieio();
0568     par->cmap_regs[PIDXDATA] = init->pclk_m;eieio();
0569     par->cmap_regs[PIDXLO] = PIXN0;     eieio();
0570     par->cmap_regs[PIDXDATA] = init->pclk_n;eieio();
0571     par->cmap_regs[PIDXLO] = PIXP0;     eieio();
0572     par->cmap_regs[PIDXDATA] = init->pclk_p;eieio();
0573     par->cmap_regs[PIDXLO] = PIXC0;     eieio();
0574     par->cmap_regs[PIDXDATA] = 0x02;    eieio();
0575 
0576     par->cmap_regs[PIDXLO] = PIXFMT;    eieio();
0577     par->cmap_regs[PIDXDATA] = pformat; eieio();
0578 }
0579 
0580 static void
0581 set_imstt_regvals_tvp (struct imstt_par *par, u_int bpp)
0582 {
0583     struct imstt_regvals *init = &par->init;
0584     __u8 tcc, mxc, lckl_n, mic;
0585     __u8 mlc, lckl_p;
0586 
0587     switch (bpp) {
0588         default:
0589         case 8:
0590             tcc = 0x80;
0591             mxc = 0x4d;
0592             lckl_n = 0xc1;
0593             mlc = init->mlc[0];
0594             lckl_p = init->lckl_p[0];
0595             break;
0596         case 16:
0597             tcc = 0x44;
0598             mxc = 0x55;
0599             lckl_n = 0xe1;
0600             mlc = init->mlc[1];
0601             lckl_p = init->lckl_p[1];
0602             break;
0603         case 24:
0604             tcc = 0x5e;
0605             mxc = 0x5d;
0606             lckl_n = 0xf1;
0607             mlc = init->mlc[2];
0608             lckl_p = init->lckl_p[2];
0609             break;
0610         case 32:
0611             tcc = 0x46;
0612             mxc = 0x5d;
0613             lckl_n = 0xf1;
0614             mlc = init->mlc[2];
0615             lckl_p = init->lckl_p[2];
0616             break;
0617     }
0618     mic = 0x08;
0619 
0620     par->cmap_regs[TVPADDRW] = TVPIRPLA;        eieio();
0621     par->cmap_regs[TVPIDATA] = 0x00;        eieio();
0622     par->cmap_regs[TVPADDRW] = TVPIRPPD;        eieio();
0623     par->cmap_regs[TVPIDATA] = init->pclk_m;    eieio();
0624     par->cmap_regs[TVPADDRW] = TVPIRPPD;        eieio();
0625     par->cmap_regs[TVPIDATA] = init->pclk_n;    eieio();
0626     par->cmap_regs[TVPADDRW] = TVPIRPPD;        eieio();
0627     par->cmap_regs[TVPIDATA] = init->pclk_p;    eieio();
0628 
0629     par->cmap_regs[TVPADDRW] = TVPIRTCC;        eieio();
0630     par->cmap_regs[TVPIDATA] = tcc;         eieio();
0631     par->cmap_regs[TVPADDRW] = TVPIRMXC;        eieio();
0632     par->cmap_regs[TVPIDATA] = mxc;         eieio();
0633     par->cmap_regs[TVPADDRW] = TVPIRMIC;        eieio();
0634     par->cmap_regs[TVPIDATA] = mic;         eieio();
0635 
0636     par->cmap_regs[TVPADDRW] = TVPIRPLA;        eieio();
0637     par->cmap_regs[TVPIDATA] = 0x00;        eieio();
0638     par->cmap_regs[TVPADDRW] = TVPIRLPD;        eieio();
0639     par->cmap_regs[TVPIDATA] = lckl_n;      eieio();
0640 
0641     par->cmap_regs[TVPADDRW] = TVPIRPLA;        eieio();
0642     par->cmap_regs[TVPIDATA] = 0x15;        eieio();
0643     par->cmap_regs[TVPADDRW] = TVPIRMLC;        eieio();
0644     par->cmap_regs[TVPIDATA] = mlc;         eieio();
0645 
0646     par->cmap_regs[TVPADDRW] = TVPIRPLA;        eieio();
0647     par->cmap_regs[TVPIDATA] = 0x2a;        eieio();
0648     par->cmap_regs[TVPADDRW] = TVPIRLPD;        eieio();
0649     par->cmap_regs[TVPIDATA] = lckl_p;      eieio();
0650 }
0651 
0652 static void
0653 set_imstt_regvals (struct fb_info *info, u_int bpp)
0654 {
0655     struct imstt_par *par = info->par;
0656     struct imstt_regvals *init = &par->init;
0657     __u32 ctl, pitch, byteswap, scr;
0658 
0659     if (par->ramdac == IBM)
0660         set_imstt_regvals_ibm(par, bpp);
0661     else
0662         set_imstt_regvals_tvp(par, bpp);
0663 
0664   /*
0665    * From what I (jsk) can gather poking around with MacsBug,
0666    * bits 8 and 9 in the SCR register control endianness
0667    * correction (byte swapping).  These bits must be set according
0668    * to the color depth as follows:
0669    *     Color depth    Bit 9   Bit 8
0670    *     ==========     =====   =====
0671    *        8bpp          0       0
0672    *       16bpp          0       1
0673    *       32bpp          1       1
0674    */
0675     switch (bpp) {
0676         default:
0677         case 8:
0678             ctl = 0x17b1;
0679             pitch = init->pitch >> 2;
0680             byteswap = 0x000;
0681             break;
0682         case 16:
0683             ctl = 0x17b3;
0684             pitch = init->pitch >> 1;
0685             byteswap = 0x100;
0686             break;
0687         case 24:
0688             ctl = 0x17b9;
0689             pitch = init->pitch - (init->pitch >> 2);
0690             byteswap = 0x200;
0691             break;
0692         case 32:
0693             ctl = 0x17b5;
0694             pitch = init->pitch;
0695             byteswap = 0x300;
0696             break;
0697     }
0698     if (par->ramdac == TVP)
0699         ctl -= 0x30;
0700 
0701     write_reg_le32(par->dc_regs, HES, init->hes);
0702     write_reg_le32(par->dc_regs, HEB, init->heb);
0703     write_reg_le32(par->dc_regs, HSB, init->hsb);
0704     write_reg_le32(par->dc_regs, HT, init->ht);
0705     write_reg_le32(par->dc_regs, VES, init->ves);
0706     write_reg_le32(par->dc_regs, VEB, init->veb);
0707     write_reg_le32(par->dc_regs, VSB, init->vsb);
0708     write_reg_le32(par->dc_regs, VT, init->vt);
0709     write_reg_le32(par->dc_regs, VIL, init->vil);
0710     write_reg_le32(par->dc_regs, HCIV, 1);
0711     write_reg_le32(par->dc_regs, VCIV, 1);
0712     write_reg_le32(par->dc_regs, TCDR, 4);
0713     write_reg_le32(par->dc_regs, RRCIV, 1);
0714     write_reg_le32(par->dc_regs, RRSC, 0x980);
0715     write_reg_le32(par->dc_regs, RRCR, 0x11);
0716 
0717     if (par->ramdac == IBM) {
0718         write_reg_le32(par->dc_regs, HRIR, 0x0100);
0719         write_reg_le32(par->dc_regs, CMR, 0x00ff);
0720         write_reg_le32(par->dc_regs, SRGCTL, 0x0073);
0721     } else {
0722         write_reg_le32(par->dc_regs, HRIR, 0x0200);
0723         write_reg_le32(par->dc_regs, CMR, 0x01ff);
0724         write_reg_le32(par->dc_regs, SRGCTL, 0x0003);
0725     }
0726 
0727     switch (info->fix.smem_len) {
0728         case 0x200000:
0729             scr = 0x059d | byteswap;
0730             break;
0731         /* case 0x400000:
0732            case 0x800000: */
0733         default:
0734             pitch >>= 1;
0735             scr = 0x150dd | byteswap;
0736             break;
0737     }
0738 
0739     write_reg_le32(par->dc_regs, SCR, scr);
0740     write_reg_le32(par->dc_regs, SPR, pitch);
0741     write_reg_le32(par->dc_regs, STGCTL, ctl);
0742 }
0743 
0744 static inline void
0745 set_offset (struct fb_var_screeninfo *var, struct fb_info *info)
0746 {
0747     struct imstt_par *par = info->par;
0748     __u32 off = var->yoffset * (info->fix.line_length >> 3)
0749             + ((var->xoffset * (info->var.bits_per_pixel >> 3)) >> 3);
0750     write_reg_le32(par->dc_regs, SSR, off);
0751 }
0752 
0753 static inline void
0754 set_555 (struct imstt_par *par)
0755 {
0756     if (par->ramdac == IBM) {
0757         par->cmap_regs[PIDXHI] = 0;     eieio();
0758         par->cmap_regs[PIDXLO] = BPP16;     eieio();
0759         par->cmap_regs[PIDXDATA] = 0x01;    eieio();
0760     } else {
0761         par->cmap_regs[TVPADDRW] = TVPIRTCC;    eieio();
0762         par->cmap_regs[TVPIDATA] = 0x44;    eieio();
0763     }
0764 }
0765 
0766 static inline void
0767 set_565 (struct imstt_par *par)
0768 {
0769     if (par->ramdac == IBM) {
0770         par->cmap_regs[PIDXHI] = 0;     eieio();
0771         par->cmap_regs[PIDXLO] = BPP16;     eieio();
0772         par->cmap_regs[PIDXDATA] = 0x03;    eieio();
0773     } else {
0774         par->cmap_regs[TVPADDRW] = TVPIRTCC;    eieio();
0775         par->cmap_regs[TVPIDATA] = 0x45;    eieio();
0776     }
0777 }
0778 
0779 static int
0780 imsttfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
0781 {
0782     if ((var->bits_per_pixel != 8 && var->bits_per_pixel != 16
0783         && var->bits_per_pixel != 24 && var->bits_per_pixel != 32)
0784         || var->xres_virtual < var->xres || var->yres_virtual < var->yres
0785         || var->nonstd
0786         || (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
0787         return -EINVAL;
0788 
0789     if ((var->xres * var->yres) * (var->bits_per_pixel >> 3) > info->fix.smem_len
0790         || (var->xres_virtual * var->yres_virtual) * (var->bits_per_pixel >> 3) > info->fix.smem_len)
0791         return -EINVAL;
0792 
0793     switch (var->bits_per_pixel) {
0794         case 8:
0795             var->red.offset = 0;
0796             var->red.length = 8;
0797             var->green.offset = 0;
0798             var->green.length = 8;
0799             var->blue.offset = 0;
0800             var->blue.length = 8;
0801             var->transp.offset = 0;
0802             var->transp.length = 0;
0803             break;
0804         case 16:    /* RGB 555 or 565 */
0805             if (var->green.length != 6)
0806                 var->red.offset = 10;
0807             var->red.length = 5;
0808             var->green.offset = 5;
0809             if (var->green.length != 6)
0810                 var->green.length = 5;
0811             var->blue.offset = 0;
0812             var->blue.length = 5;
0813             var->transp.offset = 0;
0814             var->transp.length = 0;
0815             break;
0816         case 24:    /* RGB 888 */
0817             var->red.offset = 16;
0818             var->red.length = 8;
0819             var->green.offset = 8;
0820             var->green.length = 8;
0821             var->blue.offset = 0;
0822             var->blue.length = 8;
0823             var->transp.offset = 0;
0824             var->transp.length = 0;
0825             break;
0826         case 32:    /* RGBA 8888 */
0827             var->red.offset = 16;
0828             var->red.length = 8;
0829             var->green.offset = 8;
0830             var->green.length = 8;
0831             var->blue.offset = 0;
0832             var->blue.length = 8;
0833             var->transp.offset = 24;
0834             var->transp.length = 8;
0835             break;
0836     }
0837 
0838     if (var->yres == var->yres_virtual) {
0839         __u32 vram = (info->fix.smem_len - (PAGE_SIZE << 2));
0840         var->yres_virtual = ((vram << 3) / var->bits_per_pixel) / var->xres_virtual;
0841         if (var->yres_virtual < var->yres)
0842             var->yres_virtual = var->yres;
0843     }
0844 
0845     var->red.msb_right = 0;
0846     var->green.msb_right = 0;
0847     var->blue.msb_right = 0;
0848     var->transp.msb_right = 0;
0849     var->height = -1;
0850     var->width = -1;
0851     var->vmode = FB_VMODE_NONINTERLACED;
0852     var->left_margin = var->right_margin = 16;
0853     var->upper_margin = var->lower_margin = 16;
0854     var->hsync_len = var->vsync_len = 8;
0855     return 0;
0856 }
0857 
0858 static int
0859 imsttfb_set_par(struct fb_info *info) 
0860 {
0861     struct imstt_par *par = info->par;
0862         
0863     if (!compute_imstt_regvals(par, info->var.xres, info->var.yres))
0864         return -EINVAL;
0865 
0866     if (info->var.green.length == 6)
0867         set_565(par);
0868     else
0869         set_555(par);
0870     set_imstt_regvals(info, info->var.bits_per_pixel);
0871     info->var.pixclock = 1000000 / getclkMHz(par);
0872     return 0;
0873 }
0874 
0875 static int
0876 imsttfb_setcolreg (u_int regno, u_int red, u_int green, u_int blue,
0877            u_int transp, struct fb_info *info)
0878 {
0879     struct imstt_par *par = info->par;
0880     u_int bpp = info->var.bits_per_pixel;
0881 
0882     if (regno > 255)
0883         return 1;
0884 
0885     red >>= 8;
0886     green >>= 8;
0887     blue >>= 8;
0888 
0889     /* PADDRW/PDATA are the same as TVPPADDRW/TVPPDATA */
0890     if (0 && bpp == 16) /* screws up X */
0891         par->cmap_regs[PADDRW] = regno << 3;
0892     else
0893         par->cmap_regs[PADDRW] = regno;
0894     eieio();
0895 
0896     par->cmap_regs[PDATA] = red;    eieio();
0897     par->cmap_regs[PDATA] = green;  eieio();
0898     par->cmap_regs[PDATA] = blue;   eieio();
0899 
0900     if (regno < 16)
0901         switch (bpp) {
0902             case 16:
0903                 par->palette[regno] =
0904                     (regno << (info->var.green.length ==
0905                     5 ? 10 : 11)) | (regno << 5) | regno;
0906                 break;
0907             case 24:
0908                 par->palette[regno] =
0909                     (regno << 16) | (regno << 8) | regno;
0910                 break;
0911             case 32: {
0912                 int i = (regno << 8) | regno;
0913                 par->palette[regno] = (i << 16) |i;
0914                 break;
0915             }
0916         }
0917     return 0;
0918 }
0919 
0920 static int
0921 imsttfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
0922 {
0923     if (var->xoffset + info->var.xres > info->var.xres_virtual
0924         || var->yoffset + info->var.yres > info->var.yres_virtual)
0925         return -EINVAL;
0926 
0927     info->var.xoffset = var->xoffset;
0928     info->var.yoffset = var->yoffset;
0929     set_offset(var, info);
0930     return 0;
0931 }
0932 
0933 static int 
0934 imsttfb_blank(int blank, struct fb_info *info)
0935 {
0936     struct imstt_par *par = info->par;
0937     __u32 ctrl;
0938 
0939     ctrl = read_reg_le32(par->dc_regs, STGCTL);
0940     if (blank > 0) {
0941         switch (blank) {
0942         case FB_BLANK_NORMAL:
0943         case FB_BLANK_POWERDOWN:
0944             ctrl &= ~0x00000380;
0945             if (par->ramdac == IBM) {
0946                 par->cmap_regs[PIDXHI] = 0;     eieio();
0947                 par->cmap_regs[PIDXLO] = MISCTL2;   eieio();
0948                 par->cmap_regs[PIDXDATA] = 0x55;    eieio();
0949                 par->cmap_regs[PIDXLO] = MISCTL1;   eieio();
0950                 par->cmap_regs[PIDXDATA] = 0x11;    eieio();
0951                 par->cmap_regs[PIDXLO] = SYNCCTL;   eieio();
0952                 par->cmap_regs[PIDXDATA] = 0x0f;    eieio();
0953                 par->cmap_regs[PIDXLO] = PWRMNGMT;  eieio();
0954                 par->cmap_regs[PIDXDATA] = 0x1f;    eieio();
0955                 par->cmap_regs[PIDXLO] = CLKCTL;    eieio();
0956                 par->cmap_regs[PIDXDATA] = 0xc0;
0957             }
0958             break;
0959         case FB_BLANK_VSYNC_SUSPEND:
0960             ctrl &= ~0x00000020;
0961             break;
0962         case FB_BLANK_HSYNC_SUSPEND:
0963             ctrl &= ~0x00000010;
0964             break;
0965         }
0966     } else {
0967         if (par->ramdac == IBM) {
0968             ctrl |= 0x000017b0;
0969             par->cmap_regs[PIDXHI] = 0;     eieio();
0970             par->cmap_regs[PIDXLO] = CLKCTL;    eieio();
0971             par->cmap_regs[PIDXDATA] = 0x01;    eieio();
0972             par->cmap_regs[PIDXLO] = PWRMNGMT;  eieio();
0973             par->cmap_regs[PIDXDATA] = 0x00;    eieio();
0974             par->cmap_regs[PIDXLO] = SYNCCTL;   eieio();
0975             par->cmap_regs[PIDXDATA] = 0x00;    eieio();
0976             par->cmap_regs[PIDXLO] = MISCTL1;   eieio();
0977             par->cmap_regs[PIDXDATA] = 0x01;    eieio();
0978             par->cmap_regs[PIDXLO] = MISCTL2;   eieio();
0979             par->cmap_regs[PIDXDATA] = 0x45;    eieio();
0980         } else
0981             ctrl |= 0x00001780;
0982     }
0983     write_reg_le32(par->dc_regs, STGCTL, ctrl);
0984     return 0;
0985 }
0986 
0987 static void
0988 imsttfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
0989 { 
0990     struct imstt_par *par = info->par;
0991     __u32 Bpp, line_pitch, bgc, dx, dy, width, height;
0992 
0993     bgc = rect->color;
0994     bgc |= (bgc << 8);
0995     bgc |= (bgc << 16);
0996 
0997     Bpp = info->var.bits_per_pixel >> 3,
0998     line_pitch = info->fix.line_length;
0999 
1000     dy = rect->dy * line_pitch;
1001     dx = rect->dx * Bpp;
1002     height = rect->height;
1003     height--;
1004     width = rect->width * Bpp;
1005     width--;
1006 
1007     if (rect->rop == ROP_COPY) {
1008         while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80);
1009         write_reg_le32(par->dc_regs, DSA, dy + dx);
1010         write_reg_le32(par->dc_regs, CNT, (height << 16) | width);
1011         write_reg_le32(par->dc_regs, DP_OCTL, line_pitch);
1012         write_reg_le32(par->dc_regs, BI, 0xffffffff);
1013         write_reg_le32(par->dc_regs, MBC, 0xffffffff);
1014         write_reg_le32(par->dc_regs, CLR, bgc);
1015         write_reg_le32(par->dc_regs, BLTCTL, 0x840); /* 0x200000 */
1016         while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80);
1017         while(read_reg_le32(par->dc_regs, SSTATUS) & 0x40);
1018     } else {
1019         while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80);
1020         write_reg_le32(par->dc_regs, DSA, dy + dx);
1021         write_reg_le32(par->dc_regs, S1SA, dy + dx);
1022         write_reg_le32(par->dc_regs, CNT, (height << 16) | width);
1023         write_reg_le32(par->dc_regs, DP_OCTL, line_pitch);
1024         write_reg_le32(par->dc_regs, SP, line_pitch);
1025         write_reg_le32(par->dc_regs, BLTCTL, 0x40005);
1026         while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80);
1027         while(read_reg_le32(par->dc_regs, SSTATUS) & 0x40);
1028     }
1029 }
1030 
1031 static void
1032 imsttfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1033 {
1034     struct imstt_par *par = info->par;
1035     __u32 Bpp, line_pitch, fb_offset_old, fb_offset_new, sp, dp_octl;
1036     __u32 cnt, bltctl, sx, sy, dx, dy, height, width;
1037 
1038     Bpp = info->var.bits_per_pixel >> 3,
1039 
1040     sx = area->sx * Bpp;
1041     sy = area->sy;
1042     dx = area->dx * Bpp;
1043     dy = area->dy;
1044     height = area->height;
1045     height--;
1046     width = area->width * Bpp;
1047     width--;
1048 
1049     line_pitch = info->fix.line_length;
1050     bltctl = 0x05;
1051     sp = line_pitch << 16;
1052     cnt = height << 16;
1053 
1054     if (sy < dy) {
1055         sy += height;
1056         dy += height;
1057         sp |= -(line_pitch) & 0xffff;
1058         dp_octl = -(line_pitch) & 0xffff;
1059     } else {
1060         sp |= line_pitch;
1061         dp_octl = line_pitch;
1062     }
1063     if (sx < dx) {
1064         sx += width;
1065         dx += width;
1066         bltctl |= 0x80;
1067         cnt |= -(width) & 0xffff;
1068     } else {
1069         cnt |= width;
1070     }
1071     fb_offset_old = sy * line_pitch + sx;
1072     fb_offset_new = dy * line_pitch + dx;
1073 
1074     while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80);
1075     write_reg_le32(par->dc_regs, S1SA, fb_offset_old);
1076     write_reg_le32(par->dc_regs, SP, sp);
1077     write_reg_le32(par->dc_regs, DSA, fb_offset_new);
1078     write_reg_le32(par->dc_regs, CNT, cnt);
1079     write_reg_le32(par->dc_regs, DP_OCTL, dp_octl);
1080     write_reg_le32(par->dc_regs, BLTCTL, bltctl);
1081     while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80);
1082     while(read_reg_le32(par->dc_regs, SSTATUS) & 0x40);
1083 }
1084 
1085 #if 0
1086 static int
1087 imsttfb_load_cursor_image(struct imstt_par *par, int width, int height, __u8 fgc)
1088 {
1089     u_int x, y;
1090 
1091     if (width > 32 || height > 32)
1092         return -EINVAL;
1093 
1094     if (par->ramdac == IBM) {
1095         par->cmap_regs[PIDXHI] = 1; eieio();
1096         for (x = 0; x < 0x100; x++) {
1097             par->cmap_regs[PIDXLO] = x;     eieio();
1098             par->cmap_regs[PIDXDATA] = 0x00;    eieio();
1099         }
1100         par->cmap_regs[PIDXHI] = 1; eieio();
1101         for (y = 0; y < height; y++)
1102             for (x = 0; x < width >> 2; x++) {
1103                 par->cmap_regs[PIDXLO] = x + y * 8; eieio();
1104                 par->cmap_regs[PIDXDATA] = 0xff;    eieio();
1105             }
1106         par->cmap_regs[PIDXHI] = 0;     eieio();
1107         par->cmap_regs[PIDXLO] = CURS1R;    eieio();
1108         par->cmap_regs[PIDXDATA] = fgc;     eieio();
1109         par->cmap_regs[PIDXLO] = CURS1G;    eieio();
1110         par->cmap_regs[PIDXDATA] = fgc;     eieio();
1111         par->cmap_regs[PIDXLO] = CURS1B;    eieio();
1112         par->cmap_regs[PIDXDATA] = fgc;     eieio();
1113         par->cmap_regs[PIDXLO] = CURS2R;    eieio();
1114         par->cmap_regs[PIDXDATA] = fgc;     eieio();
1115         par->cmap_regs[PIDXLO] = CURS2G;    eieio();
1116         par->cmap_regs[PIDXDATA] = fgc;     eieio();
1117         par->cmap_regs[PIDXLO] = CURS2B;    eieio();
1118         par->cmap_regs[PIDXDATA] = fgc;     eieio();
1119         par->cmap_regs[PIDXLO] = CURS3R;    eieio();
1120         par->cmap_regs[PIDXDATA] = fgc;     eieio();
1121         par->cmap_regs[PIDXLO] = CURS3G;    eieio();
1122         par->cmap_regs[PIDXDATA] = fgc;     eieio();
1123         par->cmap_regs[PIDXLO] = CURS3B;    eieio();
1124         par->cmap_regs[PIDXDATA] = fgc;     eieio();
1125     } else {
1126         par->cmap_regs[TVPADDRW] = TVPIRICC;    eieio();
1127         par->cmap_regs[TVPIDATA] &= 0x03;   eieio();
1128         par->cmap_regs[TVPADDRW] = 0;       eieio();
1129         for (x = 0; x < 0x200; x++) {
1130             par->cmap_regs[TVPCRDAT] = 0x00;    eieio();
1131         }
1132         for (x = 0; x < 0x200; x++) {
1133             par->cmap_regs[TVPCRDAT] = 0xff;    eieio();
1134         }
1135         par->cmap_regs[TVPADDRW] = TVPIRICC;    eieio();
1136         par->cmap_regs[TVPIDATA] &= 0x03;   eieio();
1137         for (y = 0; y < height; y++)
1138             for (x = 0; x < width >> 3; x++) {
1139                 par->cmap_regs[TVPADDRW] = x + y * 8;   eieio();
1140                 par->cmap_regs[TVPCRDAT] = 0xff;        eieio();
1141             }
1142         par->cmap_regs[TVPADDRW] = TVPIRICC;    eieio();
1143         par->cmap_regs[TVPIDATA] |= 0x08;   eieio();
1144         for (y = 0; y < height; y++)
1145             for (x = 0; x < width >> 3; x++) {
1146                 par->cmap_regs[TVPADDRW] = x + y * 8;   eieio();
1147                 par->cmap_regs[TVPCRDAT] = 0xff;        eieio();
1148             }
1149         par->cmap_regs[TVPCADRW] = 0x00;    eieio();
1150         for (x = 0; x < 12; x++) {
1151             par->cmap_regs[TVPCDATA] = fgc;
1152             eieio();
1153         }
1154     }
1155     return 1;
1156 }
1157 
1158 static void
1159 imstt_set_cursor(struct imstt_par *par, struct fb_image *d, int on)
1160 {
1161     if (par->ramdac == IBM) {
1162         par->cmap_regs[PIDXHI] = 0; eieio();
1163         if (!on) {
1164             par->cmap_regs[PIDXLO] = CURSCTL;   eieio();
1165             par->cmap_regs[PIDXDATA] = 0x00;    eieio();
1166         } else {
1167             par->cmap_regs[PIDXLO] = CURSXHI;   eieio();
1168             par->cmap_regs[PIDXDATA] = d->dx >> 8;  eieio();
1169             par->cmap_regs[PIDXLO] = CURSXLO;   eieio();
1170             par->cmap_regs[PIDXDATA] = d->dx & 0xff;eieio();
1171             par->cmap_regs[PIDXLO] = CURSYHI;   eieio();
1172             par->cmap_regs[PIDXDATA] = d->dy >> 8;  eieio();
1173             par->cmap_regs[PIDXLO] = CURSYLO;   eieio();
1174             par->cmap_regs[PIDXDATA] = d->dy & 0xff;eieio();
1175             par->cmap_regs[PIDXLO] = CURSCTL;   eieio();
1176             par->cmap_regs[PIDXDATA] = 0x02;    eieio();
1177         }
1178     } else {
1179         if (!on) {
1180             par->cmap_regs[TVPADDRW] = TVPIRICC;    eieio();
1181             par->cmap_regs[TVPIDATA] = 0x00;    eieio();
1182         } else {
1183             __u16 x = d->dx + 0x40, y = d->dy + 0x40;
1184 
1185             par->cmap_regs[TVPCXPOH] = x >> 8;  eieio();
1186             par->cmap_regs[TVPCXPOL] = x & 0xff;    eieio();
1187             par->cmap_regs[TVPCYPOH] = y >> 8;  eieio();
1188             par->cmap_regs[TVPCYPOL] = y & 0xff;    eieio();
1189             par->cmap_regs[TVPADDRW] = TVPIRICC;    eieio();
1190             par->cmap_regs[TVPIDATA] = 0x02;    eieio();
1191         }
1192     }
1193 }
1194 
1195 static int 
1196 imsttfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
1197 {
1198     struct imstt_par *par = info->par;
1199         u32 flags = cursor->set, fg, bg, xx, yy;
1200 
1201     if (cursor->dest == NULL && cursor->rop == ROP_XOR)
1202         return 1;
1203     
1204     imstt_set_cursor(info, cursor, 0);
1205 
1206     if (flags & FB_CUR_SETPOS) {
1207         xx = cursor->image.dx - info->var.xoffset;
1208         yy = cursor->image.dy - info->var.yoffset;
1209     }
1210 
1211     if (flags & FB_CUR_SETSIZE) {
1212         }
1213 
1214         if (flags & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP)) {
1215                 int fg_idx = cursor->image.fg_color;
1216                 int width = (cursor->image.width+7)/8;
1217                 u8 *dat = (u8 *) cursor->image.data;
1218                 u8 *dst = (u8 *) cursor->dest;
1219                 u8 *msk = (u8 *) cursor->mask;
1220 
1221                 switch (cursor->rop) {
1222                 case ROP_XOR:
1223                         for (i = 0; i < cursor->image.height; i++) {
1224                                 for (j = 0; j < width; j++) {
1225                                         d_idx = i * MAX_CURS/8  + j;
1226                                         data[d_idx] =  byte_rev[dat[s_idx] ^
1227                                                                 dst[s_idx]];
1228                                         mask[d_idx] = byte_rev[msk[s_idx]];
1229                                         s_idx++;
1230                                 }
1231                         }
1232                         break;
1233                 case ROP_COPY:
1234                 default:
1235                         for (i = 0; i < cursor->image.height; i++) {
1236                                 for (j = 0; j < width; j++) {
1237                                         d_idx = i * MAX_CURS/8 + j;
1238                                         data[d_idx] = byte_rev[dat[s_idx]];
1239                                         mask[d_idx] = byte_rev[msk[s_idx]];
1240                                         s_idx++;
1241                                 }
1242             }
1243             break;
1244         }
1245 
1246         fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
1247                      ((info->cmap.green[fg_idx] & 0xf8) << 2) |
1248                      ((info->cmap.blue[fg_idx] & 0xf8) >> 3) | 1 << 15;
1249 
1250         imsttfb_load_cursor_image(par, xx, yy, fgc);
1251     }
1252     if (cursor->enable)
1253         imstt_set_cursor(info, cursor, 1);
1254     return 0;
1255 }
1256 #endif
1257 
1258 #define FBIMSTT_SETREG      0x545401
1259 #define FBIMSTT_GETREG      0x545402
1260 #define FBIMSTT_SETCMAPREG  0x545403
1261 #define FBIMSTT_GETCMAPREG  0x545404
1262 #define FBIMSTT_SETIDXREG   0x545405
1263 #define FBIMSTT_GETIDXREG   0x545406
1264 
1265 static int
1266 imsttfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
1267 {
1268     struct imstt_par *par = info->par;
1269     void __user *argp = (void __user *)arg;
1270     __u32 reg[2];
1271     __u8 idx[2];
1272 
1273     switch (cmd) {
1274         case FBIMSTT_SETREG:
1275             if (copy_from_user(reg, argp, 8) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
1276                 return -EFAULT;
1277             write_reg_le32(par->dc_regs, reg[0], reg[1]);
1278             return 0;
1279         case FBIMSTT_GETREG:
1280             if (copy_from_user(reg, argp, 4) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
1281                 return -EFAULT;
1282             reg[1] = read_reg_le32(par->dc_regs, reg[0]);
1283             if (copy_to_user((void __user *)(arg + 4), &reg[1], 4))
1284                 return -EFAULT;
1285             return 0;
1286         case FBIMSTT_SETCMAPREG:
1287             if (copy_from_user(reg, argp, 8) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
1288                 return -EFAULT;
1289             write_reg_le32(((u_int __iomem *)par->cmap_regs), reg[0], reg[1]);
1290             return 0;
1291         case FBIMSTT_GETCMAPREG:
1292             if (copy_from_user(reg, argp, 4) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
1293                 return -EFAULT;
1294             reg[1] = read_reg_le32(((u_int __iomem *)par->cmap_regs), reg[0]);
1295             if (copy_to_user((void __user *)(arg + 4), &reg[1], 4))
1296                 return -EFAULT;
1297             return 0;
1298         case FBIMSTT_SETIDXREG:
1299             if (copy_from_user(idx, argp, 2))
1300                 return -EFAULT;
1301             par->cmap_regs[PIDXHI] = 0;     eieio();
1302             par->cmap_regs[PIDXLO] = idx[0];    eieio();
1303             par->cmap_regs[PIDXDATA] = idx[1];  eieio();
1304             return 0;
1305         case FBIMSTT_GETIDXREG:
1306             if (copy_from_user(idx, argp, 1))
1307                 return -EFAULT;
1308             par->cmap_regs[PIDXHI] = 0;     eieio();
1309             par->cmap_regs[PIDXLO] = idx[0];    eieio();
1310             idx[1] = par->cmap_regs[PIDXDATA];
1311             if (copy_to_user((void __user *)(arg + 1), &idx[1], 1))
1312                 return -EFAULT;
1313             return 0;
1314         default:
1315             return -ENOIOCTLCMD;
1316     }
1317 }
1318 
1319 static const struct pci_device_id imsttfb_pci_tbl[] = {
1320     { PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_TT128,
1321       PCI_ANY_ID, PCI_ANY_ID, 0, 0, IBM },
1322     { PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_TT3D,
1323       PCI_ANY_ID, PCI_ANY_ID, 0, 0, TVP },
1324     { 0, }
1325 };
1326 
1327 MODULE_DEVICE_TABLE(pci, imsttfb_pci_tbl);
1328 
1329 static struct pci_driver imsttfb_pci_driver = {
1330     .name =     "imsttfb",
1331     .id_table = imsttfb_pci_tbl,
1332     .probe =    imsttfb_probe,
1333     .remove =   imsttfb_remove,
1334 };
1335 
1336 static const struct fb_ops imsttfb_ops = {
1337     .owner      = THIS_MODULE,
1338     .fb_check_var   = imsttfb_check_var,
1339     .fb_set_par     = imsttfb_set_par,
1340     .fb_setcolreg   = imsttfb_setcolreg,
1341     .fb_pan_display = imsttfb_pan_display,
1342     .fb_blank   = imsttfb_blank,
1343     .fb_fillrect    = imsttfb_fillrect,
1344     .fb_copyarea    = imsttfb_copyarea,
1345     .fb_imageblit   = cfb_imageblit,
1346     .fb_ioctl   = imsttfb_ioctl,
1347 };
1348 
1349 static void init_imstt(struct fb_info *info)
1350 {
1351     struct imstt_par *par = info->par;
1352     __u32 i, tmp, *ip, *end;
1353 
1354     tmp = read_reg_le32(par->dc_regs, PRC);
1355     if (par->ramdac == IBM)
1356         info->fix.smem_len = (tmp & 0x0004) ? 0x400000 : 0x200000;
1357     else
1358         info->fix.smem_len = 0x800000;
1359 
1360     ip = (__u32 *)info->screen_base;
1361     end = (__u32 *)(info->screen_base + info->fix.smem_len);
1362     while (ip < end)
1363         *ip++ = 0;
1364 
1365     /* initialize the card */
1366     tmp = read_reg_le32(par->dc_regs, STGCTL);
1367     write_reg_le32(par->dc_regs, STGCTL, tmp & ~0x1);
1368     write_reg_le32(par->dc_regs, SSR, 0);
1369 
1370     /* set default values for DAC registers */
1371     if (par->ramdac == IBM) {
1372         par->cmap_regs[PPMASK] = 0xff;
1373         eieio();
1374         par->cmap_regs[PIDXHI] = 0;
1375         eieio();
1376         for (i = 0; i < ARRAY_SIZE(ibm_initregs); i++) {
1377             par->cmap_regs[PIDXLO] = ibm_initregs[i].addr;
1378             eieio();
1379             par->cmap_regs[PIDXDATA] = ibm_initregs[i].value;
1380             eieio();
1381         }
1382     } else {
1383         for (i = 0; i < ARRAY_SIZE(tvp_initregs); i++) {
1384             par->cmap_regs[TVPADDRW] = tvp_initregs[i].addr;
1385             eieio();
1386             par->cmap_regs[TVPIDATA] = tvp_initregs[i].value;
1387             eieio();
1388         }
1389     }
1390 
1391 #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
1392     if (IS_REACHABLE(CONFIG_NVRAM) && machine_is(powermac)) {
1393         int vmode = init_vmode, cmode = init_cmode;
1394 
1395         if (vmode == -1) {
1396             vmode = nvram_read_byte(NV_VMODE);
1397             if (vmode <= 0 || vmode > VMODE_MAX)
1398                 vmode = VMODE_640_480_67;
1399         }
1400         if (cmode == -1) {
1401             cmode = nvram_read_byte(NV_CMODE);
1402             if (cmode < CMODE_8 || cmode > CMODE_32)
1403                 cmode = CMODE_8;
1404         }
1405         if (mac_vmode_to_var(vmode, cmode, &info->var)) {
1406             info->var.xres = info->var.xres_virtual = INIT_XRES;
1407             info->var.yres = info->var.yres_virtual = INIT_YRES;
1408             info->var.bits_per_pixel = INIT_BPP;
1409         }
1410     } else
1411 #endif
1412     {
1413         info->var.xres = info->var.xres_virtual = INIT_XRES;
1414         info->var.yres = info->var.yres_virtual = INIT_YRES;
1415         info->var.bits_per_pixel = INIT_BPP;
1416     }
1417 
1418     if ((info->var.xres * info->var.yres) * (info->var.bits_per_pixel >> 3) > info->fix.smem_len
1419         || !(compute_imstt_regvals(par, info->var.xres, info->var.yres))) {
1420         printk("imsttfb: %ux%ux%u not supported\n", info->var.xres, info->var.yres, info->var.bits_per_pixel);
1421         framebuffer_release(info);
1422         return;
1423     }
1424 
1425     sprintf(info->fix.id, "IMS TT (%s)", par->ramdac == IBM ? "IBM" : "TVP");
1426     info->fix.mmio_len = 0x1000;
1427     info->fix.accel = FB_ACCEL_IMS_TWINTURBO;
1428     info->fix.type = FB_TYPE_PACKED_PIXELS;
1429     info->fix.visual = info->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
1430                             : FB_VISUAL_DIRECTCOLOR;
1431     info->fix.line_length = info->var.xres * (info->var.bits_per_pixel >> 3);
1432     info->fix.xpanstep = 8;
1433     info->fix.ypanstep = 1;
1434     info->fix.ywrapstep = 0;
1435 
1436     info->var.accel_flags = FB_ACCELF_TEXT;
1437 
1438 //  if (par->ramdac == IBM)
1439 //      imstt_cursor_init(info);
1440     if (info->var.green.length == 6)
1441         set_565(par);
1442     else
1443         set_555(par);
1444     set_imstt_regvals(info, info->var.bits_per_pixel);
1445 
1446     info->var.pixclock = 1000000 / getclkMHz(par);
1447 
1448     info->fbops = &imsttfb_ops;
1449     info->flags = FBINFO_DEFAULT |
1450                       FBINFO_HWACCEL_COPYAREA |
1451                   FBINFO_HWACCEL_FILLRECT |
1452                   FBINFO_HWACCEL_YPAN;
1453 
1454     fb_alloc_cmap(&info->cmap, 0, 0);
1455 
1456     if (register_framebuffer(info) < 0) {
1457         framebuffer_release(info);
1458         return;
1459     }
1460 
1461     tmp = (read_reg_le32(par->dc_regs, SSTATUS) & 0x0f00) >> 8;
1462     fb_info(info, "%s frame buffer; %uMB vram; chip version %u\n",
1463         info->fix.id, info->fix.smem_len >> 20, tmp);
1464 }
1465 
1466 static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1467 {
1468     unsigned long addr, size;
1469     struct imstt_par *par;
1470     struct fb_info *info;
1471     struct device_node *dp;
1472     int ret = -ENOMEM;
1473     
1474     dp = pci_device_to_OF_node(pdev);
1475     if(dp)
1476         printk(KERN_INFO "%s: OF name %pOFn\n",__func__, dp);
1477     else if (IS_ENABLED(CONFIG_OF))
1478         printk(KERN_ERR "imsttfb: no OF node for pci device\n");
1479 
1480     info = framebuffer_alloc(sizeof(struct imstt_par), &pdev->dev);
1481     if (!info)
1482         return -ENOMEM;
1483 
1484     par = info->par;
1485 
1486     addr = pci_resource_start (pdev, 0);
1487     size = pci_resource_len (pdev, 0);
1488 
1489     if (!request_mem_region(addr, size, "imsttfb")) {
1490         printk(KERN_ERR "imsttfb: Can't reserve memory region\n");
1491         framebuffer_release(info);
1492         return -ENODEV;
1493     }
1494 
1495     switch (pdev->device) {
1496         case PCI_DEVICE_ID_IMS_TT128: /* IMS,tt128mbA */
1497             par->ramdac = IBM;
1498             if (of_node_name_eq(dp, "IMS,tt128mb8") ||
1499                 of_node_name_eq(dp, "IMS,tt128mb8A"))
1500                 par->ramdac = TVP;
1501             break;
1502         case PCI_DEVICE_ID_IMS_TT3D:  /* IMS,tt3d */
1503             par->ramdac = TVP;
1504             break;
1505         default:
1506             printk(KERN_INFO "imsttfb: Device 0x%x unknown, "
1507                      "contact maintainer.\n", pdev->device);
1508             ret = -ENODEV;
1509             goto error;
1510     }
1511 
1512     info->fix.smem_start = addr;
1513     info->screen_base = (__u8 *)ioremap(addr, par->ramdac == IBM ?
1514                         0x400000 : 0x800000);
1515     if (!info->screen_base)
1516         goto error;
1517     info->fix.mmio_start = addr + 0x800000;
1518     par->dc_regs = ioremap(addr + 0x800000, 0x1000);
1519     if (!par->dc_regs)
1520         goto error;
1521     par->cmap_regs_phys = addr + 0x840000;
1522     par->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000);
1523     if (!par->cmap_regs)
1524         goto error;
1525     info->pseudo_palette = par->palette;
1526     init_imstt(info);
1527 
1528     pci_set_drvdata(pdev, info);
1529     return 0;
1530 
1531 error:
1532     if (par->dc_regs)
1533         iounmap(par->dc_regs);
1534     if (info->screen_base)
1535         iounmap(info->screen_base);
1536     release_mem_region(addr, size);
1537     framebuffer_release(info);
1538     return ret;
1539 }
1540 
1541 static void imsttfb_remove(struct pci_dev *pdev)
1542 {
1543     struct fb_info *info = pci_get_drvdata(pdev);
1544     struct imstt_par *par = info->par;
1545     int size = pci_resource_len(pdev, 0);
1546 
1547     unregister_framebuffer(info);
1548     iounmap(par->cmap_regs);
1549     iounmap(par->dc_regs);
1550     iounmap(info->screen_base);
1551     release_mem_region(info->fix.smem_start, size);
1552     framebuffer_release(info);
1553 }
1554 
1555 #ifndef MODULE
1556 static int __init
1557 imsttfb_setup(char *options)
1558 {
1559     char *this_opt;
1560 
1561     if (!options || !*options)
1562         return 0;
1563 
1564     while ((this_opt = strsep(&options, ",")) != NULL) {
1565         if (!strncmp(this_opt, "font:", 5)) {
1566             char *p;
1567             int i;
1568 
1569             p = this_opt + 5;
1570             for (i = 0; i < sizeof(fontname) - 1; i++)
1571                 if (!*p || *p == ' ' || *p == ',')
1572                     break;
1573             memcpy(fontname, this_opt + 5, i);
1574             fontname[i] = 0;
1575         } else if (!strncmp(this_opt, "inverse", 7)) {
1576             inverse = 1;
1577             fb_invert_cmaps();
1578         }
1579 #if defined(CONFIG_PPC_PMAC)
1580         else if (!strncmp(this_opt, "vmode:", 6)) {
1581             int vmode = simple_strtoul(this_opt+6, NULL, 0);
1582             if (vmode > 0 && vmode <= VMODE_MAX)
1583                 init_vmode = vmode;
1584         } else if (!strncmp(this_opt, "cmode:", 6)) {
1585             int cmode = simple_strtoul(this_opt+6, NULL, 0);
1586             switch (cmode) {
1587                 case CMODE_8:
1588                 case 8:
1589                     init_cmode = CMODE_8;
1590                     break;
1591                 case CMODE_16:
1592                 case 15:
1593                 case 16:
1594                     init_cmode = CMODE_16;
1595                     break;
1596                 case CMODE_32:
1597                 case 24:
1598                 case 32:
1599                     init_cmode = CMODE_32;
1600                     break;
1601             }
1602         }
1603 #endif
1604     }
1605     return 0;
1606 }
1607 
1608 #endif /* MODULE */
1609 
1610 static int __init imsttfb_init(void)
1611 {
1612 #ifndef MODULE
1613     char *option = NULL;
1614 
1615     if (fb_get_options("imsttfb", &option))
1616         return -ENODEV;
1617 
1618     imsttfb_setup(option);
1619 #endif
1620     return pci_register_driver(&imsttfb_pci_driver);
1621 }
1622  
1623 static void __exit imsttfb_exit(void)
1624 {
1625     pci_unregister_driver(&imsttfb_pci_driver);
1626 }
1627 
1628 MODULE_LICENSE("GPL");
1629 
1630 module_init(imsttfb_init);
1631 module_exit(imsttfb_exit);
1632